From 242328fa749ee4c72af93433a9bef95f329ac62f Mon Sep 17 00:00:00 2001 From: Filimonov Andrey Date: Tue, 19 May 2020 00:59:23 +0200 Subject: [PATCH 01/33] fix(eslint-plugin): [dot-notation] fix typo in schema (#2040) --- packages/eslint-plugin/src/rules/dot-notation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/src/rules/dot-notation.ts b/packages/eslint-plugin/src/rules/dot-notation.ts index d1d848aa2efa..3cc2be22deb4 100644 --- a/packages/eslint-plugin/src/rules/dot-notation.ts +++ b/packages/eslint-plugin/src/rules/dot-notation.ts @@ -35,7 +35,7 @@ export default createRule({ default: '', }, allowPrivateClassPropertyAccess: { - tyoe: 'boolean', + type: 'boolean', default: false, }, }, From a1816c941a5aaad55b7d304737db6da8ce67f523 Mon Sep 17 00:00:00 2001 From: iwis Date: Tue, 19 May 2020 18:14:25 +0200 Subject: [PATCH 02/33] docs: Adding FAQ entry saying TypeScript should be installed locally (#2043) --- docs/getting-started/linting/FAQ.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/getting-started/linting/FAQ.md b/docs/getting-started/linting/FAQ.md index c2554886714c..33410ed3c46b 100644 --- a/docs/getting-started/linting/FAQ.md +++ b/docs/getting-started/linting/FAQ.md @@ -7,6 +7,7 @@ - [I use a framework (like Vue) that requires custom file extensions, and I get errors like "You should add `parserOptions.extraFileExtensions` to your config"](#i-use-a-framework-like-vue-that-requires-custom-file-extensions-and-i-get-errors-like-you-should-add-parseroptionsextrafileextensions-to-your-config) - [I am using a rule from ESLint core, and it doesn't work correctly with TypeScript code](#i-am-using-a-rule-from-eslint-core-and-it-doesnt-work-correctly-with-typescript-code) - [One of my lint rules isn't working correctly on a pure JavaScript file](#one-of-my-lint-rules-isnt-working-correctly-on-a-pure-javascript-file) +- [TypeScript should be installed locally](#typescript-should-be-installed-locally) --- @@ -117,3 +118,10 @@ If you don't find an existing extension rule, or the extension rule doesn't work This is to be expected - ESLint rules do not check file extensions on purpose, as it causes issues in environments that use non-standard extensions (for example, a `.vue` and a `.md` file can both contain TypeScript code to be linted). If you have some pure JavaScript code that you do not want to apply certain lint rules to, then you can use [ESLint's `overrides` configuration](https://eslint.org/docs/user-guide/configuring#configuration-based-on-glob-patterns) to turn off certain rules, or even change the parser based on glob patterns. + +--- + +## TypeScript should be installed locally + +Make sure that you have installed TypeScript locally i.e. by using `npm install typescript`, not `npm install -g typescript`, +or by using `yarn add typescript`, not `yarn global add typescript`. See https://github.com/typescript-eslint/typescript-eslint/issues/2041 for more information. From 06bec63c56536db070608ab136d2ad57083f0c6a Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Thu, 21 May 2020 09:26:37 -0700 Subject: [PATCH 03/33] feat(typescript-estree): handle 3.9's non-null assertion changes (#2036) --- package.json | 2 +- packages/eslint-plugin/package.json | 1 + .../no-non-null-asserted-optional-chain.ts | 31 +- ...o-non-null-asserted-optional-chain.test.ts | 32 +- .../tests/rules/no-unsafe-call.test.ts | 13 +- .../tests/rules/no-unsafe-return.test.ts | 24 +- .../restrict-template-expressions.test.ts | 25 +- .../lib/__snapshots__/typescript.ts.snap | 1263 +- ...-chain-call-with-non-null-assertion.src.ts | 8 + ...ment-access-with-non-null-assertion.src.ts | 8 + ...ional-chain-with-non-null-assertion.src.ts | 5 + packages/typescript-estree/src/convert.ts | 25 +- packages/typescript-estree/src/node-utils.ts | 65 + .../src/ts-estree/ts-nodes.ts | 371 +- .../tests/lib/__snapshots__/convert.ts.snap | 1 + .../semantic-diagnostics-enabled.ts.snap | 6 + .../lib/__snapshots__/typescript.ts.snap | 11754 +++++++++++----- .../tests/lib/semanticInfo.ts | 4 +- yarn.lock | 8 +- 19 files changed, 9987 insertions(+), 3659 deletions(-) create mode 100644 packages/shared-fixtures/fixtures/typescript/basics/optional-chain-call-with-non-null-assertion.src.ts create mode 100644 packages/shared-fixtures/fixtures/typescript/basics/optional-chain-element-access-with-non-null-assertion.src.ts create mode 100644 packages/shared-fixtures/fixtures/typescript/basics/optional-chain-with-non-null-assertion.src.ts diff --git a/package.json b/package.json index c317a871da2a..14c09a7d3f64 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "ts-jest": "^25.5.1", "ts-node": "^8.10.1", "tslint": "^6.1.2", - "typescript": ">=3.2.1 <3.9.0" + "typescript": ">=3.2.1 <4.0.0" }, "resolutions": { "typescript": "^3.8.3" diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index a08286a3c634..ea80890eef0a 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -44,6 +44,7 @@ "@typescript-eslint/experimental-utils": "2.34.0", "functional-red-black-tree": "^1.0.1", "regexpp": "^3.0.0", + "semver": "^7.3.2", "tsutils": "^3.17.1" }, "devDependencies": { diff --git a/packages/eslint-plugin/src/rules/no-non-null-asserted-optional-chain.ts b/packages/eslint-plugin/src/rules/no-non-null-asserted-optional-chain.ts index b3704b8d5dd2..9ebc2d6a61fe 100644 --- a/packages/eslint-plugin/src/rules/no-non-null-asserted-optional-chain.ts +++ b/packages/eslint-plugin/src/rules/no-non-null-asserted-optional-chain.ts @@ -1,8 +1,19 @@ -import { TSESTree, TSESLint } from '@typescript-eslint/experimental-utils'; +import { + TSESTree, + TSESLint, + AST_NODE_TYPES, +} from '@typescript-eslint/experimental-utils'; +import { version } from 'typescript'; +import * as semver from 'semver'; import * as util from '../util'; type MessageIds = 'noNonNullOptionalChain' | 'suggestRemovingNonNull'; +const is3dot9 = !semver.satisfies( + version, + '< 3.9.0 || < 3.9.1-rc || < 3.9.0-beta', +); + export default util.createRule<[], MessageIds>({ name: 'no-non-null-asserted-optional-chain', meta: { @@ -29,6 +40,24 @@ export default util.createRule<[], MessageIds>({ | TSESTree.OptionalCallExpression | TSESTree.OptionalMemberExpression, ): void { + if (is3dot9) { + // TS3.9 made a breaking change to how non-null works with optional chains. + // Pre-3.9, `x?.y!.z` means `(x?.y).z` - i.e. it essentially scrubbed the optionality from the chain + // Post-3.9, `x?.y!.z` means `x?.y!.z` - i.e. it just asserts that the property `y` is non-null, not the result of `x?.y`. + // This means that for > 3.9, x?.y!.z is valid! + // NOTE: these cases are still invalid: + // - x?.y.z! + // - (x?.y)!.z + const nnAssertionParent = node.parent?.parent; + if ( + nnAssertionParent?.type === + AST_NODE_TYPES.OptionalMemberExpression || + nnAssertionParent?.type === AST_NODE_TYPES.OptionalCallExpression + ) { + return; + } + } + // selector guarantees this assertion const parent = node.parent as TSESTree.TSNonNullExpression; context.report({ diff --git a/packages/eslint-plugin/tests/rules/no-non-null-asserted-optional-chain.test.ts b/packages/eslint-plugin/tests/rules/no-non-null-asserted-optional-chain.test.ts index 0a28cbbfc928..6affcf2fef55 100644 --- a/packages/eslint-plugin/tests/rules/no-non-null-asserted-optional-chain.test.ts +++ b/packages/eslint-plugin/tests/rules/no-non-null-asserted-optional-chain.test.ts @@ -13,6 +13,10 @@ ruleTester.run('no-non-null-asserted-optional-chain', rule, { 'foo?.bar();', '(foo?.bar).baz!;', '(foo?.bar()).baz!;', + // Valid as of 3.9 + 'foo?.bar!.baz;', + 'foo?.bar!();', + "foo?.['bar']!.baz;", ], invalid: [ { @@ -71,20 +75,6 @@ ruleTester.run('no-non-null-asserted-optional-chain', rule, { }, ], }, - { - code: 'foo?.bar!();', - errors: [ - { - messageId: 'noNonNullOptionalChain', - suggestions: [ - { - messageId: 'suggestRemovingNonNull', - output: 'foo?.bar();', - }, - ], - }, - ], - }, { code: noFormat`(foo?.bar)!.baz`, errors: [ @@ -99,20 +89,6 @@ ruleTester.run('no-non-null-asserted-optional-chain', rule, { }, ], }, - { - code: "foo?.['bar']!.baz;", - errors: [ - { - messageId: 'noNonNullOptionalChain', - suggestions: [ - { - messageId: 'suggestRemovingNonNull', - output: "foo?.['bar'].baz;", - }, - ], - }, - ], - }, { code: noFormat`(foo?.bar)!().baz`, errors: [ diff --git a/packages/eslint-plugin/tests/rules/no-unsafe-call.test.ts b/packages/eslint-plugin/tests/rules/no-unsafe-call.test.ts index f860410da5c1..981abb0eadde 100644 --- a/packages/eslint-plugin/tests/rules/no-unsafe-call.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unsafe-call.test.ts @@ -39,6 +39,12 @@ function foo(x: { a?: () => void }) { let foo: any = 23; String(foo); // ERROR: Unsafe call of an any typed value `, + // TS 3.9 changed this to be safe + ` + function foo(x: T) { + x(); + } + `, ], invalid: [ ...batchedSingleLineTests({ @@ -47,7 +53,6 @@ function foo(x: any) { x() } function foo(x: any) { x?.() } function foo(x: any) { x.a.b.c.d.e.f.g() } function foo(x: any) { x.a.b.c.d.e.f.g?.() } -function foo(x: T) { x() } `, errors: [ { @@ -74,12 +79,6 @@ function foo(x: T) { x() } column: 24, endColumn: 39, }, - { - messageId: 'unsafeCall', - line: 6, - column: 37, - endColumn: 38, - }, ], }), ...batchedSingleLineTests({ diff --git a/packages/eslint-plugin/tests/rules/no-unsafe-return.test.ts b/packages/eslint-plugin/tests/rules/no-unsafe-return.test.ts index 42a58734a476..91627f91b02b 100644 --- a/packages/eslint-plugin/tests/rules/no-unsafe-return.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unsafe-return.test.ts @@ -71,26 +71,14 @@ function foo(): Set { return { prop: '' } as Foo; } `, + // TS 3.9 changed this to be safe + ` + function fn(x: T) { + return x; + } + `, ], invalid: [ - { - code: ` -function fn(x: T) { - return x; -} - `, - errors: [ - { - messageId: 'unsafeReturnAssignment', - data: { - sender: 'any', - receiver: 'T', - }, - line: 3, - column: 3, - }, - ], - }, ...batchedSingleLineTests({ code: noFormat` function foo() { return (1 as any); } diff --git a/packages/eslint-plugin/tests/rules/restrict-template-expressions.test.ts b/packages/eslint-plugin/tests/rules/restrict-template-expressions.test.ts index 9b991053dcb2..b0b3069062d2 100644 --- a/packages/eslint-plugin/tests/rules/restrict-template-expressions.test.ts +++ b/packages/eslint-plugin/tests/rules/restrict-template-expressions.test.ts @@ -158,14 +158,6 @@ ruleTester.run('restrict-template-expressions', rule, { const msg = \`arg = \${user.name || 'the user with no name'}\`; `, }, - { - options: [{ allowAny: true }], - code: ` - function test(arg: T) { - return \`arg = \${arg}\`; - } - `, - }, // allowNullable { options: [{ allowNullable: true }], @@ -344,5 +336,22 @@ ruleTester.run('restrict-template-expressions', rule, { }, ], }, + // TS 3.9 change + { + options: [{ allowAny: true }], + code: ` + function test(arg: T) { + return \`arg = \${arg}\`; + } + `, + errors: [ + { + messageId: 'invalidType', + data: { type: 'unknown' }, + line: 3, + column: 27, + }, + ], + }, ], }); diff --git a/packages/parser/tests/lib/__snapshots__/typescript.ts.snap b/packages/parser/tests/lib/__snapshots__/typescript.ts.snap index 36c63d18c9a0..97450c6c6014 100644 --- a/packages/parser/tests/lib/__snapshots__/typescript.ts.snap +++ b/packages/parser/tests/lib/__snapshots__/typescript.ts.snap @@ -27847,33 +27847,33 @@ Object { } `; -exports[`typescript fixtures/basics/optional-chain-call-with-parens.src 1`] = ` +exports[`typescript fixtures/basics/optional-chain-call-with-non-null-assertion.src 1`] = ` Object { - "$id": 14, + "$id": 11, "block": Object { "range": Array [ 0, - 218, + 156, ], "type": "Program", }, "childScopes": Array [ Object { - "$id": 13, + "$id": 10, "block": Object { "range": Array [ 0, - 218, + 156, ], "type": "Program", }, "childScopes": Array [ Object { - "$id": 12, + "$id": 9, "block": Object { "range": Array [ 0, - 217, + 155, ], "type": "FunctionDeclaration", }, @@ -27884,13 +27884,13 @@ Object { Object { "$id": 3, "from": Object { - "$ref": 12, + "$ref": 9, }, "identifier": Object { "name": "one", "range": Array [ - 51, - 54, + 40, + 43, ], "type": "Identifier", }, @@ -27903,13 +27903,13 @@ Object { Object { "$id": 4, "from": Object { - "$ref": 12, + "$ref": 9, }, "identifier": Object { "name": "one", "range": Array [ - 66, - 69, + 55, + 58, ], "type": "Identifier", }, @@ -27922,13 +27922,13 @@ Object { Object { "$id": 5, "from": Object { - "$ref": 12, + "$ref": 9, }, "identifier": Object { "name": "one", "range": Array [ - 85, - 88, + 77, + 80, ], "type": "Identifier", }, @@ -27941,13 +27941,13 @@ Object { Object { "$id": 6, "from": Object { - "$ref": 12, + "$ref": 9, }, "identifier": Object { "name": "one", "range": Array [ - 104, - 107, + 94, + 97, ], "type": "Identifier", }, @@ -27960,13 +27960,13 @@ Object { Object { "$id": 7, "from": Object { - "$ref": 12, + "$ref": 9, }, "identifier": Object { "name": "one", "range": Array [ - 129, - 132, + 117, + 120, ], "type": "Identifier", }, @@ -27979,13 +27979,13 @@ Object { Object { "$id": 8, "from": Object { - "$ref": 12, + "$ref": 9, }, "identifier": Object { "name": "one", "range": Array [ - 156, - 159, + 134, + 137, ], "type": "Identifier", }, @@ -27995,16 +27995,964 @@ Object { }, "writeExpr": undefined, }, + ], + "throughReferences": Array [], + "type": "function", + "upperScope": Object { + "$ref": 10, + }, + "variableMap": Object { + "arguments": Object { + "$ref": 1, + }, + "one": Object { + "$ref": 2, + }, + }, + "variableScope": Object { + "$ref": 9, + }, + "variables": Array [ + Object { + "$id": 1, + "defs": Array [], + "eslintUsed": undefined, + "identifiers": Array [], + "name": "arguments", + "references": Array [], + "scope": Object { + "$ref": 9, + }, + }, Object { - "$id": 9, + "$id": 2, + "defs": Array [ + Object { + "name": Object { + "name": "one", + "range": Array [ + 25, + 34, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 0, + 155, + ], + "type": "FunctionDeclaration", + }, + "parent": null, + "type": "Parameter", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "one", + "range": Array [ + 25, + 34, + ], + "type": "Identifier", + }, + ], + "name": "one", + "references": Array [ + Object { + "$ref": 3, + }, + Object { + "$ref": 4, + }, + Object { + "$ref": 5, + }, + Object { + "$ref": 6, + }, + Object { + "$ref": 7, + }, + Object { + "$ref": 8, + }, + ], + "scope": Object { + "$ref": 9, + }, + }, + ], + }, + ], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [], + "throughReferences": Array [], + "type": "module", + "upperScope": Object { + "$ref": 11, + }, + "variableMap": Object { + "processOptional": Object { + "$ref": 0, + }, + }, + "variableScope": Object { + "$ref": 10, + }, + "variables": Array [ + Object { + "$id": 0, + "defs": Array [ + Object { + "name": Object { + "name": "processOptional", + "range": Array [ + 9, + 24, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 0, + 155, + ], + "type": "FunctionDeclaration", + }, + "parent": null, + "type": "FunctionName", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "processOptional", + "range": Array [ + 9, + 24, + ], + "type": "Identifier", + }, + ], + "name": "processOptional", + "references": Array [], + "scope": Object { + "$ref": 10, + }, + }, + ], + }, + ], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [], + "throughReferences": Array [], + "type": "global", + "upperScope": null, + "variableMap": Object {}, + "variableScope": Object { + "$ref": 11, + }, + "variables": Array [], +} +`; + +exports[`typescript fixtures/basics/optional-chain-call-with-parens.src 1`] = ` +Object { + "$id": 14, + "block": Object { + "range": Array [ + 0, + 218, + ], + "type": "Program", + }, + "childScopes": Array [ + Object { + "$id": 13, + "block": Object { + "range": Array [ + 0, + 218, + ], + "type": "Program", + }, + "childScopes": Array [ + Object { + "$id": 12, + "block": Object { + "range": Array [ + 0, + 217, + ], + "type": "FunctionDeclaration", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [ + Object { + "$id": 3, "from": Object { "$ref": 12, }, "identifier": Object { "name": "one", "range": Array [ - 169, - 172, + 51, + 54, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 2, + }, + "writeExpr": undefined, + }, + Object { + "$id": 4, + "from": Object { + "$ref": 12, + }, + "identifier": Object { + "name": "one", + "range": Array [ + 66, + 69, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 2, + }, + "writeExpr": undefined, + }, + Object { + "$id": 5, + "from": Object { + "$ref": 12, + }, + "identifier": Object { + "name": "one", + "range": Array [ + 85, + 88, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 2, + }, + "writeExpr": undefined, + }, + Object { + "$id": 6, + "from": Object { + "$ref": 12, + }, + "identifier": Object { + "name": "one", + "range": Array [ + 104, + 107, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 2, + }, + "writeExpr": undefined, + }, + Object { + "$id": 7, + "from": Object { + "$ref": 12, + }, + "identifier": Object { + "name": "one", + "range": Array [ + 129, + 132, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 2, + }, + "writeExpr": undefined, + }, + Object { + "$id": 8, + "from": Object { + "$ref": 12, + }, + "identifier": Object { + "name": "one", + "range": Array [ + 156, + 159, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 2, + }, + "writeExpr": undefined, + }, + Object { + "$id": 9, + "from": Object { + "$ref": 12, + }, + "identifier": Object { + "name": "one", + "range": Array [ + 169, + 172, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 2, + }, + "writeExpr": undefined, + }, + Object { + "$id": 10, + "from": Object { + "$ref": 12, + }, + "identifier": Object { + "name": "one", + "range": Array [ + 184, + 187, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 2, + }, + "writeExpr": undefined, + }, + Object { + "$id": 11, + "from": Object { + "$ref": 12, + }, + "identifier": Object { + "name": "one", + "range": Array [ + 202, + 205, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 2, + }, + "writeExpr": undefined, + }, + ], + "throughReferences": Array [], + "type": "function", + "upperScope": Object { + "$ref": 13, + }, + "variableMap": Object { + "arguments": Object { + "$ref": 1, + }, + "one": Object { + "$ref": 2, + }, + }, + "variableScope": Object { + "$ref": 12, + }, + "variables": Array [ + Object { + "$id": 1, + "defs": Array [], + "eslintUsed": undefined, + "identifiers": Array [], + "name": "arguments", + "references": Array [], + "scope": Object { + "$ref": 12, + }, + }, + Object { + "$id": 2, + "defs": Array [ + Object { + "name": Object { + "name": "one", + "range": Array [ + 35, + 44, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 0, + 217, + ], + "type": "FunctionDeclaration", + }, + "parent": null, + "type": "Parameter", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "one", + "range": Array [ + 35, + 44, + ], + "type": "Identifier", + }, + ], + "name": "one", + "references": Array [ + Object { + "$ref": 3, + }, + Object { + "$ref": 4, + }, + Object { + "$ref": 5, + }, + Object { + "$ref": 6, + }, + Object { + "$ref": 7, + }, + Object { + "$ref": 8, + }, + Object { + "$ref": 9, + }, + Object { + "$ref": 10, + }, + Object { + "$ref": 11, + }, + ], + "scope": Object { + "$ref": 12, + }, + }, + ], + }, + ], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [], + "throughReferences": Array [], + "type": "module", + "upperScope": Object { + "$ref": 14, + }, + "variableMap": Object { + "processOptionalCallParens": Object { + "$ref": 0, + }, + }, + "variableScope": Object { + "$ref": 13, + }, + "variables": Array [ + Object { + "$id": 0, + "defs": Array [ + Object { + "name": Object { + "name": "processOptionalCallParens", + "range": Array [ + 9, + 34, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 0, + 217, + ], + "type": "FunctionDeclaration", + }, + "parent": null, + "type": "FunctionName", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "processOptionalCallParens", + "range": Array [ + 9, + 34, + ], + "type": "Identifier", + }, + ], + "name": "processOptionalCallParens", + "references": Array [], + "scope": Object { + "$ref": 13, + }, + }, + ], + }, + ], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [], + "throughReferences": Array [], + "type": "global", + "upperScope": null, + "variableMap": Object {}, + "variableScope": Object { + "$ref": 14, + }, + "variables": Array [], +} +`; + +exports[`typescript fixtures/basics/optional-chain-element-access.src 1`] = ` +Object { + "$id": 11, + "block": Object { + "range": Array [ + 0, + 142, + ], + "type": "Program", + }, + "childScopes": Array [ + Object { + "$id": 10, + "block": Object { + "range": Array [ + 0, + 142, + ], + "type": "Program", + }, + "childScopes": Array [ + Object { + "$id": 9, + "block": Object { + "range": Array [ + 0, + 141, + ], + "type": "FunctionDeclaration", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [ + Object { + "$id": 3, + "from": Object { + "$ref": 9, + }, + "identifier": Object { + "name": "one", + "range": Array [ + 47, + 50, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 2, + }, + "writeExpr": undefined, + }, + Object { + "$id": 4, + "from": Object { + "$ref": 9, + }, + "identifier": Object { + "name": "one", + "range": Array [ + 59, + 62, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 2, + }, + "writeExpr": undefined, + }, + Object { + "$id": 5, + "from": Object { + "$ref": 9, + }, + "identifier": Object { + "name": "one", + "range": Array [ + 74, + 77, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 2, + }, + "writeExpr": undefined, + }, + Object { + "$id": 6, + "from": Object { + "$ref": 9, + }, + "identifier": Object { + "name": "one", + "range": Array [ + 89, + 92, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 2, + }, + "writeExpr": undefined, + }, + Object { + "$id": 7, + "from": Object { + "$ref": 9, + }, + "identifier": Object { + "name": "one", + "range": Array [ + 104, + 107, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 2, + }, + "writeExpr": undefined, + }, + Object { + "$id": 8, + "from": Object { + "$ref": 9, + }, + "identifier": Object { + "name": "one", + "range": Array [ + 122, + 125, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 2, + }, + "writeExpr": undefined, + }, + ], + "throughReferences": Array [], + "type": "function", + "upperScope": Object { + "$ref": 10, + }, + "variableMap": Object { + "arguments": Object { + "$ref": 1, + }, + "one": Object { + "$ref": 2, + }, + }, + "variableScope": Object { + "$ref": 9, + }, + "variables": Array [ + Object { + "$id": 1, + "defs": Array [], + "eslintUsed": undefined, + "identifiers": Array [], + "name": "arguments", + "references": Array [], + "scope": Object { + "$ref": 9, + }, + }, + Object { + "$id": 2, + "defs": Array [ + Object { + "name": Object { + "name": "one", + "range": Array [ + 32, + 41, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 0, + 141, + ], + "type": "FunctionDeclaration", + }, + "parent": null, + "type": "Parameter", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "one", + "range": Array [ + 32, + 41, + ], + "type": "Identifier", + }, + ], + "name": "one", + "references": Array [ + Object { + "$ref": 3, + }, + Object { + "$ref": 4, + }, + Object { + "$ref": 5, + }, + Object { + "$ref": 6, + }, + Object { + "$ref": 7, + }, + Object { + "$ref": 8, + }, + ], + "scope": Object { + "$ref": 9, + }, + }, + ], + }, + ], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [], + "throughReferences": Array [], + "type": "module", + "upperScope": Object { + "$ref": 11, + }, + "variableMap": Object { + "processOptionalElement": Object { + "$ref": 0, + }, + }, + "variableScope": Object { + "$ref": 10, + }, + "variables": Array [ + Object { + "$id": 0, + "defs": Array [ + Object { + "name": Object { + "name": "processOptionalElement", + "range": Array [ + 9, + 31, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 0, + 141, + ], + "type": "FunctionDeclaration", + }, + "parent": null, + "type": "FunctionName", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "processOptionalElement", + "range": Array [ + 9, + 31, + ], + "type": "Identifier", + }, + ], + "name": "processOptionalElement", + "references": Array [], + "scope": Object { + "$ref": 10, + }, + }, + ], + }, + ], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [], + "throughReferences": Array [], + "type": "global", + "upperScope": null, + "variableMap": Object {}, + "variableScope": Object { + "$ref": 11, + }, + "variables": Array [], +} +`; + +exports[`typescript fixtures/basics/optional-chain-element-access-with-non-null-assertion.src 1`] = ` +Object { + "$id": 11, + "block": Object { + "range": Array [ + 0, + 183, + ], + "type": "Program", + }, + "childScopes": Array [ + Object { + "$id": 10, + "block": Object { + "range": Array [ + 0, + 183, + ], + "type": "Program", + }, + "childScopes": Array [ + Object { + "$id": 9, + "block": Object { + "range": Array [ + 0, + 182, + ], + "type": "FunctionDeclaration", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [ + Object { + "$id": 3, + "from": Object { + "$ref": 9, + }, + "identifier": Object { + "name": "one", + "range": Array [ + 40, + 43, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 2, + }, + "writeExpr": undefined, + }, + Object { + "$id": 4, + "from": Object { + "$ref": 9, + }, + "identifier": Object { + "name": "one", + "range": Array [ + 64, + 67, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 2, + }, + "writeExpr": undefined, + }, + Object { + "$id": 5, + "from": Object { + "$ref": 9, + }, + "identifier": Object { + "name": "one", + "range": Array [ + 89, + 92, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 2, + }, + "writeExpr": undefined, + }, + Object { + "$id": 6, + "from": Object { + "$ref": 9, + }, + "identifier": Object { + "name": "one", + "range": Array [ + 113, + 116, ], "type": "Identifier", }, @@ -28015,15 +28963,15 @@ Object { "writeExpr": undefined, }, Object { - "$id": 10, + "$id": 7, "from": Object { - "$ref": 12, + "$ref": 9, }, "identifier": Object { "name": "one", "range": Array [ - 184, - 187, + 136, + 139, ], "type": "Identifier", }, @@ -28034,15 +28982,15 @@ Object { "writeExpr": undefined, }, Object { - "$id": 11, + "$id": 8, "from": Object { - "$ref": 12, + "$ref": 9, }, "identifier": Object { "name": "one", "range": Array [ - 202, - 205, + 160, + 163, ], "type": "Identifier", }, @@ -28056,7 +29004,7 @@ Object { "throughReferences": Array [], "type": "function", "upperScope": Object { - "$ref": 13, + "$ref": 10, }, "variableMap": Object { "arguments": Object { @@ -28067,7 +29015,7 @@ Object { }, }, "variableScope": Object { - "$ref": 12, + "$ref": 9, }, "variables": Array [ Object { @@ -28078,7 +29026,7 @@ Object { "name": "arguments", "references": Array [], "scope": Object { - "$ref": 12, + "$ref": 9, }, }, Object { @@ -28088,15 +29036,15 @@ Object { "name": Object { "name": "one", "range": Array [ - 35, - 44, + 25, + 34, ], "type": "Identifier", }, "node": Object { "range": Array [ 0, - 217, + 182, ], "type": "FunctionDeclaration", }, @@ -28109,8 +29057,8 @@ Object { Object { "name": "one", "range": Array [ - 35, - 44, + 25, + 34, ], "type": "Identifier", }, @@ -28135,18 +29083,9 @@ Object { Object { "$ref": 8, }, - Object { - "$ref": 9, - }, - Object { - "$ref": 10, - }, - Object { - "$ref": 11, - }, ], "scope": Object { - "$ref": 12, + "$ref": 9, }, }, ], @@ -28158,15 +29097,15 @@ Object { "throughReferences": Array [], "type": "module", "upperScope": Object { - "$ref": 14, + "$ref": 11, }, "variableMap": Object { - "processOptionalCallParens": Object { + "processOptional": Object { "$ref": 0, }, }, "variableScope": Object { - "$ref": 13, + "$ref": 10, }, "variables": Array [ Object { @@ -28174,17 +29113,17 @@ Object { "defs": Array [ Object { "name": Object { - "name": "processOptionalCallParens", + "name": "processOptional", "range": Array [ 9, - 34, + 24, ], "type": "Identifier", }, "node": Object { "range": Array [ 0, - 217, + 182, ], "type": "FunctionDeclaration", }, @@ -28195,18 +29134,18 @@ Object { "eslintUsed": undefined, "identifiers": Array [ Object { - "name": "processOptionalCallParens", + "name": "processOptional", "range": Array [ 9, - 34, + 24, ], "type": "Identifier", }, ], - "name": "processOptionalCallParens", + "name": "processOptional", "references": Array [], "scope": Object { - "$ref": 13, + "$ref": 10, }, }, ], @@ -28220,19 +29159,19 @@ Object { "upperScope": null, "variableMap": Object {}, "variableScope": Object { - "$ref": 14, + "$ref": 11, }, "variables": Array [], } `; -exports[`typescript fixtures/basics/optional-chain-element-access.src 1`] = ` +exports[`typescript fixtures/basics/optional-chain-element-access-with-parens.src 1`] = ` Object { "$id": 11, "block": Object { "range": Array [ 0, - 142, + 168, ], "type": "Program", }, @@ -28242,7 +29181,7 @@ Object { "block": Object { "range": Array [ 0, - 142, + 168, ], "type": "Program", }, @@ -28252,7 +29191,7 @@ Object { "block": Object { "range": Array [ 0, - 141, + 167, ], "type": "FunctionDeclaration", }, @@ -28268,8 +29207,8 @@ Object { "identifier": Object { "name": "one", "range": Array [ - 47, - 50, + 54, + 57, ], "type": "Identifier", }, @@ -28287,8 +29226,8 @@ Object { "identifier": Object { "name": "one", "range": Array [ - 59, - 62, + 68, + 71, ], "type": "Identifier", }, @@ -28306,8 +29245,8 @@ Object { "identifier": Object { "name": "one", "range": Array [ - 74, - 77, + 85, + 88, ], "type": "Identifier", }, @@ -28325,8 +29264,8 @@ Object { "identifier": Object { "name": "one", "range": Array [ - 89, - 92, + 102, + 105, ], "type": "Identifier", }, @@ -28344,8 +29283,8 @@ Object { "identifier": Object { "name": "one", "range": Array [ - 104, - 107, + 122, + 125, ], "type": "Identifier", }, @@ -28363,8 +29302,8 @@ Object { "identifier": Object { "name": "one", "range": Array [ - 122, - 125, + 144, + 147, ], "type": "Identifier", }, @@ -28410,15 +29349,15 @@ Object { "name": Object { "name": "one", "range": Array [ - 32, - 41, + 38, + 47, ], "type": "Identifier", }, "node": Object { "range": Array [ 0, - 141, + 167, ], "type": "FunctionDeclaration", }, @@ -28431,8 +29370,8 @@ Object { Object { "name": "one", "range": Array [ - 32, - 41, + 38, + 47, ], "type": "Identifier", }, @@ -28474,7 +29413,7 @@ Object { "$ref": 11, }, "variableMap": Object { - "processOptionalElement": Object { + "processOptionalElementParens": Object { "$ref": 0, }, }, @@ -28487,17 +29426,17 @@ Object { "defs": Array [ Object { "name": Object { - "name": "processOptionalElement", + "name": "processOptionalElementParens", "range": Array [ 9, - 31, + 37, ], "type": "Identifier", }, "node": Object { "range": Array [ 0, - 141, + 167, ], "type": "FunctionDeclaration", }, @@ -28508,15 +29447,15 @@ Object { "eslintUsed": undefined, "identifiers": Array [ Object { - "name": "processOptionalElement", + "name": "processOptionalElementParens", "range": Array [ 9, - 31, + 37, ], "type": "Identifier", }, ], - "name": "processOptionalElement", + "name": "processOptionalElementParens", "references": Array [], "scope": Object { "$ref": 10, @@ -28539,33 +29478,33 @@ Object { } `; -exports[`typescript fixtures/basics/optional-chain-element-access-with-parens.src 1`] = ` +exports[`typescript fixtures/basics/optional-chain-with-non-null-assertion.src 1`] = ` Object { - "$id": 11, + "$id": 8, "block": Object { "range": Array [ 0, - 168, + 101, ], "type": "Program", }, "childScopes": Array [ Object { - "$id": 10, + "$id": 7, "block": Object { "range": Array [ 0, - 168, + 101, ], "type": "Program", }, "childScopes": Array [ Object { - "$id": 9, + "$id": 6, "block": Object { "range": Array [ 0, - 167, + 100, ], "type": "FunctionDeclaration", }, @@ -28576,13 +29515,13 @@ Object { Object { "$id": 3, "from": Object { - "$ref": 9, + "$ref": 6, }, "identifier": Object { "name": "one", "range": Array [ - 54, - 57, + 40, + 43, ], "type": "Identifier", }, @@ -28595,13 +29534,13 @@ Object { Object { "$id": 4, "from": Object { - "$ref": 9, + "$ref": 6, }, "identifier": Object { "name": "one", "range": Array [ - 68, - 71, + 60, + 63, ], "type": "Identifier", }, @@ -28614,70 +29553,13 @@ Object { Object { "$id": 5, "from": Object { - "$ref": 9, - }, - "identifier": Object { - "name": "one", - "range": Array [ - 85, - 88, - ], - "type": "Identifier", - }, - "kind": "r", - "resolved": Object { - "$ref": 2, - }, - "writeExpr": undefined, - }, - Object { - "$id": 6, - "from": Object { - "$ref": 9, - }, - "identifier": Object { - "name": "one", - "range": Array [ - 102, - 105, - ], - "type": "Identifier", - }, - "kind": "r", - "resolved": Object { - "$ref": 2, - }, - "writeExpr": undefined, - }, - Object { - "$id": 7, - "from": Object { - "$ref": 9, - }, - "identifier": Object { - "name": "one", - "range": Array [ - 122, - 125, - ], - "type": "Identifier", - }, - "kind": "r", - "resolved": Object { - "$ref": 2, - }, - "writeExpr": undefined, - }, - Object { - "$id": 8, - "from": Object { - "$ref": 9, + "$ref": 6, }, "identifier": Object { "name": "one", "range": Array [ - 144, - 147, + 81, + 84, ], "type": "Identifier", }, @@ -28691,7 +29573,7 @@ Object { "throughReferences": Array [], "type": "function", "upperScope": Object { - "$ref": 10, + "$ref": 7, }, "variableMap": Object { "arguments": Object { @@ -28702,7 +29584,7 @@ Object { }, }, "variableScope": Object { - "$ref": 9, + "$ref": 6, }, "variables": Array [ Object { @@ -28713,7 +29595,7 @@ Object { "name": "arguments", "references": Array [], "scope": Object { - "$ref": 9, + "$ref": 6, }, }, Object { @@ -28723,15 +29605,15 @@ Object { "name": Object { "name": "one", "range": Array [ - 38, - 47, + 25, + 34, ], "type": "Identifier", }, "node": Object { "range": Array [ 0, - 167, + 100, ], "type": "FunctionDeclaration", }, @@ -28744,8 +29626,8 @@ Object { Object { "name": "one", "range": Array [ - 38, - 47, + 25, + 34, ], "type": "Identifier", }, @@ -28761,18 +29643,9 @@ Object { Object { "$ref": 5, }, - Object { - "$ref": 6, - }, - Object { - "$ref": 7, - }, - Object { - "$ref": 8, - }, ], "scope": Object { - "$ref": 9, + "$ref": 6, }, }, ], @@ -28784,15 +29657,15 @@ Object { "throughReferences": Array [], "type": "module", "upperScope": Object { - "$ref": 11, + "$ref": 8, }, "variableMap": Object { - "processOptionalElementParens": Object { + "processOptional": Object { "$ref": 0, }, }, "variableScope": Object { - "$ref": 10, + "$ref": 7, }, "variables": Array [ Object { @@ -28800,17 +29673,17 @@ Object { "defs": Array [ Object { "name": Object { - "name": "processOptionalElementParens", + "name": "processOptional", "range": Array [ 9, - 37, + 24, ], "type": "Identifier", }, "node": Object { "range": Array [ 0, - 167, + 100, ], "type": "FunctionDeclaration", }, @@ -28821,18 +29694,18 @@ Object { "eslintUsed": undefined, "identifiers": Array [ Object { - "name": "processOptionalElementParens", + "name": "processOptional", "range": Array [ 9, - 37, + 24, ], "type": "Identifier", }, ], - "name": "processOptionalElementParens", + "name": "processOptional", "references": Array [], "scope": Object { - "$ref": 10, + "$ref": 7, }, }, ], @@ -28846,7 +29719,7 @@ Object { "upperScope": null, "variableMap": Object {}, "variableScope": Object { - "$ref": 11, + "$ref": 8, }, "variables": Array [], } diff --git a/packages/shared-fixtures/fixtures/typescript/basics/optional-chain-call-with-non-null-assertion.src.ts b/packages/shared-fixtures/fixtures/typescript/basics/optional-chain-call-with-non-null-assertion.src.ts new file mode 100644 index 000000000000..c86387595e47 --- /dev/null +++ b/packages/shared-fixtures/fixtures/typescript/basics/optional-chain-call-with-non-null-assertion.src.ts @@ -0,0 +1,8 @@ +function processOptional(one?: any) { + one?.two!(); + one?.two!.three(); + (one?.two)!(); + (one?.two)!.three(); + (one?.two!)(); + (one?.two!).three(); +} diff --git a/packages/shared-fixtures/fixtures/typescript/basics/optional-chain-element-access-with-non-null-assertion.src.ts b/packages/shared-fixtures/fixtures/typescript/basics/optional-chain-element-access-with-non-null-assertion.src.ts new file mode 100644 index 000000000000..ee4e7fc8451f --- /dev/null +++ b/packages/shared-fixtures/fixtures/typescript/basics/optional-chain-element-access-with-non-null-assertion.src.ts @@ -0,0 +1,8 @@ +function processOptional(one?: any) { + one?.['two']!.three; + (one?.['two'])!.three; + (one?.['two']!).three; + one?.two!['three']; + (one?.two)!['three']; + (one?.two!)['three']; +} diff --git a/packages/shared-fixtures/fixtures/typescript/basics/optional-chain-with-non-null-assertion.src.ts b/packages/shared-fixtures/fixtures/typescript/basics/optional-chain-with-non-null-assertion.src.ts new file mode 100644 index 000000000000..a7a94dcaa2bf --- /dev/null +++ b/packages/shared-fixtures/fixtures/typescript/basics/optional-chain-with-non-null-assertion.src.ts @@ -0,0 +1,5 @@ +function processOptional(one?: any) { + one?.two!.three; + (one?.two)!.three; + (one?.two!).three; +} diff --git a/packages/typescript-estree/src/convert.ts b/packages/typescript-estree/src/convert.ts index 1e693c58efc0..66111f488403 100644 --- a/packages/typescript-estree/src/convert.ts +++ b/packages/typescript-estree/src/convert.ts @@ -18,6 +18,7 @@ import { isComputedProperty, isESTreeClassMember, isOptional, + isChildOptionalChain, unescapeStringLiteralText, TSError, } from './node-utils'; @@ -241,7 +242,11 @@ export class Converter { ): T { const result = data; if (!result.range) { - result.range = getRange(node, this.ast); + result.range = getRange( + // this is completely valid, but TS hates it + node as never, + this.ast, + ); } if (!result.loc) { result.loc = getLocFor(result.range[0], result.range[1], this.ast); @@ -1748,11 +1753,7 @@ export class Converter { const isLocallyOptional = node.questionDotToken !== undefined; // the optional expression should propagate up the member expression tree - const isChildOptional = - (object.type === AST_NODE_TYPES.OptionalMemberExpression || - object.type === AST_NODE_TYPES.OptionalCallExpression) && - // (x?.y).z is semantically different, and as such .z is no longer optional - node.expression.kind !== ts.SyntaxKind.ParenthesizedExpression; + const isChildOptional = isChildOptionalChain(node, object); if (isLocallyOptional || isChildOptional) { return this.createNode(node, { @@ -1780,11 +1781,7 @@ export class Converter { const isLocallyOptional = node.questionDotToken !== undefined; // the optional expression should propagate up the member expression tree - const isChildOptional = - (object.type === AST_NODE_TYPES.OptionalMemberExpression || - object.type === AST_NODE_TYPES.OptionalCallExpression) && - // (x?.y).z is semantically different, and as such .z is no longer optional - node.expression.kind !== ts.SyntaxKind.ParenthesizedExpression; + const isChildOptional = isChildOptionalChain(node, object); if (isLocallyOptional || isChildOptional) { return this.createNode(node, { @@ -1812,11 +1809,7 @@ export class Converter { const isLocallyOptional = node.questionDotToken !== undefined; // the optional expression should propagate up the member expression tree - const isChildOptional = - (callee.type === AST_NODE_TYPES.OptionalMemberExpression || - callee.type === AST_NODE_TYPES.OptionalCallExpression) && - // (x?.y).z() is semantically different, and as such .z() is no longer optional - node.expression.kind !== ts.SyntaxKind.ParenthesizedExpression; + const isChildOptional = isChildOptionalChain(node, callee); if (isLocallyOptional || isChildOptional) { result = this.createNode(node, { diff --git a/packages/typescript-estree/src/node-utils.ts b/packages/typescript-estree/src/node-utils.ts index 6cbc6b0ba82b..835c3f962693 100644 --- a/packages/typescript-estree/src/node-utils.ts +++ b/packages/typescript-estree/src/node-utils.ts @@ -1,4 +1,5 @@ import unescape from 'lodash/unescape'; +import * as semver from 'semver'; import * as ts from 'typescript'; import { AST_NODE_TYPES, AST_TOKEN_TYPES, TSESTree } from './ts-estree'; @@ -448,6 +449,70 @@ export function isOptional(node: { : false; } +/** + * Returns true if the node is an optional chain node + */ +export function isOptionalChain( + node: TSESTree.Node, +): node is TSESTree.OptionalCallExpression | TSESTree.OptionalMemberExpression { + return ( + node.type === AST_NODE_TYPES.OptionalCallExpression || + node.type == AST_NODE_TYPES.OptionalMemberExpression + ); +} + +/** + * Returns true if the current TS version is TS 3.9 + */ +function isTSv3dot9(): boolean { + return !semver.satisfies(ts.version, '< 3.9.0 || < 3.9.1-rc || < 3.9.0-beta'); +} + +/** + * Returns true of the child of property access expression is an optional chain + */ +export function isChildOptionalChain( + node: + | ts.PropertyAccessExpression + | ts.ElementAccessExpression + | ts.CallExpression, + object: TSESTree.LeftHandSideExpression, +): boolean { + if ( + isOptionalChain(object) && + // (x?.y).z is semantically different, and as such .z is no longer optional + node.expression.kind !== ts.SyntaxKind.ParenthesizedExpression + ) { + return true; + } + + if (!isTSv3dot9()) { + return false; + } + + // TS3.9 made a breaking change to how non-null works with optional chains. + // Pre-3.9, `x?.y!.z` means `(x?.y).z` - i.e. it essentially scrubbed the optionality from the chain + // Post-3.9, `x?.y!.z` means `x?.y!.z` - i.e. it just asserts that the property `y` is non-null, not the result of `x?.y` + + if ( + object.type !== AST_NODE_TYPES.TSNonNullExpression || + !isOptionalChain(object.expression) + ) { + return false; + } + + if ( + // make sure it's not (x.y)!.z + node.expression.kind === ts.SyntaxKind.NonNullExpression && + (node.expression as ts.NonNullExpression).expression.kind !== + ts.SyntaxKind.ParenthesizedExpression + ) { + return true; + } + + return false; +} + /** * Returns the type of a given ts.Token * @param token the ts.Token diff --git a/packages/typescript-estree/src/ts-estree/ts-nodes.ts b/packages/typescript-estree/src/ts-estree/ts-nodes.ts index 825aceab97d3..2b8505d1fda2 100644 --- a/packages/typescript-estree/src/ts-estree/ts-nodes.ts +++ b/packages/typescript-estree/src/ts-estree/ts-nodes.ts @@ -2,191 +2,188 @@ import * as ts from 'typescript'; export type TSToken = ts.Token; -export type TSNode = ts.Node & - ( - | ts.Modifier - | ts.Identifier - | ts.QualifiedName - | ts.ComputedPropertyName - | ts.Decorator - | ts.TypeParameterDeclaration - // | ts.SignatureDeclarationBase -> CallSignatureDeclaration, ConstructSignatureDeclaration - | ts.CallSignatureDeclaration - | ts.ConstructSignatureDeclaration - | ts.VariableDeclaration - | ts.VariableDeclarationList - | ts.ParameterDeclaration - | ts.BindingElement - | ts.PropertySignature - | ts.PropertyDeclaration - | ts.PropertyAssignment - | ts.ShorthandPropertyAssignment - | ts.SpreadAssignment - | ts.ObjectBindingPattern - | ts.ArrayBindingPattern - | ts.FunctionDeclaration - | ts.MethodSignature - | ts.MethodDeclaration - | ts.ConstructorDeclaration - | ts.SemicolonClassElement - | ts.GetAccessorDeclaration - | ts.SetAccessorDeclaration - | ts.IndexSignatureDeclaration - | ts.KeywordTypeNode // TODO: This node is bad, maybe we should report this - | ts.ImportTypeNode - | ts.ThisTypeNode - // | ts.FunctionOrConstructorTypeNodeBase -> FunctionTypeNode, ConstructorTypeNode - | ts.ConstructorTypeNode - | ts.FunctionTypeNode - | ts.TypeReferenceNode - | ts.TypePredicateNode - | ts.TypeQueryNode - | ts.TypeLiteralNode - | ts.ArrayTypeNode - | ts.TupleTypeNode - | ts.OptionalTypeNode - | ts.RestTypeNode - | ts.UnionTypeNode - | ts.IntersectionTypeNode - | ts.ConditionalTypeNode - | ts.InferTypeNode - | ts.ParenthesizedTypeNode - | ts.TypeOperatorNode - | ts.IndexedAccessTypeNode - | ts.MappedTypeNode - | ts.LiteralTypeNode - | ts.StringLiteral - | ts.OmittedExpression - | ts.PartiallyEmittedExpression - | ts.PrefixUnaryExpression - | ts.PostfixUnaryExpression - | ts.NullLiteral - | ts.BooleanLiteral - | ts.ThisExpression - | ts.SuperExpression - | ts.ImportExpression - | ts.DeleteExpression - | ts.TypeOfExpression - | ts.VoidExpression - | ts.AwaitExpression - | ts.YieldExpression - | ts.SyntheticExpression - | ts.BinaryExpression - | ts.ConditionalExpression - | ts.FunctionExpression - | ts.ArrowFunction - | ts.RegularExpressionLiteral - | ts.NoSubstitutionTemplateLiteral - | ts.NumericLiteral - | ts.BigIntLiteral - | ts.TemplateHead - | ts.TemplateMiddle - | ts.TemplateTail - | ts.TemplateExpression - | ts.TemplateSpan - | ts.ParenthesizedExpression - | ts.ArrayLiteralExpression - | ts.SpreadElement - | ts.ObjectLiteralExpression - | ts.PropertyAccessExpression - | ts.ElementAccessExpression - | ts.CallExpression - | ts.ExpressionWithTypeArguments - | ts.NewExpression - | ts.TaggedTemplateExpression - | ts.AsExpression - | ts.TypeAssertion - | ts.NonNullExpression - | ts.MetaProperty - | ts.JsxElement - | ts.JsxOpeningElement - | ts.JsxSelfClosingElement - | ts.JsxFragment - | ts.JsxOpeningFragment - | ts.JsxClosingFragment - | ts.JsxAttribute - | ts.JsxSpreadAttribute - | ts.JsxClosingElement - | ts.JsxExpression - | ts.JsxText - | ts.NotEmittedStatement - | ts.CommaListExpression - | ts.EmptyStatement - | ts.DebuggerStatement - | ts.MissingDeclaration - | ts.Block - | ts.VariableStatement - | ts.ExpressionStatement - | ts.IfStatement - | ts.DoStatement - | ts.WhileStatement - | ts.ForStatement - | ts.ForInStatement - | ts.ForOfStatement - | ts.BreakStatement - | ts.ContinueStatement - | ts.ReturnStatement - | ts.WithStatement - | ts.SwitchStatement - | ts.CaseBlock - | ts.CaseClause - | ts.DefaultClause - | ts.LabeledStatement - | ts.ThrowStatement - | ts.TryStatement - | ts.CatchClause - // | ts.ClassLikeDeclarationBase -> ClassDeclaration | ClassExpression - | ts.ClassDeclaration - | ts.ClassExpression - | ts.InterfaceDeclaration - | ts.HeritageClause - | ts.TypeAliasDeclaration - | ts.EnumMember - | ts.EnumDeclaration - | ts.ModuleDeclaration - | ts.ModuleBlock - | ts.ImportEqualsDeclaration - | ts.ExternalModuleReference - | ts.ImportDeclaration - | ts.ImportClause - | ts.NamespaceImport - | ts.NamespaceExportDeclaration - | ts.ExportDeclaration - | ts.NamedImports - | ts.NamedExports - | ts.ImportSpecifier - | ts.ExportSpecifier - | ts.ExportAssignment - | ts.CommentRange - | ts.SourceFile - | ts.Bundle - | ts.InputFiles - | ts.UnparsedSource - | ts.JsonMinusNumericLiteral +export type TSNode = + | ts.Modifier + | ts.Identifier + | ts.QualifiedName + | ts.ComputedPropertyName + | ts.Decorator + | ts.TypeParameterDeclaration + // | ts.SignatureDeclarationBase -> CallSignatureDeclaration, ConstructSignatureDeclaration + | ts.CallSignatureDeclaration + | ts.ConstructSignatureDeclaration + | ts.VariableDeclaration + | ts.VariableDeclarationList + | ts.ParameterDeclaration + | ts.BindingElement + | ts.PropertySignature + | ts.PropertyDeclaration + | ts.PropertyAssignment + | ts.ShorthandPropertyAssignment + | ts.SpreadAssignment + | ts.ObjectBindingPattern + | ts.ArrayBindingPattern + | ts.FunctionDeclaration + | ts.MethodSignature + | ts.MethodDeclaration + | ts.ConstructorDeclaration + | ts.SemicolonClassElement + | ts.GetAccessorDeclaration + | ts.SetAccessorDeclaration + | ts.IndexSignatureDeclaration + | ts.KeywordTypeNode // TODO: This node is bad, maybe we should report this + | ts.ImportTypeNode + | ts.ThisTypeNode + // | ts.FunctionOrConstructorTypeNodeBase -> FunctionTypeNode, ConstructorTypeNode + | ts.ConstructorTypeNode + | ts.FunctionTypeNode + | ts.TypeReferenceNode + | ts.TypePredicateNode + | ts.TypeQueryNode + | ts.TypeLiteralNode + | ts.ArrayTypeNode + | ts.TupleTypeNode + | ts.OptionalTypeNode + | ts.RestTypeNode + | ts.UnionTypeNode + | ts.IntersectionTypeNode + | ts.ConditionalTypeNode + | ts.InferTypeNode + | ts.ParenthesizedTypeNode + | ts.TypeOperatorNode + | ts.IndexedAccessTypeNode + | ts.MappedTypeNode + | ts.LiteralTypeNode + | ts.StringLiteral + | ts.OmittedExpression + | ts.PartiallyEmittedExpression + | ts.PrefixUnaryExpression + | ts.PostfixUnaryExpression + | ts.NullLiteral + | ts.BooleanLiteral + | ts.ThisExpression + | ts.SuperExpression + | ts.ImportExpression + | ts.DeleteExpression + | ts.TypeOfExpression + | ts.VoidExpression + | ts.AwaitExpression + | ts.YieldExpression + | ts.SyntheticExpression + | ts.BinaryExpression + | ts.ConditionalExpression + | ts.FunctionExpression + | ts.ArrowFunction + | ts.RegularExpressionLiteral + | ts.NoSubstitutionTemplateLiteral + | ts.NumericLiteral + | ts.BigIntLiteral + | ts.TemplateHead + | ts.TemplateMiddle + | ts.TemplateTail + | ts.TemplateExpression + | ts.TemplateSpan + | ts.ParenthesizedExpression + | ts.ArrayLiteralExpression + | ts.SpreadElement + | ts.ObjectLiteralExpression + | ts.PropertyAccessExpression + | ts.ElementAccessExpression + | ts.CallExpression + | ts.ExpressionWithTypeArguments + | ts.NewExpression + | ts.TaggedTemplateExpression + | ts.AsExpression + | ts.TypeAssertion + | ts.NonNullExpression + | ts.MetaProperty + | ts.JsxElement + | ts.JsxOpeningElement + | ts.JsxSelfClosingElement + | ts.JsxFragment + | ts.JsxOpeningFragment + | ts.JsxClosingFragment + | ts.JsxAttribute + | ts.JsxSpreadAttribute + | ts.JsxClosingElement + | ts.JsxExpression + | ts.JsxText + | ts.NotEmittedStatement + | ts.CommaListExpression + | ts.EmptyStatement + | ts.DebuggerStatement + | ts.MissingDeclaration + | ts.Block + | ts.VariableStatement + | ts.ExpressionStatement + | ts.IfStatement + | ts.DoStatement + | ts.WhileStatement + | ts.ForStatement + | ts.ForInStatement + | ts.ForOfStatement + | ts.BreakStatement + | ts.ContinueStatement + | ts.ReturnStatement + | ts.WithStatement + | ts.SwitchStatement + | ts.CaseBlock + | ts.CaseClause + | ts.DefaultClause + | ts.LabeledStatement + | ts.ThrowStatement + | ts.TryStatement + | ts.CatchClause + // | ts.ClassLikeDeclarationBase -> ClassDeclaration | ClassExpression + | ts.ClassDeclaration + | ts.ClassExpression + | ts.InterfaceDeclaration + | ts.HeritageClause + | ts.TypeAliasDeclaration + | ts.EnumMember + | ts.EnumDeclaration + | ts.ModuleDeclaration + | ts.ModuleBlock + | ts.ImportEqualsDeclaration + | ts.ExternalModuleReference + | ts.ImportDeclaration + | ts.ImportClause + | ts.NamespaceImport + | ts.NamespaceExportDeclaration + | ts.ExportDeclaration + | ts.NamedImports + | ts.NamedExports + | ts.ImportSpecifier + | ts.ExportSpecifier + | ts.ExportAssignment + | ts.SourceFile + | ts.Bundle + | ts.InputFiles + | ts.UnparsedSource + | ts.JsonMinusNumericLiteral - // JSDoc: Unsupported - | ts.JSDoc - | ts.JSDocTypeExpression - | ts.JSDocUnknownTag - | ts.JSDocAugmentsTag - | ts.JSDocClassTag - | ts.JSDocEnumTag - | ts.JSDocThisTag - | ts.JSDocTemplateTag - | ts.JSDocReturnTag - | ts.JSDocTypeTag - | ts.JSDocTypedefTag - | ts.JSDocCallbackTag - | ts.JSDocSignature - | ts.JSDocPropertyTag - | ts.JSDocParameterTag - | ts.JSDocTypeLiteral - | ts.JSDocFunctionType - | ts.JSDocAllType - | ts.JSDocUnknownType - | ts.JSDocNullableType - | ts.JSDocNonNullableType - | ts.JSDocOptionalType - | ts.JSDocVariadicType - | ts.JSDocAuthorTag - ); + // JSDoc: Unsupported + | ts.JSDoc + | ts.JSDocTypeExpression + | ts.JSDocUnknownTag + | ts.JSDocAugmentsTag + | ts.JSDocClassTag + | ts.JSDocEnumTag + | ts.JSDocThisTag + | ts.JSDocTemplateTag + | ts.JSDocReturnTag + | ts.JSDocTypeTag + | ts.JSDocTypedefTag + | ts.JSDocCallbackTag + | ts.JSDocSignature + | ts.JSDocPropertyTag + | ts.JSDocParameterTag + | ts.JSDocTypeLiteral + | ts.JSDocFunctionType + | ts.JSDocAllType + | ts.JSDocUnknownType + | ts.JSDocNullableType + | ts.JSDocNonNullableType + | ts.JSDocOptionalType + | ts.JSDocVariadicType + | ts.JSDocAuthorTag; diff --git a/packages/typescript-estree/tests/lib/__snapshots__/convert.ts.snap b/packages/typescript-estree/tests/lib/__snapshots__/convert.ts.snap index 82c53ddf8cb9..448b85afda1f 100644 --- a/packages/typescript-estree/tests/lib/__snapshots__/convert.ts.snap +++ b/packages/typescript-estree/tests/lib/__snapshots__/convert.ts.snap @@ -6,6 +6,7 @@ Object { "bindDiagnostics": Array [], "bindSuggestionDiagnostics": undefined, "checkJsDirective": undefined, + "commentDirectives": undefined, "endOfFileToken": Object { "loc": Object { "end": Object { diff --git a/packages/typescript-estree/tests/lib/__snapshots__/semantic-diagnostics-enabled.ts.snap b/packages/typescript-estree/tests/lib/__snapshots__/semantic-diagnostics-enabled.ts.snap index ad2d09238013..124cc7cde046 100644 --- a/packages/typescript-estree/tests/lib/__snapshots__/semantic-diagnostics-enabled.ts.snap +++ b/packages/typescript-estree/tests/lib/__snapshots__/semantic-diagnostics-enabled.ts.snap @@ -1994,12 +1994,18 @@ exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" e exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" enabled fixtures/typescript/basics/optional-chain-call.src 1`] = `"TEST OUTPUT: No semantic or syntactic issues found"`; +exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" enabled fixtures/typescript/basics/optional-chain-call-with-non-null-assertion.src 1`] = `"TEST OUTPUT: No semantic or syntactic issues found"`; + exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" enabled fixtures/typescript/basics/optional-chain-call-with-parens.src 1`] = `"TEST OUTPUT: No semantic or syntactic issues found"`; exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" enabled fixtures/typescript/basics/optional-chain-element-access.src 1`] = `"TEST OUTPUT: No semantic or syntactic issues found"`; +exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" enabled fixtures/typescript/basics/optional-chain-element-access-with-non-null-assertion.src 1`] = `"TEST OUTPUT: No semantic or syntactic issues found"`; + exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" enabled fixtures/typescript/basics/optional-chain-element-access-with-parens.src 1`] = `"TEST OUTPUT: No semantic or syntactic issues found"`; +exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" enabled fixtures/typescript/basics/optional-chain-with-non-null-assertion.src 1`] = `"TEST OUTPUT: No semantic or syntactic issues found"`; + exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" enabled fixtures/typescript/basics/optional-chain-with-parens.src 1`] = `"TEST OUTPUT: No semantic or syntactic issues found"`; exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" enabled fixtures/typescript/basics/parenthesized-use-strict.src 1`] = `"TEST OUTPUT: No semantic or syntactic issues found"`; diff --git a/packages/typescript-estree/tests/lib/__snapshots__/typescript.ts.snap b/packages/typescript-estree/tests/lib/__snapshots__/typescript.ts.snap index 800d7042f2c8..5143a42c849d 100644 --- a/packages/typescript-estree/tests/lib/__snapshots__/typescript.ts.snap +++ b/packages/typescript-estree/tests/lib/__snapshots__/typescript.ts.snap @@ -85525,7 +85525,7 @@ Object { } `; -exports[`typescript fixtures/basics/optional-chain-call-with-parens.src 1`] = ` +exports[`typescript fixtures/basics/optional-chain-call-with-non-null-assertion.src 1`] = ` Object { "body": Array [ Object { @@ -85536,74 +85536,91 @@ Object { "expression": Object { "arguments": Array [], "callee": Object { - "computed": false, - "loc": Object { - "end": Object { - "column": 10, - "line": 2, - }, - "start": Object { - "column": 3, - "line": 2, - }, - }, - "object": Object { + "expression": Object { + "computed": false, "loc": Object { "end": Object { - "column": 6, + "column": 10, "line": 2, }, "start": Object { - "column": 3, + "column": 2, "line": 2, }, }, - "name": "one", - "range": Array [ - 51, - 54, - ], - "type": "Identifier", - }, - "optional": true, - "property": Object { - "loc": Object { - "end": Object { - "column": 10, - "line": 2, + "object": Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 2, + }, + "start": Object { + "column": 2, + "line": 2, + }, }, - "start": Object { - "column": 8, - "line": 2, + "name": "one", + "range": Array [ + 40, + 43, + ], + "type": "Identifier", + }, + "optional": true, + "property": Object { + "loc": Object { + "end": Object { + "column": 10, + "line": 2, + }, + "start": Object { + "column": 7, + "line": 2, + }, }, + "name": "two", + "range": Array [ + 45, + 48, + ], + "type": "Identifier", }, - "name": "fn", "range": Array [ - 56, - 58, + 40, + 48, ], - "type": "Identifier", + "type": "OptionalMemberExpression", + }, + "loc": Object { + "end": Object { + "column": 11, + "line": 2, + }, + "start": Object { + "column": 2, + "line": 2, + }, }, "range": Array [ - 51, - 58, + 40, + 49, ], - "type": "OptionalMemberExpression", + "type": "TSNonNullExpression", }, "loc": Object { "end": Object { - "column": 12, + "column": 13, "line": 2, }, "start": Object { - "column": 3, + "column": 2, "line": 2, }, }, "optional": false, "range": Array [ + 40, 51, - 60, ], "type": "OptionalCallExpression", }, @@ -85618,8 +85635,8 @@ Object { }, }, "range": Array [ - 50, - 62, + 40, + 52, ], "type": "ExpressionStatement", }, @@ -85630,7 +85647,7 @@ Object { "computed": false, "loc": Object { "end": Object { - "column": 15, + "column": 17, "line": 3, }, "start": Object { @@ -85639,88 +85656,105 @@ Object { }, }, "object": Object { - "computed": false, - "loc": Object { - "end": Object { - "column": 11, - "line": 3, - }, - "start": Object { - "column": 3, - "line": 3, - }, - }, - "object": Object { + "expression": Object { + "computed": false, "loc": Object { "end": Object { - "column": 6, + "column": 10, "line": 3, }, "start": Object { - "column": 3, + "column": 2, "line": 3, }, }, - "name": "one", - "range": Array [ - 66, - 69, - ], - "type": "Identifier", - }, - "optional": true, - "property": Object { - "loc": Object { - "end": Object { - "column": 11, - "line": 3, + "object": Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 3, + }, + "start": Object { + "column": 2, + "line": 3, + }, }, - "start": Object { - "column": 8, - "line": 3, + "name": "one", + "range": Array [ + 55, + 58, + ], + "type": "Identifier", + }, + "optional": true, + "property": Object { + "loc": Object { + "end": Object { + "column": 10, + "line": 3, + }, + "start": Object { + "column": 7, + "line": 3, + }, }, + "name": "two", + "range": Array [ + 60, + 63, + ], + "type": "Identifier", }, - "name": "two", "range": Array [ - 71, - 74, + 55, + 63, ], - "type": "Identifier", + "type": "OptionalMemberExpression", + }, + "loc": Object { + "end": Object { + "column": 11, + "line": 3, + }, + "start": Object { + "column": 2, + "line": 3, + }, }, "range": Array [ - 66, - 74, + 55, + 64, ], - "type": "OptionalMemberExpression", + "type": "TSNonNullExpression", }, "optional": false, "property": Object { "loc": Object { "end": Object { - "column": 15, + "column": 17, "line": 3, }, "start": Object { - "column": 13, + "column": 12, "line": 3, }, }, - "name": "fn", + "name": "three", "range": Array [ - 76, - 78, + 65, + 70, ], "type": "Identifier", }, "range": Array [ - 65, - 78, + 55, + 70, ], - "type": "MemberExpression", + "type": "OptionalMemberExpression", }, "loc": Object { "end": Object { - "column": 17, + "column": 19, "line": 3, }, "start": Object { @@ -85730,14 +85764,14 @@ Object { }, "optional": false, "range": Array [ - 65, - 80, + 55, + 72, ], - "type": "CallExpression", + "type": "OptionalCallExpression", }, "loc": Object { "end": Object { - "column": 18, + "column": 20, "line": 3, }, "start": Object { @@ -85746,8 +85780,8 @@ Object { }, }, "range": Array [ - 65, - 81, + 55, + 73, ], "type": "ExpressionStatement", }, @@ -85755,22 +85789,11 @@ Object { "expression": Object { "arguments": Array [], "callee": Object { - "computed": false, - "loc": Object { - "end": Object { - "column": 14, - "line": 4, - }, - "start": Object { - "column": 3, - "line": 4, - }, - }, - "object": Object { + "expression": Object { "computed": false, "loc": Object { "end": Object { - "column": 10, + "column": 11, "line": 4, }, "start": Object { @@ -85791,81 +85814,72 @@ Object { }, "name": "one", "range": Array [ - 85, - 88, + 77, + 80, ], "type": "Identifier", }, - "optional": false, + "optional": true, "property": Object { "loc": Object { "end": Object { - "column": 10, + "column": 11, "line": 4, }, "start": Object { - "column": 7, + "column": 8, "line": 4, }, }, "name": "two", "range": Array [ - 89, - 92, + 82, + 85, ], "type": "Identifier", }, "range": Array [ + 77, 85, - 92, ], - "type": "MemberExpression", + "type": "OptionalMemberExpression", }, - "optional": true, - "property": Object { - "loc": Object { - "end": Object { - "column": 14, - "line": 4, - }, - "start": Object { - "column": 12, - "line": 4, - }, + "loc": Object { + "end": Object { + "column": 13, + "line": 4, + }, + "start": Object { + "column": 2, + "line": 4, }, - "name": "fn", - "range": Array [ - 94, - 96, - ], - "type": "Identifier", }, "range": Array [ - 85, - 96, + 76, + 87, ], - "type": "OptionalMemberExpression", + "type": "TSNonNullExpression", }, "loc": Object { "end": Object { - "column": 16, + "column": 15, "line": 4, }, "start": Object { - "column": 3, + "column": 2, "line": 4, }, }, "optional": false, "range": Array [ - 85, - 98, + 76, + 89, ], - "type": "OptionalCallExpression", + "type": "CallExpression", }, "loc": Object { "end": Object { - "column": 18, + "column": 16, "line": 4, }, "start": Object { @@ -85874,8 +85888,8 @@ Object { }, }, "range": Array [ - 84, - 100, + 76, + 90, ], "type": "ExpressionStatement", }, @@ -85886,7 +85900,7 @@ Object { "computed": false, "loc": Object { "end": Object { - "column": 21, + "column": 19, "line": 5, }, "start": Object { @@ -85895,22 +85909,11 @@ Object { }, }, "object": Object { - "computed": false, - "loc": Object { - "end": Object { - "column": 17, - "line": 5, - }, - "start": Object { - "column": 3, - "line": 5, - }, - }, - "object": Object { + "expression": Object { "computed": false, "loc": Object { "end": Object { - "column": 10, + "column": 11, "line": 5, }, "start": Object { @@ -85931,89 +85934,80 @@ Object { }, "name": "one", "range": Array [ - 104, - 107, + 94, + 97, ], "type": "Identifier", }, - "optional": false, + "optional": true, "property": Object { "loc": Object { "end": Object { - "column": 10, + "column": 11, "line": 5, }, "start": Object { - "column": 7, + "column": 8, "line": 5, }, }, "name": "two", "range": Array [ - 108, - 111, + 99, + 102, ], "type": "Identifier", }, "range": Array [ - 104, - 111, + 94, + 102, ], - "type": "MemberExpression", + "type": "OptionalMemberExpression", }, - "optional": true, - "property": Object { - "loc": Object { - "end": Object { - "column": 17, - "line": 5, - }, - "start": Object { - "column": 12, - "line": 5, - }, + "loc": Object { + "end": Object { + "column": 13, + "line": 5, + }, + "start": Object { + "column": 2, + "line": 5, }, - "name": "three", - "range": Array [ - 113, - 118, - ], - "type": "Identifier", }, "range": Array [ + 93, 104, - 118, ], - "type": "OptionalMemberExpression", + "type": "TSNonNullExpression", }, "optional": false, "property": Object { "loc": Object { "end": Object { - "column": 21, + "column": 19, "line": 5, }, "start": Object { - "column": 19, + "column": 14, "line": 5, }, }, - "name": "fn", + "name": "three", "range": Array [ - 120, - 122, + 105, + 110, ], "type": "Identifier", }, "range": Array [ - 103, - 122, + 93, + 110, ], "type": "MemberExpression", }, "loc": Object { "end": Object { - "column": 23, + "column": 21, "line": 5, }, "start": Object { @@ -86023,14 +86017,14 @@ Object { }, "optional": false, "range": Array [ - 103, - 124, + 93, + 112, ], "type": "CallExpression", }, "loc": Object { "end": Object { - "column": 24, + "column": 22, "line": 5, }, "start": Object { @@ -86039,8 +86033,8 @@ Object { }, }, "range": Array [ - 103, - 125, + 93, + 113, ], "type": "ExpressionStatement", }, @@ -86048,22 +86042,11 @@ Object { "expression": Object { "arguments": Array [], "callee": Object { - "computed": false, - "loc": Object { - "end": Object { - "column": 21, - "line": 6, - }, - "start": Object { - "column": 3, - "line": 6, - }, - }, - "object": Object { + "expression": Object { "computed": false, "loc": Object { "end": Object { - "column": 17, + "column": 11, "line": 6, }, "start": Object { @@ -86072,10 +86055,9 @@ Object { }, }, "object": Object { - "computed": false, "loc": Object { "end": Object { - "column": 10, + "column": 6, "line": 6, }, "start": Object { @@ -86083,119 +86065,74 @@ Object { "line": 6, }, }, - "object": Object { - "loc": Object { - "end": Object { - "column": 6, - "line": 6, - }, - "start": Object { - "column": 3, - "line": 6, - }, - }, - "name": "one", - "range": Array [ - 129, - 132, - ], - "type": "Identifier", - }, - "optional": false, - "property": Object { - "loc": Object { - "end": Object { - "column": 10, - "line": 6, - }, - "start": Object { - "column": 7, - "line": 6, - }, - }, - "name": "two", - "range": Array [ - 133, - 136, - ], - "type": "Identifier", - }, + "name": "one", "range": Array [ - 129, - 136, + 117, + 120, ], - "type": "MemberExpression", + "type": "Identifier", }, "optional": true, "property": Object { "loc": Object { "end": Object { - "column": 17, + "column": 11, "line": 6, }, "start": Object { - "column": 12, + "column": 8, "line": 6, }, }, - "name": "three", + "name": "two", "range": Array [ - 138, - 143, + 122, + 125, ], "type": "Identifier", }, "range": Array [ - 129, - 143, + 117, + 125, ], "type": "OptionalMemberExpression", }, - "optional": true, - "property": Object { - "loc": Object { - "end": Object { - "column": 21, - "line": 6, - }, - "start": Object { - "column": 19, - "line": 6, - }, + "loc": Object { + "end": Object { + "column": 12, + "line": 6, + }, + "start": Object { + "column": 3, + "line": 6, }, - "name": "fn", - "range": Array [ - 145, - 147, - ], - "type": "Identifier", }, "range": Array [ - 129, - 147, + 117, + 126, ], - "type": "OptionalMemberExpression", + "type": "TSNonNullExpression", }, "loc": Object { "end": Object { - "column": 23, + "column": 15, "line": 6, }, "start": Object { - "column": 3, + "column": 2, "line": 6, }, }, "optional": false, "range": Array [ + 116, 129, - 149, ], - "type": "OptionalCallExpression", + "type": "CallExpression", }, "loc": Object { "end": Object { - "column": 25, + "column": 16, "line": 6, }, "start": Object { @@ -86204,8 +86141,8 @@ Object { }, }, "range": Array [ - 128, - 151, + 116, + 130, ], "type": "ExpressionStatement", }, @@ -86213,290 +86150,144 @@ Object { "expression": Object { "arguments": Array [], "callee": Object { + "computed": false, "loc": Object { "end": Object { - "column": 6, - "line": 8, + "column": 19, + "line": 7, }, "start": Object { - "column": 3, - "line": 8, - }, - }, - "name": "one", - "range": Array [ - 156, - 159, - ], - "type": "Identifier", - }, - "loc": Object { - "end": Object { - "column": 10, - "line": 8, - }, - "start": Object { - "column": 3, - "line": 8, + "column": 2, + "line": 7, + }, }, - }, - "optional": true, - "range": Array [ - 156, - 163, - ], - "type": "OptionalCallExpression", - }, - "loc": Object { - "end": Object { - "column": 12, - "line": 8, - }, - "start": Object { - "column": 2, - "line": 8, - }, - }, - "range": Array [ - 155, - 165, - ], - "type": "ExpressionStatement", - }, - Object { - "expression": Object { - "arguments": Array [], - "callee": Object { - "arguments": Array [], - "callee": Object { + "object": Object { + "expression": Object { + "computed": false, + "loc": Object { + "end": Object { + "column": 11, + "line": 7, + }, + "start": Object { + "column": 3, + "line": 7, + }, + }, + "object": Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 7, + }, + "start": Object { + "column": 3, + "line": 7, + }, + }, + "name": "one", + "range": Array [ + 134, + 137, + ], + "type": "Identifier", + }, + "optional": true, + "property": Object { + "loc": Object { + "end": Object { + "column": 11, + "line": 7, + }, + "start": Object { + "column": 8, + "line": 7, + }, + }, + "name": "two", + "range": Array [ + 139, + 142, + ], + "type": "Identifier", + }, + "range": Array [ + 134, + 142, + ], + "type": "OptionalMemberExpression", + }, "loc": Object { "end": Object { - "column": 6, - "line": 9, + "column": 12, + "line": 7, }, "start": Object { "column": 3, - "line": 9, + "line": 7, }, }, - "name": "one", "range": Array [ - 169, - 172, + 134, + 143, ], - "type": "Identifier", - }, - "loc": Object { - "end": Object { - "column": 10, - "line": 9, - }, - "start": Object { - "column": 3, - "line": 9, - }, - }, - "optional": true, - "range": Array [ - 169, - 176, - ], - "type": "OptionalCallExpression", - }, - "loc": Object { - "end": Object { - "column": 13, - "line": 9, - }, - "start": Object { - "column": 2, - "line": 9, + "type": "TSNonNullExpression", }, - }, - "optional": false, - "range": Array [ - 168, - 179, - ], - "type": "CallExpression", - }, - "loc": Object { - "end": Object { - "column": 14, - "line": 9, - }, - "start": Object { - "column": 2, - "line": 9, - }, - }, - "range": Array [ - 168, - 180, - ], - "type": "ExpressionStatement", - }, - Object { - "expression": Object { - "arguments": Array [], - "callee": Object { - "arguments": Array [], - "callee": Object { + "optional": false, + "property": Object { "loc": Object { "end": Object { - "column": 6, - "line": 10, + "column": 19, + "line": 7, }, "start": Object { - "column": 3, - "line": 10, + "column": 14, + "line": 7, }, }, - "name": "one", + "name": "three", "range": Array [ - 184, - 187, + 145, + 150, ], "type": "Identifier", }, - "loc": Object { - "end": Object { - "column": 10, - "line": 10, - }, - "start": Object { - "column": 3, - "line": 10, - }, - }, - "optional": true, "range": Array [ - 184, - 191, + 133, + 150, ], - "type": "OptionalCallExpression", + "type": "MemberExpression", }, "loc": Object { "end": Object { - "column": 15, - "line": 10, + "column": 21, + "line": 7, }, "start": Object { "column": 2, - "line": 10, + "line": 7, }, }, - "optional": true, + "optional": false, "range": Array [ - 183, - 196, + 133, + 152, ], - "type": "OptionalCallExpression", + "type": "CallExpression", }, "loc": Object { "end": Object { - "column": 16, - "line": 10, + "column": 22, + "line": 7, }, "start": Object { "column": 2, - "line": 10, + "line": 7, }, }, "range": Array [ - 183, - 197, - ], - "type": "ExpressionStatement", - }, - Object { - "expression": Object { - "computed": false, - "loc": Object { - "end": Object { - "column": 15, - "line": 12, - }, - "start": Object { - "column": 2, - "line": 12, - }, - }, - "object": Object { - "arguments": Array [], - "callee": Object { - "loc": Object { - "end": Object { - "column": 6, - "line": 12, - }, - "start": Object { - "column": 3, - "line": 12, - }, - }, - "name": "one", - "range": Array [ - 202, - 205, - ], - "type": "Identifier", - }, - "loc": Object { - "end": Object { - "column": 10, - "line": 12, - }, - "start": Object { - "column": 3, - "line": 12, - }, - }, - "optional": true, - "range": Array [ - 202, - 209, - ], - "type": "OptionalCallExpression", - }, - "optional": false, - "property": Object { - "loc": Object { - "end": Object { - "column": 15, - "line": 12, - }, - "start": Object { - "column": 12, - "line": 12, - }, - }, - "name": "two", - "range": Array [ - 211, - 214, - ], - "type": "Identifier", - }, - "range": Array [ - 201, - 214, - ], - "type": "MemberExpression", - }, - "loc": Object { - "end": Object { - "column": 16, - "line": 12, - }, - "start": Object { - "column": 2, - "line": 12, - }, - }, - "range": Array [ - 201, - 215, + 133, + 153, ], "type": "ExpressionStatement", }, @@ -86504,16 +86295,16 @@ Object { "loc": Object { "end": Object { "column": 1, - "line": 13, + "line": 8, }, "start": Object { - "column": 46, + "column": 36, "line": 1, }, }, "range": Array [ - 46, - 217, + 36, + 155, ], "type": "BlockStatement", }, @@ -86522,7 +86313,7 @@ Object { "id": Object { "loc": Object { "end": Object { - "column": 34, + "column": 24, "line": 1, }, "start": Object { @@ -86530,17 +86321,17 @@ Object { "line": 1, }, }, - "name": "processOptionalCallParens", + "name": "processOptional", "range": Array [ 9, - 34, + 24, ], "type": "Identifier", }, "loc": Object { "end": Object { "column": 1, - "line": 13, + "line": 8, }, "start": Object { "column": 0, @@ -86551,51 +86342,51 @@ Object { Object { "loc": Object { "end": Object { - "column": 44, + "column": 34, "line": 1, }, "start": Object { - "column": 35, + "column": 25, "line": 1, }, }, "name": "one", "optional": true, "range": Array [ - 35, - 44, + 25, + 34, ], "type": "Identifier", "typeAnnotation": Object { "loc": Object { "end": Object { - "column": 44, + "column": 34, "line": 1, }, "start": Object { - "column": 39, + "column": 29, "line": 1, }, }, "range": Array [ - 39, - 44, + 29, + 34, ], "type": "TSTypeAnnotation", "typeAnnotation": Object { "loc": Object { "end": Object { - "column": 44, + "column": 34, "line": 1, }, "start": Object { - "column": 41, + "column": 31, "line": 1, }, }, "range": Array [ - 41, - 44, + 31, + 34, ], "type": "TSAnyKeyword", }, @@ -86604,7 +86395,7 @@ Object { ], "range": Array [ 0, - 217, + 155, ], "type": "FunctionDeclaration", }, @@ -86612,7 +86403,7 @@ Object { "loc": Object { "end": Object { "column": 0, - "line": 14, + "line": 9, }, "start": Object { "column": 0, @@ -86621,7 +86412,7 @@ Object { }, "range": Array [ 0, - 218, + 156, ], "sourceType": "script", "tokens": Array [ @@ -86646,7 +86437,7 @@ Object { Object { "loc": Object { "end": Object { - "column": 34, + "column": 24, "line": 1, }, "start": Object { @@ -86656,25 +86447,25 @@ Object { }, "range": Array [ 9, - 34, + 24, ], "type": "Identifier", - "value": "processOptionalCallParens", + "value": "processOptional", }, Object { "loc": Object { "end": Object { - "column": 35, + "column": 25, "line": 1, }, "start": Object { - "column": 34, + "column": 24, "line": 1, }, }, "range": Array [ - 34, - 35, + 24, + 25, ], "type": "Punctuator", "value": "(", @@ -86682,17 +86473,17 @@ Object { Object { "loc": Object { "end": Object { - "column": 38, + "column": 28, "line": 1, }, "start": Object { - "column": 35, + "column": 25, "line": 1, }, }, "range": Array [ - 35, - 38, + 25, + 28, ], "type": "Identifier", "value": "one", @@ -86700,17 +86491,17 @@ Object { Object { "loc": Object { "end": Object { - "column": 39, + "column": 29, "line": 1, }, "start": Object { - "column": 38, + "column": 28, "line": 1, }, }, "range": Array [ - 38, - 39, + 28, + 29, ], "type": "Punctuator", "value": "?", @@ -86718,17 +86509,17 @@ Object { Object { "loc": Object { "end": Object { - "column": 40, + "column": 30, "line": 1, }, "start": Object { - "column": 39, + "column": 29, "line": 1, }, }, "range": Array [ - 39, - 40, + 29, + 30, ], "type": "Punctuator", "value": ":", @@ -86736,17 +86527,17 @@ Object { Object { "loc": Object { "end": Object { - "column": 44, + "column": 34, "line": 1, }, "start": Object { - "column": 41, + "column": 31, "line": 1, }, }, "range": Array [ - 41, - 44, + 31, + 34, ], "type": "Identifier", "value": "any", @@ -86754,17 +86545,17 @@ Object { Object { "loc": Object { "end": Object { - "column": 45, + "column": 35, "line": 1, }, "start": Object { - "column": 44, + "column": 34, "line": 1, }, }, "range": Array [ - 44, - 45, + 34, + 35, ], "type": "Punctuator", "value": ")", @@ -86772,17 +86563,17 @@ Object { Object { "loc": Object { "end": Object { - "column": 47, + "column": 37, "line": 1, }, "start": Object { - "column": 46, + "column": 36, "line": 1, }, }, "range": Array [ - 46, - 47, + 36, + 37, ], "type": "Punctuator", "value": "{", @@ -86790,7 +86581,7 @@ Object { Object { "loc": Object { "end": Object { - "column": 3, + "column": 5, "line": 2, }, "start": Object { @@ -86799,26 +86590,8 @@ Object { }, }, "range": Array [ - 50, - 51, - ], - "type": "Punctuator", - "value": "(", - }, - Object { - "loc": Object { - "end": Object { - "column": 6, - "line": 2, - }, - "start": Object { - "column": 3, - "line": 2, - }, - }, - "range": Array [ - 51, - 54, + 40, + 43, ], "type": "Identifier", "value": "one", @@ -86826,17 +86599,17 @@ Object { Object { "loc": Object { "end": Object { - "column": 8, + "column": 7, "line": 2, }, "start": Object { - "column": 6, + "column": 5, "line": 2, }, }, "range": Array [ - 54, - 56, + 43, + 45, ], "type": "Punctuator", "value": "?.", @@ -86848,16 +86621,16 @@ Object { "line": 2, }, "start": Object { - "column": 8, + "column": 7, "line": 2, }, }, "range": Array [ - 56, - 58, + 45, + 48, ], "type": "Identifier", - "value": "fn", + "value": "two", }, Object { "loc": Object { @@ -86871,11 +86644,11 @@ Object { }, }, "range": Array [ - 58, - 59, + 48, + 49, ], "type": "Punctuator", - "value": "(", + "value": "!", }, Object { "loc": Object { @@ -86889,11 +86662,11 @@ Object { }, }, "range": Array [ - 59, - 60, + 49, + 50, ], "type": "Punctuator", - "value": ")", + "value": "(", }, Object { "loc": Object { @@ -86907,8 +86680,8 @@ Object { }, }, "range": Array [ - 60, - 61, + 50, + 51, ], "type": "Punctuator", "value": ")", @@ -86925,8 +86698,8 @@ Object { }, }, "range": Array [ - 61, - 62, + 51, + 52, ], "type": "Punctuator", "value": ";", @@ -86934,7 +86707,7 @@ Object { Object { "loc": Object { "end": Object { - "column": 3, + "column": 5, "line": 3, }, "start": Object { @@ -86943,62 +86716,44 @@ Object { }, }, "range": Array [ - 65, - 66, + 55, + 58, ], - "type": "Punctuator", - "value": "(", + "type": "Identifier", + "value": "one", }, Object { "loc": Object { "end": Object { - "column": 6, + "column": 7, "line": 3, }, "start": Object { - "column": 3, + "column": 5, "line": 3, }, }, "range": Array [ - 66, - 69, + 58, + 60, ], - "type": "Identifier", - "value": "one", + "type": "Punctuator", + "value": "?.", }, Object { "loc": Object { "end": Object { - "column": 8, + "column": 10, "line": 3, }, "start": Object { - "column": 6, + "column": 7, "line": 3, }, }, "range": Array [ - 69, - 71, - ], - "type": "Punctuator", - "value": "?.", - }, - Object { - "loc": Object { - "end": Object { - "column": 11, - "line": 3, - }, - "start": Object { - "column": 8, - "line": 3, - }, - }, - "range": Array [ - 71, - 74, + 60, + 63, ], "type": "Identifier", "value": "two", @@ -87006,35 +86761,35 @@ Object { Object { "loc": Object { "end": Object { - "column": 12, + "column": 11, "line": 3, }, "start": Object { - "column": 11, + "column": 10, "line": 3, }, }, "range": Array [ - 74, - 75, + 63, + 64, ], "type": "Punctuator", - "value": ")", + "value": "!", }, Object { "loc": Object { "end": Object { - "column": 13, + "column": 12, "line": 3, }, "start": Object { - "column": 12, + "column": 11, "line": 3, }, }, "range": Array [ - 75, - 76, + 64, + 65, ], "type": "Punctuator", "value": ".", @@ -87042,35 +86797,35 @@ Object { Object { "loc": Object { "end": Object { - "column": 15, + "column": 17, "line": 3, }, "start": Object { - "column": 13, + "column": 12, "line": 3, }, }, "range": Array [ - 76, - 78, + 65, + 70, ], "type": "Identifier", - "value": "fn", + "value": "three", }, Object { "loc": Object { "end": Object { - "column": 16, + "column": 18, "line": 3, }, "start": Object { - "column": 15, + "column": 17, "line": 3, }, }, "range": Array [ - 78, - 79, + 70, + 71, ], "type": "Punctuator", "value": "(", @@ -87078,17 +86833,17 @@ Object { Object { "loc": Object { "end": Object { - "column": 17, + "column": 19, "line": 3, }, "start": Object { - "column": 16, + "column": 18, "line": 3, }, }, "range": Array [ - 79, - 80, + 71, + 72, ], "type": "Punctuator", "value": ")", @@ -87096,17 +86851,17 @@ Object { Object { "loc": Object { "end": Object { - "column": 18, + "column": 20, "line": 3, }, "start": Object { - "column": 17, + "column": 19, "line": 3, }, }, "range": Array [ - 80, - 81, + 72, + 73, ], "type": "Punctuator", "value": ";", @@ -87123,8 +86878,8 @@ Object { }, }, "range": Array [ - 84, - 85, + 76, + 77, ], "type": "Punctuator", "value": "(", @@ -87141,8 +86896,8 @@ Object { }, }, "range": Array [ - 85, - 88, + 77, + 80, ], "type": "Identifier", "value": "one", @@ -87150,7 +86905,7 @@ Object { Object { "loc": Object { "end": Object { - "column": 7, + "column": 8, "line": 4, }, "start": Object { @@ -87159,26 +86914,26 @@ Object { }, }, "range": Array [ - 88, - 89, + 80, + 82, ], "type": "Punctuator", - "value": ".", + "value": "?.", }, Object { "loc": Object { "end": Object { - "column": 10, + "column": 11, "line": 4, }, "start": Object { - "column": 7, + "column": 8, "line": 4, }, }, "range": Array [ - 89, - 92, + 82, + 85, ], "type": "Identifier", "value": "two", @@ -87190,21 +86945,21 @@ Object { "line": 4, }, "start": Object { - "column": 10, + "column": 11, "line": 4, }, }, "range": Array [ - 92, - 94, + 85, + 86, ], "type": "Punctuator", - "value": "?.", + "value": ")", }, Object { "loc": Object { "end": Object { - "column": 14, + "column": 13, "line": 4, }, "start": Object { @@ -87213,26 +86968,26 @@ Object { }, }, "range": Array [ - 94, - 96, + 86, + 87, ], - "type": "Identifier", - "value": "fn", + "type": "Punctuator", + "value": "!", }, Object { "loc": Object { "end": Object { - "column": 15, + "column": 14, "line": 4, }, "start": Object { - "column": 14, + "column": 13, "line": 4, }, }, "range": Array [ - 96, - 97, + 87, + 88, ], "type": "Punctuator", "value": "(", @@ -87240,35 +86995,17 @@ Object { Object { "loc": Object { "end": Object { - "column": 16, - "line": 4, - }, - "start": Object { "column": 15, "line": 4, }, - }, - "range": Array [ - 97, - 98, - ], - "type": "Punctuator", - "value": ")", - }, - Object { - "loc": Object { - "end": Object { - "column": 17, - "line": 4, - }, "start": Object { - "column": 16, + "column": 14, "line": 4, }, }, "range": Array [ - 98, - 99, + 88, + 89, ], "type": "Punctuator", "value": ")", @@ -87276,17 +87013,17 @@ Object { Object { "loc": Object { "end": Object { - "column": 18, + "column": 16, "line": 4, }, "start": Object { - "column": 17, + "column": 15, "line": 4, }, }, "range": Array [ - 99, - 100, + 89, + 90, ], "type": "Punctuator", "value": ";", @@ -87303,8 +87040,8 @@ Object { }, }, "range": Array [ - 103, - 104, + 93, + 94, ], "type": "Punctuator", "value": "(", @@ -87321,8 +87058,8 @@ Object { }, }, "range": Array [ - 104, - 107, + 94, + 97, ], "type": "Identifier", "value": "one", @@ -87330,7 +87067,7 @@ Object { Object { "loc": Object { "end": Object { - "column": 7, + "column": 8, "line": 5, }, "start": Object { @@ -87339,26 +87076,26 @@ Object { }, }, "range": Array [ - 107, - 108, + 97, + 99, ], "type": "Punctuator", - "value": ".", + "value": "?.", }, Object { "loc": Object { "end": Object { - "column": 10, + "column": 11, "line": 5, }, "start": Object { - "column": 7, + "column": 8, "line": 5, }, }, "range": Array [ - 108, - 111, + 99, + 102, ], "type": "Identifier", "value": "two", @@ -87370,21 +87107,21 @@ Object { "line": 5, }, "start": Object { - "column": 10, + "column": 11, "line": 5, }, }, "range": Array [ - 111, - 113, + 102, + 103, ], "type": "Punctuator", - "value": "?.", + "value": ")", }, Object { "loc": Object { "end": Object { - "column": 17, + "column": 13, "line": 5, }, "start": Object { @@ -87393,44 +87130,26 @@ Object { }, }, "range": Array [ - 113, - 118, - ], - "type": "Identifier", - "value": "three", - }, - Object { - "loc": Object { - "end": Object { - "column": 18, - "line": 5, - }, - "start": Object { - "column": 17, - "line": 5, - }, - }, - "range": Array [ - 118, - 119, + 103, + 104, ], "type": "Punctuator", - "value": ")", + "value": "!", }, Object { "loc": Object { "end": Object { - "column": 19, + "column": 14, "line": 5, }, "start": Object { - "column": 18, + "column": 13, "line": 5, }, }, "range": Array [ - 119, - 120, + 104, + 105, ], "type": "Punctuator", "value": ".", @@ -87438,35 +87157,35 @@ Object { Object { "loc": Object { "end": Object { - "column": 21, + "column": 19, "line": 5, }, "start": Object { - "column": 19, + "column": 14, "line": 5, }, }, "range": Array [ - 120, - 122, + 105, + 110, ], "type": "Identifier", - "value": "fn", + "value": "three", }, Object { "loc": Object { "end": Object { - "column": 22, + "column": 20, "line": 5, }, "start": Object { - "column": 21, + "column": 19, "line": 5, }, }, "range": Array [ - 122, - 123, + 110, + 111, ], "type": "Punctuator", "value": "(", @@ -87474,17 +87193,17 @@ Object { Object { "loc": Object { "end": Object { - "column": 23, + "column": 21, "line": 5, }, "start": Object { - "column": 22, + "column": 20, "line": 5, }, }, "range": Array [ - 123, - 124, + 111, + 112, ], "type": "Punctuator", "value": ")", @@ -87492,17 +87211,17 @@ Object { Object { "loc": Object { "end": Object { - "column": 24, + "column": 22, "line": 5, }, "start": Object { - "column": 23, + "column": 21, "line": 5, }, }, "range": Array [ - 124, - 125, + 112, + 113, ], "type": "Punctuator", "value": ";", @@ -87519,8 +87238,8 @@ Object { }, }, "range": Array [ - 128, - 129, + 116, + 117, ], "type": "Punctuator", "value": "(", @@ -87537,8 +87256,8 @@ Object { }, }, "range": Array [ - 129, - 132, + 117, + 120, ], "type": "Identifier", "value": "one", @@ -87546,7 +87265,7 @@ Object { Object { "loc": Object { "end": Object { - "column": 7, + "column": 8, "line": 6, }, "start": Object { @@ -87555,26 +87274,26 @@ Object { }, }, "range": Array [ - 132, - 133, + 120, + 122, ], "type": "Punctuator", - "value": ".", + "value": "?.", }, Object { "loc": Object { "end": Object { - "column": 10, + "column": 11, "line": 6, }, "start": Object { - "column": 7, + "column": 8, "line": 6, }, }, "range": Array [ - 133, - 136, + 122, + 125, ], "type": "Identifier", "value": "two", @@ -87586,21 +87305,21 @@ Object { "line": 6, }, "start": Object { - "column": 10, + "column": 11, "line": 6, }, }, "range": Array [ - 136, - 138, + 125, + 126, ], "type": "Punctuator", - "value": "?.", + "value": "!", }, Object { "loc": Object { "end": Object { - "column": 17, + "column": 13, "line": 6, }, "start": Object { @@ -87609,62 +87328,26 @@ Object { }, }, "range": Array [ - 138, - 143, - ], - "type": "Identifier", - "value": "three", - }, - Object { - "loc": Object { - "end": Object { - "column": 19, - "line": 6, - }, - "start": Object { - "column": 17, - "line": 6, - }, - }, - "range": Array [ - 143, - 145, + 126, + 127, ], "type": "Punctuator", - "value": "?.", - }, - Object { - "loc": Object { - "end": Object { - "column": 21, - "line": 6, - }, - "start": Object { - "column": 19, - "line": 6, - }, - }, - "range": Array [ - 145, - 147, - ], - "type": "Identifier", - "value": "fn", + "value": ")", }, Object { "loc": Object { "end": Object { - "column": 22, + "column": 14, "line": 6, }, "start": Object { - "column": 21, + "column": 13, "line": 6, }, }, "range": Array [ - 147, - 148, + 127, + 128, ], "type": "Punctuator", "value": "(", @@ -87672,35 +87355,17 @@ Object { Object { "loc": Object { "end": Object { - "column": 23, - "line": 6, - }, - "start": Object { - "column": 22, - "line": 6, - }, - }, - "range": Array [ - 148, - 149, - ], - "type": "Punctuator", - "value": ")", - }, - Object { - "loc": Object { - "end": Object { - "column": 24, + "column": 15, "line": 6, }, "start": Object { - "column": 23, + "column": 14, "line": 6, }, }, "range": Array [ - 149, - 150, + 128, + 129, ], "type": "Punctuator", "value": ")", @@ -87708,17 +87373,17 @@ Object { Object { "loc": Object { "end": Object { - "column": 25, + "column": 16, "line": 6, }, "start": Object { - "column": 24, + "column": 15, "line": 6, }, }, "range": Array [ - 150, - 151, + 129, + 130, ], "type": "Punctuator", "value": ";", @@ -87727,16 +87392,16 @@ Object { "loc": Object { "end": Object { "column": 3, - "line": 8, + "line": 7, }, "start": Object { "column": 2, - "line": 8, + "line": 7, }, }, "range": Array [ - 155, - 156, + 133, + 134, ], "type": "Punctuator", "value": "(", @@ -87745,16 +87410,16 @@ Object { "loc": Object { "end": Object { "column": 6, - "line": 8, + "line": 7, }, "start": Object { "column": 3, - "line": 8, + "line": 7, }, }, "range": Array [ - 156, - 159, + 134, + 137, ], "type": "Identifier", "value": "one", @@ -87763,16 +87428,16 @@ Object { "loc": Object { "end": Object { "column": 8, - "line": 8, + "line": 7, }, "start": Object { "column": 6, - "line": 8, + "line": 7, }, }, "range": Array [ - 159, - 161, + 137, + 139, ], "type": "Punctuator", "value": "?.", @@ -87780,53 +87445,53 @@ Object { Object { "loc": Object { "end": Object { - "column": 9, - "line": 8, + "column": 11, + "line": 7, }, "start": Object { "column": 8, - "line": 8, + "line": 7, }, }, "range": Array [ - 161, - 162, + 139, + 142, ], - "type": "Punctuator", - "value": "(", + "type": "Identifier", + "value": "two", }, Object { "loc": Object { "end": Object { - "column": 10, - "line": 8, + "column": 12, + "line": 7, }, "start": Object { - "column": 9, - "line": 8, + "column": 11, + "line": 7, }, }, "range": Array [ - 162, - 163, + 142, + 143, ], "type": "Punctuator", - "value": ")", + "value": "!", }, Object { "loc": Object { "end": Object { - "column": 11, - "line": 8, + "column": 13, + "line": 7, }, "start": Object { - "column": 10, - "line": 8, + "column": 12, + "line": 7, }, }, "range": Array [ - 163, - 164, + 143, + 144, ], "type": "Punctuator", "value": ")", @@ -87834,615 +87499,201 @@ Object { Object { "loc": Object { "end": Object { - "column": 12, - "line": 8, + "column": 14, + "line": 7, }, "start": Object { - "column": 11, - "line": 8, + "column": 13, + "line": 7, }, }, "range": Array [ - 164, - 165, + 144, + 145, ], "type": "Punctuator", - "value": ";", + "value": ".", }, Object { "loc": Object { "end": Object { - "column": 3, - "line": 9, + "column": 19, + "line": 7, }, "start": Object { - "column": 2, - "line": 9, + "column": 14, + "line": 7, }, }, "range": Array [ - 168, - 169, + 145, + 150, ], - "type": "Punctuator", - "value": "(", + "type": "Identifier", + "value": "three", }, Object { "loc": Object { "end": Object { - "column": 6, - "line": 9, + "column": 20, + "line": 7, }, "start": Object { - "column": 3, - "line": 9, + "column": 19, + "line": 7, }, }, "range": Array [ - 169, - 172, + 150, + 151, ], - "type": "Identifier", - "value": "one", + "type": "Punctuator", + "value": "(", }, Object { "loc": Object { "end": Object { - "column": 8, - "line": 9, + "column": 21, + "line": 7, }, "start": Object { - "column": 6, - "line": 9, + "column": 20, + "line": 7, }, }, "range": Array [ - 172, - 174, + 151, + 152, ], "type": "Punctuator", - "value": "?.", + "value": ")", }, Object { "loc": Object { "end": Object { - "column": 9, - "line": 9, + "column": 22, + "line": 7, }, "start": Object { - "column": 8, - "line": 9, + "column": 21, + "line": 7, }, }, "range": Array [ - 174, - 175, + 152, + 153, ], "type": "Punctuator", - "value": "(", + "value": ";", }, Object { "loc": Object { "end": Object { - "column": 10, - "line": 9, + "column": 1, + "line": 8, }, "start": Object { - "column": 9, - "line": 9, - }, - }, - "range": Array [ - 175, - 176, - ], - "type": "Punctuator", - "value": ")", - }, - Object { - "loc": Object { - "end": Object { - "column": 11, - "line": 9, - }, - "start": Object { - "column": 10, - "line": 9, - }, - }, - "range": Array [ - 176, - 177, - ], - "type": "Punctuator", - "value": ")", - }, - Object { - "loc": Object { - "end": Object { - "column": 12, - "line": 9, - }, - "start": Object { - "column": 11, - "line": 9, - }, - }, - "range": Array [ - 177, - 178, - ], - "type": "Punctuator", - "value": "(", - }, - Object { - "loc": Object { - "end": Object { - "column": 13, - "line": 9, - }, - "start": Object { - "column": 12, - "line": 9, - }, - }, - "range": Array [ - 178, - 179, - ], - "type": "Punctuator", - "value": ")", - }, - Object { - "loc": Object { - "end": Object { - "column": 14, - "line": 9, - }, - "start": Object { - "column": 13, - "line": 9, - }, - }, - "range": Array [ - 179, - 180, - ], - "type": "Punctuator", - "value": ";", - }, - Object { - "loc": Object { - "end": Object { - "column": 3, - "line": 10, - }, - "start": Object { - "column": 2, - "line": 10, - }, - }, - "range": Array [ - 183, - 184, - ], - "type": "Punctuator", - "value": "(", - }, - Object { - "loc": Object { - "end": Object { - "column": 6, - "line": 10, - }, - "start": Object { - "column": 3, - "line": 10, - }, - }, - "range": Array [ - 184, - 187, - ], - "type": "Identifier", - "value": "one", - }, - Object { - "loc": Object { - "end": Object { - "column": 8, - "line": 10, - }, - "start": Object { - "column": 6, - "line": 10, - }, - }, - "range": Array [ - 187, - 189, - ], - "type": "Punctuator", - "value": "?.", - }, - Object { - "loc": Object { - "end": Object { - "column": 9, - "line": 10, - }, - "start": Object { - "column": 8, - "line": 10, - }, - }, - "range": Array [ - 189, - 190, - ], - "type": "Punctuator", - "value": "(", - }, - Object { - "loc": Object { - "end": Object { - "column": 10, - "line": 10, - }, - "start": Object { - "column": 9, - "line": 10, - }, - }, - "range": Array [ - 190, - 191, - ], - "type": "Punctuator", - "value": ")", - }, - Object { - "loc": Object { - "end": Object { - "column": 11, - "line": 10, - }, - "start": Object { - "column": 10, - "line": 10, - }, - }, - "range": Array [ - 191, - 192, - ], - "type": "Punctuator", - "value": ")", - }, - Object { - "loc": Object { - "end": Object { - "column": 13, - "line": 10, - }, - "start": Object { - "column": 11, - "line": 10, - }, - }, - "range": Array [ - 192, - 194, - ], - "type": "Punctuator", - "value": "?.", - }, - Object { - "loc": Object { - "end": Object { - "column": 14, - "line": 10, - }, - "start": Object { - "column": 13, - "line": 10, - }, - }, - "range": Array [ - 194, - 195, - ], - "type": "Punctuator", - "value": "(", - }, - Object { - "loc": Object { - "end": Object { - "column": 15, - "line": 10, - }, - "start": Object { - "column": 14, - "line": 10, + "column": 0, + "line": 8, }, }, "range": Array [ - 195, - 196, + 154, + 155, ], "type": "Punctuator", - "value": ")", + "value": "}", }, - Object { - "loc": Object { - "end": Object { - "column": 16, - "line": 10, - }, - "start": Object { - "column": 15, - "line": 10, - }, - }, - "range": Array [ - 196, - 197, - ], - "type": "Punctuator", - "value": ";", - }, - Object { - "loc": Object { - "end": Object { - "column": 3, - "line": 12, - }, - "start": Object { - "column": 2, - "line": 12, - }, - }, - "range": Array [ - 201, - 202, - ], - "type": "Punctuator", - "value": "(", - }, - Object { - "loc": Object { - "end": Object { - "column": 6, - "line": 12, - }, - "start": Object { - "column": 3, - "line": 12, - }, - }, - "range": Array [ - 202, - 205, - ], - "type": "Identifier", - "value": "one", - }, - Object { - "loc": Object { - "end": Object { - "column": 8, - "line": 12, - }, - "start": Object { - "column": 6, - "line": 12, - }, - }, - "range": Array [ - 205, - 207, - ], - "type": "Punctuator", - "value": "?.", - }, - Object { - "loc": Object { - "end": Object { - "column": 9, - "line": 12, - }, - "start": Object { - "column": 8, - "line": 12, - }, - }, - "range": Array [ - 207, - 208, - ], - "type": "Punctuator", - "value": "(", - }, - Object { - "loc": Object { - "end": Object { - "column": 10, - "line": 12, - }, - "start": Object { - "column": 9, - "line": 12, - }, - }, - "range": Array [ - 208, - 209, - ], - "type": "Punctuator", - "value": ")", - }, - Object { - "loc": Object { - "end": Object { - "column": 11, - "line": 12, - }, - "start": Object { - "column": 10, - "line": 12, - }, - }, - "range": Array [ - 209, - 210, - ], - "type": "Punctuator", - "value": ")", - }, - Object { - "loc": Object { - "end": Object { - "column": 12, - "line": 12, - }, - "start": Object { - "column": 11, - "line": 12, - }, - }, - "range": Array [ - 210, - 211, - ], - "type": "Punctuator", - "value": ".", - }, - Object { - "loc": Object { - "end": Object { - "column": 15, - "line": 12, - }, - "start": Object { - "column": 12, - "line": 12, - }, - }, - "range": Array [ - 211, - 214, - ], - "type": "Identifier", - "value": "two", - }, - Object { - "loc": Object { - "end": Object { - "column": 16, - "line": 12, - }, - "start": Object { - "column": 15, - "line": 12, - }, - }, - "range": Array [ - 214, - 215, - ], - "type": "Punctuator", - "value": ";", - }, - Object { - "loc": Object { - "end": Object { - "column": 1, - "line": 13, - }, - "start": Object { - "column": 0, - "line": 13, - }, - }, - "range": Array [ - 216, - 217, - ], - "type": "Punctuator", - "value": "}", - }, - ], - "type": "Program", -} -`; - -exports[`typescript fixtures/basics/optional-chain-element-access.src 1`] = ` -Object { - "body": Array [ + ], + "type": "Program", +} +`; + +exports[`typescript fixtures/basics/optional-chain-call-with-parens.src 1`] = ` +Object { + "body": Array [ Object { "async": false, "body": Object { "body": Array [ Object { "expression": Object { - "computed": true, - "loc": Object { - "end": Object { - "column": 10, - "line": 2, - }, - "start": Object { - "column": 2, - "line": 2, - }, - }, - "object": Object { + "arguments": Array [], + "callee": Object { + "computed": false, "loc": Object { "end": Object { - "column": 5, + "column": 10, "line": 2, }, "start": Object { - "column": 2, + "column": 3, "line": 2, }, }, - "name": "one", - "range": Array [ - 47, - 50, - ], - "type": "Identifier", - }, - "optional": true, - "property": Object { - "loc": Object { - "end": Object { - "column": 9, - "line": 2, - }, - "start": Object { - "column": 8, - "line": 2, + "object": Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 2, + }, + "start": Object { + "column": 3, + "line": 2, + }, }, + "name": "one", + "range": Array [ + 51, + 54, + ], + "type": "Identifier", + }, + "optional": true, + "property": Object { + "loc": Object { + "end": Object { + "column": 10, + "line": 2, + }, + "start": Object { + "column": 8, + "line": 2, + }, + }, + "name": "fn", + "range": Array [ + 56, + 58, + ], + "type": "Identifier", + }, + "range": Array [ + 51, + 58, + ], + "type": "OptionalMemberExpression", + }, + "loc": Object { + "end": Object { + "column": 12, + "line": 2, + }, + "start": Object { + "column": 3, + "line": 2, }, - "range": Array [ - 53, - 54, - ], - "raw": "2", - "type": "Literal", - "value": 2, }, + "optional": false, "range": Array [ - 47, - 55, + 51, + 60, ], - "type": "OptionalMemberExpression", + "type": "OptionalCallExpression", }, "loc": Object { "end": Object { - "column": 11, + "column": 14, "line": 2, }, "start": Object { @@ -88451,29 +87702,19 @@ Object { }, }, "range": Array [ - 47, - 56, + 50, + 62, ], "type": "ExpressionStatement", }, Object { "expression": Object { - "computed": true, - "loc": Object { - "end": Object { - "column": 13, - "line": 3, - }, - "start": Object { - "column": 2, - "line": 3, - }, - }, - "object": Object { - "computed": true, + "arguments": Array [], + "callee": Object { + "computed": false, "loc": Object { "end": Object { - "column": 10, + "column": 15, "line": 3, }, "start": Object { @@ -88482,78 +87723,105 @@ Object { }, }, "object": Object { + "computed": false, "loc": Object { "end": Object { - "column": 5, + "column": 11, "line": 3, }, "start": Object { - "column": 2, + "column": 3, "line": 3, }, }, - "name": "one", + "object": Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 3, + }, + "start": Object { + "column": 3, + "line": 3, + }, + }, + "name": "one", + "range": Array [ + 66, + 69, + ], + "type": "Identifier", + }, + "optional": true, + "property": Object { + "loc": Object { + "end": Object { + "column": 11, + "line": 3, + }, + "start": Object { + "column": 8, + "line": 3, + }, + }, + "name": "two", + "range": Array [ + 71, + 74, + ], + "type": "Identifier", + }, "range": Array [ - 59, - 62, + 66, + 74, ], - "type": "Identifier", + "type": "OptionalMemberExpression", }, - "optional": true, + "optional": false, "property": Object { "loc": Object { "end": Object { - "column": 9, + "column": 15, "line": 3, }, "start": Object { - "column": 8, + "column": 13, "line": 3, }, }, + "name": "fn", "range": Array [ - 65, - 66, + 76, + 78, ], - "raw": "2", - "type": "Literal", - "value": 2, + "type": "Identifier", }, "range": Array [ - 59, - 67, + 65, + 78, ], - "type": "OptionalMemberExpression", + "type": "MemberExpression", }, - "optional": false, - "property": Object { - "loc": Object { - "end": Object { - "column": 12, - "line": 3, - }, - "start": Object { - "column": 11, - "line": 3, - }, + "loc": Object { + "end": Object { + "column": 17, + "line": 3, + }, + "start": Object { + "column": 2, + "line": 3, }, - "range": Array [ - 68, - 69, - ], - "raw": "3", - "type": "Literal", - "value": 3, }, + "optional": false, "range": Array [ - 59, - 70, + 65, + 80, ], - "type": "OptionalMemberExpression", + "type": "CallExpression", }, "loc": Object { "end": Object { - "column": 14, + "column": 18, "line": 3, }, "start": Object { @@ -88562,109 +87830,126 @@ Object { }, }, "range": Array [ - 59, - 71, + 65, + 81, ], "type": "ExpressionStatement", }, Object { "expression": Object { - "computed": true, - "loc": Object { - "end": Object { - "column": 13, - "line": 4, - }, - "start": Object { - "column": 2, - "line": 4, - }, - }, - "object": Object { - "computed": true, + "arguments": Array [], + "callee": Object { + "computed": false, "loc": Object { "end": Object { - "column": 8, + "column": 14, "line": 4, }, "start": Object { - "column": 2, + "column": 3, "line": 4, }, }, "object": Object { + "computed": false, "loc": Object { "end": Object { - "column": 5, + "column": 10, "line": 4, }, "start": Object { - "column": 2, + "column": 3, "line": 4, }, }, - "name": "one", + "object": Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 4, + }, + "start": Object { + "column": 3, + "line": 4, + }, + }, + "name": "one", + "range": Array [ + 85, + 88, + ], + "type": "Identifier", + }, + "optional": false, + "property": Object { + "loc": Object { + "end": Object { + "column": 10, + "line": 4, + }, + "start": Object { + "column": 7, + "line": 4, + }, + }, + "name": "two", + "range": Array [ + 89, + 92, + ], + "type": "Identifier", + }, "range": Array [ - 74, - 77, + 85, + 92, ], - "type": "Identifier", + "type": "MemberExpression", }, - "optional": false, + "optional": true, "property": Object { "loc": Object { "end": Object { - "column": 7, + "column": 14, "line": 4, }, "start": Object { - "column": 6, + "column": 12, "line": 4, }, }, + "name": "fn", "range": Array [ - 78, - 79, - ], - "raw": "2", - "type": "Literal", - "value": 2, + 94, + 96, + ], + "type": "Identifier", }, "range": Array [ - 74, - 80, + 85, + 96, ], - "type": "MemberExpression", + "type": "OptionalMemberExpression", }, - "optional": true, - "property": Object { - "loc": Object { - "end": Object { - "column": 12, - "line": 4, - }, - "start": Object { - "column": 11, - "line": 4, - }, + "loc": Object { + "end": Object { + "column": 16, + "line": 4, + }, + "start": Object { + "column": 3, + "line": 4, }, - "range": Array [ - 83, - 84, - ], - "raw": "3", - "type": "Literal", - "value": 3, }, + "optional": false, "range": Array [ - 74, 85, + 98, ], - "type": "OptionalMemberExpression", + "type": "OptionalCallExpression", }, "loc": Object { "end": Object { - "column": 14, + "column": 18, "line": 4, }, "start": Object { @@ -88673,29 +87958,19 @@ Object { }, }, "range": Array [ - 74, - 86, + 84, + 100, ], "type": "ExpressionStatement", }, Object { "expression": Object { - "computed": true, - "loc": Object { - "end": Object { - "column": 13, - "line": 5, - }, - "start": Object { - "column": 2, - "line": 5, - }, - }, - "object": Object { - "computed": true, + "arguments": Array [], + "callee": Object { + "computed": false, "loc": Object { "end": Object { - "column": 8, + "column": 21, "line": 5, }, "start": Object { @@ -88704,78 +87979,142 @@ Object { }, }, "object": Object { + "computed": false, "loc": Object { "end": Object { - "column": 5, + "column": 17, "line": 5, }, "start": Object { - "column": 2, + "column": 3, "line": 5, }, }, - "name": "one", + "object": Object { + "computed": false, + "loc": Object { + "end": Object { + "column": 10, + "line": 5, + }, + "start": Object { + "column": 3, + "line": 5, + }, + }, + "object": Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 5, + }, + "start": Object { + "column": 3, + "line": 5, + }, + }, + "name": "one", + "range": Array [ + 104, + 107, + ], + "type": "Identifier", + }, + "optional": false, + "property": Object { + "loc": Object { + "end": Object { + "column": 10, + "line": 5, + }, + "start": Object { + "column": 7, + "line": 5, + }, + }, + "name": "two", + "range": Array [ + 108, + 111, + ], + "type": "Identifier", + }, + "range": Array [ + 104, + 111, + ], + "type": "MemberExpression", + }, + "optional": true, + "property": Object { + "loc": Object { + "end": Object { + "column": 17, + "line": 5, + }, + "start": Object { + "column": 12, + "line": 5, + }, + }, + "name": "three", + "range": Array [ + 113, + 118, + ], + "type": "Identifier", + }, "range": Array [ - 89, - 92, + 104, + 118, ], - "type": "Identifier", + "type": "OptionalMemberExpression", }, "optional": false, "property": Object { "loc": Object { "end": Object { - "column": 7, + "column": 21, "line": 5, }, "start": Object { - "column": 6, + "column": 19, "line": 5, }, }, + "name": "fn", "range": Array [ - 93, - 94, + 120, + 122, ], - "raw": "2", - "type": "Literal", - "value": 2, + "type": "Identifier", }, "range": Array [ - 89, - 95, + 103, + 122, ], "type": "MemberExpression", }, - "optional": true, - "property": Object { - "loc": Object { - "end": Object { - "column": 12, - "line": 5, - }, - "start": Object { - "column": 11, - "line": 5, - }, + "loc": Object { + "end": Object { + "column": 23, + "line": 5, + }, + "start": Object { + "column": 2, + "line": 5, }, - "range": Array [ - 98, - 99, - ], - "raw": "3", - "type": "Literal", - "value": 3, }, + "optional": false, "range": Array [ - 89, - 100, + 103, + 124, ], - "type": "OptionalMemberExpression", + "type": "CallExpression", }, "loc": Object { "end": Object { - "column": 14, + "column": 24, "line": 5, }, "start": Object { @@ -88784,147 +88123,163 @@ Object { }, }, "range": Array [ - 89, - 101, + 103, + 125, ], "type": "ExpressionStatement", }, Object { "expression": Object { - "computed": true, - "loc": Object { - "end": Object { - "column": 16, - "line": 6, - }, - "start": Object { - "column": 2, - "line": 6, - }, - }, - "object": Object { - "computed": true, + "arguments": Array [], + "callee": Object { + "computed": false, "loc": Object { "end": Object { - "column": 13, + "column": 21, "line": 6, }, "start": Object { - "column": 2, + "column": 3, "line": 6, }, }, "object": Object { - "computed": true, + "computed": false, "loc": Object { "end": Object { - "column": 8, + "column": 17, "line": 6, }, "start": Object { - "column": 2, + "column": 3, "line": 6, }, }, "object": Object { + "computed": false, "loc": Object { "end": Object { - "column": 5, + "column": 10, "line": 6, }, "start": Object { - "column": 2, + "column": 3, "line": 6, }, }, - "name": "one", - "range": Array [ - 104, - 107, - ], - "type": "Identifier", - }, - "optional": false, - "property": Object { - "loc": Object { - "end": Object { - "column": 7, - "line": 6, - }, - "start": Object { - "column": 6, + "object": Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 6, + }, + "start": Object { + "column": 3, + "line": 6, + }, + }, + "name": "one", + "range": Array [ + 129, + 132, + ], + "type": "Identifier", + }, + "optional": false, + "property": Object { + "loc": Object { + "end": Object { + "column": 10, + "line": 6, + }, + "start": Object { + "column": 7, + "line": 6, + }, + }, + "name": "two", + "range": Array [ + 133, + 136, + ], + "type": "Identifier", + }, + "range": Array [ + 129, + 136, + ], + "type": "MemberExpression", + }, + "optional": true, + "property": Object { + "loc": Object { + "end": Object { + "column": 17, + "line": 6, + }, + "start": Object { + "column": 12, "line": 6, }, }, + "name": "three", "range": Array [ - 108, - 109, + 138, + 143, ], - "raw": "2", - "type": "Literal", - "value": 2, + "type": "Identifier", }, "range": Array [ - 104, - 110, + 129, + 143, ], - "type": "MemberExpression", + "type": "OptionalMemberExpression", }, "optional": true, "property": Object { "loc": Object { "end": Object { - "column": 12, + "column": 21, "line": 6, }, "start": Object { - "column": 11, + "column": 19, "line": 6, }, }, + "name": "fn", "range": Array [ - 113, - 114, + 145, + 147, ], - "raw": "3", - "type": "Literal", - "value": 3, + "type": "Identifier", }, "range": Array [ - 104, - 115, + 129, + 147, ], "type": "OptionalMemberExpression", }, - "optional": false, - "property": Object { - "loc": Object { - "end": Object { - "column": 15, - "line": 6, - }, - "start": Object { - "column": 14, - "line": 6, - }, + "loc": Object { + "end": Object { + "column": 23, + "line": 6, + }, + "start": Object { + "column": 3, + "line": 6, }, - "range": Array [ - 116, - 117, - ], - "raw": "4", - "type": "Literal", - "value": 4, }, + "optional": false, "range": Array [ - 104, - 118, + 129, + 149, ], - "type": "OptionalMemberExpression", + "type": "OptionalCallExpression", }, "loc": Object { "end": Object { - "column": 17, + "column": 25, "line": 6, }, "start": Object { @@ -88933,157 +88288,299 @@ Object { }, }, "range": Array [ - 104, - 119, + 128, + 151, ], "type": "ExpressionStatement", }, Object { "expression": Object { - "computed": true, - "loc": Object { - "end": Object { - "column": 18, - "line": 7, - }, - "start": Object { - "column": 2, - "line": 7, - }, - }, - "object": Object { - "computed": true, + "arguments": Array [], + "callee": Object { "loc": Object { "end": Object { - "column": 13, - "line": 7, + "column": 6, + "line": 8, }, "start": Object { - "column": 2, - "line": 7, + "column": 3, + "line": 8, }, }, - "object": Object { - "computed": true, + "name": "one", + "range": Array [ + 156, + 159, + ], + "type": "Identifier", + }, + "loc": Object { + "end": Object { + "column": 10, + "line": 8, + }, + "start": Object { + "column": 3, + "line": 8, + }, + }, + "optional": true, + "range": Array [ + 156, + 163, + ], + "type": "OptionalCallExpression", + }, + "loc": Object { + "end": Object { + "column": 12, + "line": 8, + }, + "start": Object { + "column": 2, + "line": 8, + }, + }, + "range": Array [ + 155, + 165, + ], + "type": "ExpressionStatement", + }, + Object { + "expression": Object { + "arguments": Array [], + "callee": Object { + "arguments": Array [], + "callee": Object { "loc": Object { "end": Object { - "column": 8, - "line": 7, + "column": 6, + "line": 9, }, "start": Object { - "column": 2, - "line": 7, - }, - }, - "object": Object { - "loc": Object { - "end": Object { - "column": 5, - "line": 7, - }, - "start": Object { - "column": 2, - "line": 7, - }, - }, - "name": "one", - "range": Array [ - 122, - 125, - ], - "type": "Identifier", - }, - "optional": false, - "property": Object { - "loc": Object { - "end": Object { - "column": 7, - "line": 7, - }, - "start": Object { - "column": 6, - "line": 7, - }, + "column": 3, + "line": 9, }, - "range": Array [ - 126, - 127, - ], - "raw": "2", - "type": "Literal", - "value": 2, }, + "name": "one", "range": Array [ - 122, - 128, + 169, + 172, ], - "type": "MemberExpression", + "type": "Identifier", }, - "optional": true, - "property": Object { - "loc": Object { - "end": Object { - "column": 12, - "line": 7, - }, - "start": Object { - "column": 11, - "line": 7, + "loc": Object { + "end": Object { + "column": 10, + "line": 9, + }, + "start": Object { + "column": 3, + "line": 9, + }, + }, + "optional": true, + "range": Array [ + 169, + 176, + ], + "type": "OptionalCallExpression", + }, + "loc": Object { + "end": Object { + "column": 13, + "line": 9, + }, + "start": Object { + "column": 2, + "line": 9, + }, + }, + "optional": false, + "range": Array [ + 168, + 179, + ], + "type": "CallExpression", + }, + "loc": Object { + "end": Object { + "column": 14, + "line": 9, + }, + "start": Object { + "column": 2, + "line": 9, + }, + }, + "range": Array [ + 168, + 180, + ], + "type": "ExpressionStatement", + }, + Object { + "expression": Object { + "arguments": Array [], + "callee": Object { + "arguments": Array [], + "callee": Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 10, + }, + "start": Object { + "column": 3, + "line": 10, }, }, + "name": "one", "range": Array [ - 131, - 132, + 184, + 187, ], - "raw": "3", - "type": "Literal", - "value": 3, + "type": "Identifier", + }, + "loc": Object { + "end": Object { + "column": 10, + "line": 10, + }, + "start": Object { + "column": 3, + "line": 10, + }, }, + "optional": true, "range": Array [ - 122, - 133, + 184, + 191, ], - "type": "OptionalMemberExpression", + "type": "OptionalCallExpression", + }, + "loc": Object { + "end": Object { + "column": 15, + "line": 10, + }, + "start": Object { + "column": 2, + "line": 10, + }, }, "optional": true, + "range": Array [ + 183, + 196, + ], + "type": "OptionalCallExpression", + }, + "loc": Object { + "end": Object { + "column": 16, + "line": 10, + }, + "start": Object { + "column": 2, + "line": 10, + }, + }, + "range": Array [ + 183, + 197, + ], + "type": "ExpressionStatement", + }, + Object { + "expression": Object { + "computed": false, + "loc": Object { + "end": Object { + "column": 15, + "line": 12, + }, + "start": Object { + "column": 2, + "line": 12, + }, + }, + "object": Object { + "arguments": Array [], + "callee": Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 12, + }, + "start": Object { + "column": 3, + "line": 12, + }, + }, + "name": "one", + "range": Array [ + 202, + 205, + ], + "type": "Identifier", + }, + "loc": Object { + "end": Object { + "column": 10, + "line": 12, + }, + "start": Object { + "column": 3, + "line": 12, + }, + }, + "optional": true, + "range": Array [ + 202, + 209, + ], + "type": "OptionalCallExpression", + }, + "optional": false, "property": Object { "loc": Object { "end": Object { - "column": 17, - "line": 7, + "column": 15, + "line": 12, }, "start": Object { - "column": 16, - "line": 7, + "column": 12, + "line": 12, }, }, + "name": "two", "range": Array [ - 136, - 137, + 211, + 214, ], - "raw": "4", - "type": "Literal", - "value": 4, + "type": "Identifier", }, "range": Array [ - 122, - 138, + 201, + 214, ], - "type": "OptionalMemberExpression", + "type": "MemberExpression", }, "loc": Object { "end": Object { - "column": 19, - "line": 7, + "column": 16, + "line": 12, }, "start": Object { "column": 2, - "line": 7, + "line": 12, }, }, "range": Array [ - 122, - 139, + 201, + 215, ], "type": "ExpressionStatement", }, @@ -89091,16 +88588,16 @@ Object { "loc": Object { "end": Object { "column": 1, - "line": 8, + "line": 13, }, "start": Object { - "column": 43, + "column": 46, "line": 1, }, }, "range": Array [ - 43, - 141, + 46, + 217, ], "type": "BlockStatement", }, @@ -89109,7 +88606,7 @@ Object { "id": Object { "loc": Object { "end": Object { - "column": 31, + "column": 34, "line": 1, }, "start": Object { @@ -89117,17 +88614,17 @@ Object { "line": 1, }, }, - "name": "processOptionalElement", + "name": "processOptionalCallParens", "range": Array [ 9, - 31, + 34, ], "type": "Identifier", }, "loc": Object { "end": Object { "column": 1, - "line": 8, + "line": 13, }, "start": Object { "column": 0, @@ -89138,51 +88635,51 @@ Object { Object { "loc": Object { "end": Object { - "column": 41, + "column": 44, "line": 1, }, "start": Object { - "column": 32, + "column": 35, "line": 1, }, }, "name": "one", "optional": true, "range": Array [ - 32, - 41, + 35, + 44, ], "type": "Identifier", "typeAnnotation": Object { "loc": Object { "end": Object { - "column": 41, + "column": 44, "line": 1, }, "start": Object { - "column": 36, + "column": 39, "line": 1, }, }, "range": Array [ - 36, - 41, + 39, + 44, ], "type": "TSTypeAnnotation", "typeAnnotation": Object { "loc": Object { "end": Object { - "column": 41, + "column": 44, "line": 1, }, "start": Object { - "column": 38, + "column": 41, "line": 1, }, }, "range": Array [ - 38, 41, + 44, ], "type": "TSAnyKeyword", }, @@ -89191,7 +88688,7 @@ Object { ], "range": Array [ 0, - 141, + 217, ], "type": "FunctionDeclaration", }, @@ -89199,7 +88696,7 @@ Object { "loc": Object { "end": Object { "column": 0, - "line": 9, + "line": 14, }, "start": Object { "column": 0, @@ -89208,7 +88705,7 @@ Object { }, "range": Array [ 0, - 142, + 218, ], "sourceType": "script", "tokens": Array [ @@ -89233,7 +88730,7 @@ Object { Object { "loc": Object { "end": Object { - "column": 31, + "column": 34, "line": 1, }, "start": Object { @@ -89243,25 +88740,25 @@ Object { }, "range": Array [ 9, - 31, + 34, ], "type": "Identifier", - "value": "processOptionalElement", + "value": "processOptionalCallParens", }, Object { "loc": Object { "end": Object { - "column": 32, + "column": 35, "line": 1, }, "start": Object { - "column": 31, + "column": 34, "line": 1, }, }, "range": Array [ - 31, - 32, + 34, + 35, ], "type": "Punctuator", "value": "(", @@ -89269,17 +88766,17 @@ Object { Object { "loc": Object { "end": Object { - "column": 35, + "column": 38, "line": 1, }, "start": Object { - "column": 32, + "column": 35, "line": 1, }, }, "range": Array [ - 32, 35, + 38, ], "type": "Identifier", "value": "one", @@ -89287,17 +88784,17 @@ Object { Object { "loc": Object { "end": Object { - "column": 36, + "column": 39, "line": 1, }, "start": Object { - "column": 35, + "column": 38, "line": 1, }, }, "range": Array [ - 35, - 36, + 38, + 39, ], "type": "Punctuator", "value": "?", @@ -89305,17 +88802,17 @@ Object { Object { "loc": Object { "end": Object { - "column": 37, + "column": 40, "line": 1, }, "start": Object { - "column": 36, + "column": 39, "line": 1, }, }, "range": Array [ - 36, - 37, + 39, + 40, ], "type": "Punctuator", "value": ":", @@ -89323,17 +88820,17 @@ Object { Object { "loc": Object { "end": Object { - "column": 41, + "column": 44, "line": 1, }, "start": Object { - "column": 38, + "column": 41, "line": 1, }, }, "range": Array [ - 38, 41, + 44, ], "type": "Identifier", "value": "any", @@ -89341,17 +88838,17 @@ Object { Object { "loc": Object { "end": Object { - "column": 42, + "column": 45, "line": 1, }, "start": Object { - "column": 41, + "column": 44, "line": 1, }, }, "range": Array [ - 41, - 42, + 44, + 45, ], "type": "Punctuator", "value": ")", @@ -89359,17 +88856,17 @@ Object { Object { "loc": Object { "end": Object { - "column": 44, + "column": 47, "line": 1, }, "start": Object { - "column": 43, + "column": 46, "line": 1, }, }, "range": Array [ - 43, - 44, + 46, + 47, ], "type": "Punctuator", "value": "{", @@ -89377,7 +88874,7 @@ Object { Object { "loc": Object { "end": Object { - "column": 5, + "column": 3, "line": 2, }, "start": Object { @@ -89386,29 +88883,29 @@ Object { }, }, "range": Array [ - 47, 50, + 51, ], - "type": "Identifier", - "value": "one", + "type": "Punctuator", + "value": "(", }, Object { "loc": Object { "end": Object { - "column": 7, + "column": 6, "line": 2, }, "start": Object { - "column": 5, + "column": 3, "line": 2, }, }, "range": Array [ - 50, - 52, + 51, + 54, ], - "type": "Punctuator", - "value": "?.", + "type": "Identifier", + "value": "one", }, Object { "loc": Object { @@ -89417,21 +88914,21 @@ Object { "line": 2, }, "start": Object { - "column": 7, + "column": 6, "line": 2, }, }, "range": Array [ - 52, - 53, + 54, + 56, ], "type": "Punctuator", - "value": "[", + "value": "?.", }, Object { "loc": Object { "end": Object { - "column": 9, + "column": 10, "line": 2, }, "start": Object { @@ -89440,137 +88937,137 @@ Object { }, }, "range": Array [ - 53, - 54, + 56, + 58, ], - "type": "Numeric", - "value": "2", + "type": "Identifier", + "value": "fn", }, Object { "loc": Object { "end": Object { - "column": 10, + "column": 11, "line": 2, }, "start": Object { - "column": 9, + "column": 10, "line": 2, }, }, "range": Array [ - 54, - 55, + 58, + 59, ], "type": "Punctuator", - "value": "]", + "value": "(", }, Object { "loc": Object { "end": Object { - "column": 11, + "column": 12, "line": 2, }, "start": Object { - "column": 10, + "column": 11, "line": 2, }, }, "range": Array [ - 55, - 56, + 59, + 60, ], "type": "Punctuator", - "value": ";", + "value": ")", }, Object { "loc": Object { "end": Object { - "column": 5, - "line": 3, + "column": 13, + "line": 2, }, "start": Object { - "column": 2, - "line": 3, + "column": 12, + "line": 2, }, }, "range": Array [ - 59, - 62, + 60, + 61, ], - "type": "Identifier", - "value": "one", + "type": "Punctuator", + "value": ")", }, Object { "loc": Object { "end": Object { - "column": 7, - "line": 3, + "column": 14, + "line": 2, }, "start": Object { - "column": 5, - "line": 3, + "column": 13, + "line": 2, }, }, "range": Array [ + 61, 62, - 64, ], "type": "Punctuator", - "value": "?.", + "value": ";", }, Object { "loc": Object { "end": Object { - "column": 8, + "column": 3, "line": 3, }, "start": Object { - "column": 7, + "column": 2, "line": 3, }, }, "range": Array [ - 64, 65, + 66, ], "type": "Punctuator", - "value": "[", + "value": "(", }, Object { "loc": Object { "end": Object { - "column": 9, + "column": 6, "line": 3, }, "start": Object { - "column": 8, + "column": 3, "line": 3, }, }, "range": Array [ - 65, 66, + 69, ], - "type": "Numeric", - "value": "2", + "type": "Identifier", + "value": "one", }, Object { "loc": Object { "end": Object { - "column": 10, + "column": 8, "line": 3, }, "start": Object { - "column": 9, + "column": 6, "line": 3, }, }, "range": Array [ - 66, - 67, + 69, + 71, ], "type": "Punctuator", - "value": "]", + "value": "?.", }, Object { "loc": Object { @@ -89579,16 +89076,16 @@ Object { "line": 3, }, "start": Object { - "column": 10, + "column": 8, "line": 3, }, }, "range": Array [ - 67, - 68, + 71, + 74, ], - "type": "Punctuator", - "value": "[", + "type": "Identifier", + "value": "two", }, Object { "loc": Object { @@ -89602,11 +89099,11 @@ Object { }, }, "range": Array [ - 68, - 69, + 74, + 75, ], - "type": "Numeric", - "value": "3", + "type": "Punctuator", + "value": ")", }, Object { "loc": Object { @@ -89620,16 +89117,16 @@ Object { }, }, "range": Array [ - 69, - 70, + 75, + 76, ], "type": "Punctuator", - "value": "]", + "value": ".", }, Object { "loc": Object { "end": Object { - "column": 14, + "column": 15, "line": 3, }, "start": Object { @@ -89638,155 +89135,155 @@ Object { }, }, "range": Array [ - 70, - 71, + 76, + 78, ], - "type": "Punctuator", - "value": ";", + "type": "Identifier", + "value": "fn", }, Object { "loc": Object { "end": Object { - "column": 5, - "line": 4, + "column": 16, + "line": 3, }, "start": Object { - "column": 2, - "line": 4, + "column": 15, + "line": 3, }, }, "range": Array [ - 74, - 77, + 78, + 79, ], - "type": "Identifier", - "value": "one", + "type": "Punctuator", + "value": "(", }, Object { "loc": Object { "end": Object { - "column": 6, - "line": 4, + "column": 17, + "line": 3, }, "start": Object { - "column": 5, - "line": 4, + "column": 16, + "line": 3, }, }, "range": Array [ - 77, - 78, + 79, + 80, ], "type": "Punctuator", - "value": "[", + "value": ")", }, Object { "loc": Object { "end": Object { - "column": 7, - "line": 4, + "column": 18, + "line": 3, }, "start": Object { - "column": 6, - "line": 4, + "column": 17, + "line": 3, }, }, "range": Array [ - 78, - 79, + 80, + 81, ], - "type": "Numeric", - "value": "2", + "type": "Punctuator", + "value": ";", }, Object { "loc": Object { "end": Object { - "column": 8, + "column": 3, "line": 4, }, "start": Object { - "column": 7, + "column": 2, "line": 4, }, }, "range": Array [ - 79, - 80, + 84, + 85, ], "type": "Punctuator", - "value": "]", + "value": "(", }, Object { "loc": Object { "end": Object { - "column": 10, + "column": 6, "line": 4, }, "start": Object { - "column": 8, + "column": 3, "line": 4, }, }, "range": Array [ - 80, - 82, + 85, + 88, ], - "type": "Punctuator", - "value": "?.", + "type": "Identifier", + "value": "one", }, Object { "loc": Object { "end": Object { - "column": 11, + "column": 7, "line": 4, }, "start": Object { - "column": 10, + "column": 6, "line": 4, }, }, "range": Array [ - 82, - 83, + 88, + 89, ], "type": "Punctuator", - "value": "[", + "value": ".", }, Object { "loc": Object { "end": Object { - "column": 12, + "column": 10, "line": 4, }, "start": Object { - "column": 11, + "column": 7, "line": 4, }, }, "range": Array [ - 83, - 84, + 89, + 92, ], - "type": "Numeric", - "value": "3", + "type": "Identifier", + "value": "two", }, Object { "loc": Object { "end": Object { - "column": 13, + "column": 12, "line": 4, }, "start": Object { - "column": 12, + "column": 10, "line": 4, }, }, "range": Array [ - 84, - 85, + 92, + 94, ], "type": "Punctuator", - "value": "]", + "value": "?.", }, Object { "loc": Object { @@ -89795,884 +89292,5612 @@ Object { "line": 4, }, "start": Object { - "column": 13, + "column": 12, "line": 4, }, }, "range": Array [ - 85, - 86, + 94, + 96, ], - "type": "Punctuator", - "value": ";", + "type": "Identifier", + "value": "fn", }, Object { "loc": Object { "end": Object { - "column": 5, - "line": 5, + "column": 15, + "line": 4, }, "start": Object { - "column": 2, - "line": 5, + "column": 14, + "line": 4, }, }, "range": Array [ - 89, - 92, + 96, + 97, ], - "type": "Identifier", - "value": "one", + "type": "Punctuator", + "value": "(", }, Object { "loc": Object { "end": Object { - "column": 6, - "line": 5, + "column": 16, + "line": 4, }, "start": Object { - "column": 5, - "line": 5, + "column": 15, + "line": 4, }, }, "range": Array [ - 92, - 93, + 97, + 98, ], "type": "Punctuator", - "value": "[", + "value": ")", }, Object { "loc": Object { "end": Object { - "column": 7, - "line": 5, + "column": 17, + "line": 4, }, "start": Object { - "column": 6, - "line": 5, + "column": 16, + "line": 4, }, }, "range": Array [ - 93, - 94, + 98, + 99, ], - "type": "Numeric", - "value": "2", + "type": "Punctuator", + "value": ")", }, Object { "loc": Object { "end": Object { - "column": 8, - "line": 5, + "column": 18, + "line": 4, }, "start": Object { - "column": 7, - "line": 5, + "column": 17, + "line": 4, }, }, "range": Array [ - 94, - 95, + 99, + 100, ], "type": "Punctuator", - "value": "]", + "value": ";", }, Object { "loc": Object { "end": Object { - "column": 10, + "column": 3, "line": 5, }, "start": Object { - "column": 8, + "column": 2, "line": 5, }, }, "range": Array [ - 95, - 97, + 103, + 104, ], "type": "Punctuator", - "value": "?.", + "value": "(", }, Object { "loc": Object { "end": Object { - "column": 11, + "column": 6, "line": 5, }, "start": Object { - "column": 10, + "column": 3, "line": 5, }, }, "range": Array [ - 97, - 98, + 104, + 107, ], - "type": "Punctuator", - "value": "[", + "type": "Identifier", + "value": "one", }, Object { "loc": Object { "end": Object { - "column": 12, + "column": 7, "line": 5, }, "start": Object { - "column": 11, + "column": 6, "line": 5, }, }, "range": Array [ - 98, - 99, + 107, + 108, ], - "type": "Numeric", - "value": "3", + "type": "Punctuator", + "value": ".", }, Object { "loc": Object { "end": Object { - "column": 13, + "column": 10, "line": 5, }, "start": Object { - "column": 12, + "column": 7, "line": 5, }, }, "range": Array [ - 99, - 100, + 108, + 111, ], - "type": "Punctuator", - "value": "]", + "type": "Identifier", + "value": "two", }, Object { "loc": Object { "end": Object { - "column": 14, + "column": 12, "line": 5, }, "start": Object { - "column": 13, + "column": 10, "line": 5, }, }, "range": Array [ - 100, - 101, + 111, + 113, ], "type": "Punctuator", - "value": ";", + "value": "?.", }, Object { "loc": Object { "end": Object { - "column": 5, - "line": 6, + "column": 17, + "line": 5, }, "start": Object { - "column": 2, - "line": 6, + "column": 12, + "line": 5, }, }, "range": Array [ - 104, - 107, + 113, + 118, ], "type": "Identifier", - "value": "one", + "value": "three", }, Object { "loc": Object { "end": Object { - "column": 6, - "line": 6, + "column": 18, + "line": 5, }, "start": Object { - "column": 5, - "line": 6, + "column": 17, + "line": 5, }, }, "range": Array [ - 107, - 108, + 118, + 119, ], "type": "Punctuator", - "value": "[", + "value": ")", }, Object { "loc": Object { "end": Object { - "column": 7, - "line": 6, + "column": 19, + "line": 5, }, "start": Object { - "column": 6, - "line": 6, + "column": 18, + "line": 5, }, }, "range": Array [ - 108, - 109, + 119, + 120, ], - "type": "Numeric", - "value": "2", + "type": "Punctuator", + "value": ".", }, Object { "loc": Object { "end": Object { - "column": 8, - "line": 6, + "column": 21, + "line": 5, }, "start": Object { - "column": 7, - "line": 6, + "column": 19, + "line": 5, }, }, "range": Array [ - 109, - 110, + 120, + 122, ], - "type": "Punctuator", - "value": "]", + "type": "Identifier", + "value": "fn", }, Object { "loc": Object { "end": Object { - "column": 10, - "line": 6, + "column": 22, + "line": 5, }, "start": Object { - "column": 8, - "line": 6, + "column": 21, + "line": 5, }, }, "range": Array [ - 110, - 112, + 122, + 123, ], "type": "Punctuator", - "value": "?.", + "value": "(", }, Object { "loc": Object { "end": Object { - "column": 11, - "line": 6, + "column": 23, + "line": 5, }, "start": Object { - "column": 10, - "line": 6, + "column": 22, + "line": 5, }, }, "range": Array [ - 112, - 113, + 123, + 124, ], "type": "Punctuator", - "value": "[", + "value": ")", }, Object { "loc": Object { "end": Object { - "column": 12, - "line": 6, + "column": 24, + "line": 5, }, "start": Object { - "column": 11, - "line": 6, + "column": 23, + "line": 5, }, }, "range": Array [ - 113, - 114, + 124, + 125, ], - "type": "Numeric", - "value": "3", + "type": "Punctuator", + "value": ";", }, Object { "loc": Object { "end": Object { - "column": 13, + "column": 3, "line": 6, }, "start": Object { - "column": 12, + "column": 2, "line": 6, }, }, "range": Array [ - 114, - 115, + 128, + 129, ], "type": "Punctuator", - "value": "]", + "value": "(", }, Object { "loc": Object { "end": Object { - "column": 14, + "column": 6, "line": 6, }, "start": Object { - "column": 13, + "column": 3, "line": 6, }, }, "range": Array [ - 115, - 116, + 129, + 132, ], - "type": "Punctuator", - "value": "[", + "type": "Identifier", + "value": "one", }, Object { "loc": Object { "end": Object { - "column": 15, + "column": 7, "line": 6, }, "start": Object { - "column": 14, + "column": 6, "line": 6, }, }, "range": Array [ - 116, - 117, + 132, + 133, ], - "type": "Numeric", - "value": "4", + "type": "Punctuator", + "value": ".", }, Object { "loc": Object { "end": Object { - "column": 16, + "column": 10, "line": 6, }, "start": Object { - "column": 15, + "column": 7, "line": 6, }, }, "range": Array [ - 117, - 118, + 133, + 136, ], - "type": "Punctuator", - "value": "]", + "type": "Identifier", + "value": "two", }, Object { "loc": Object { "end": Object { - "column": 17, + "column": 12, "line": 6, }, "start": Object { - "column": 16, + "column": 10, "line": 6, }, }, "range": Array [ - 118, - 119, + 136, + 138, ], "type": "Punctuator", - "value": ";", + "value": "?.", }, Object { "loc": Object { "end": Object { - "column": 5, - "line": 7, + "column": 17, + "line": 6, }, "start": Object { - "column": 2, - "line": 7, + "column": 12, + "line": 6, }, }, "range": Array [ - 122, - 125, + 138, + 143, ], "type": "Identifier", - "value": "one", + "value": "three", }, Object { "loc": Object { "end": Object { - "column": 6, - "line": 7, + "column": 19, + "line": 6, }, "start": Object { - "column": 5, - "line": 7, + "column": 17, + "line": 6, }, }, "range": Array [ - 125, - 126, + 143, + 145, ], "type": "Punctuator", - "value": "[", + "value": "?.", }, Object { "loc": Object { "end": Object { - "column": 7, - "line": 7, + "column": 21, + "line": 6, }, "start": Object { - "column": 6, - "line": 7, + "column": 19, + "line": 6, }, }, "range": Array [ - 126, - 127, + 145, + 147, ], - "type": "Numeric", - "value": "2", + "type": "Identifier", + "value": "fn", }, Object { "loc": Object { "end": Object { - "column": 8, - "line": 7, + "column": 22, + "line": 6, }, "start": Object { - "column": 7, - "line": 7, + "column": 21, + "line": 6, }, }, "range": Array [ - 127, - 128, + 147, + 148, ], "type": "Punctuator", - "value": "]", + "value": "(", }, Object { "loc": Object { "end": Object { - "column": 10, - "line": 7, + "column": 23, + "line": 6, }, "start": Object { - "column": 8, - "line": 7, + "column": 22, + "line": 6, }, }, "range": Array [ - 128, - 130, + 148, + 149, ], "type": "Punctuator", - "value": "?.", + "value": ")", }, Object { "loc": Object { "end": Object { - "column": 11, - "line": 7, + "column": 24, + "line": 6, }, "start": Object { - "column": 10, - "line": 7, + "column": 23, + "line": 6, }, }, "range": Array [ - 130, - 131, + 149, + 150, ], "type": "Punctuator", - "value": "[", + "value": ")", }, Object { "loc": Object { "end": Object { - "column": 12, - "line": 7, + "column": 25, + "line": 6, }, "start": Object { - "column": 11, - "line": 7, + "column": 24, + "line": 6, }, }, "range": Array [ - 131, - 132, + 150, + 151, ], - "type": "Numeric", - "value": "3", + "type": "Punctuator", + "value": ";", }, Object { "loc": Object { "end": Object { - "column": 13, - "line": 7, + "column": 3, + "line": 8, }, "start": Object { - "column": 12, - "line": 7, + "column": 2, + "line": 8, }, }, "range": Array [ - 132, - 133, + 155, + 156, ], "type": "Punctuator", - "value": "]", + "value": "(", }, Object { "loc": Object { "end": Object { - "column": 15, - "line": 7, + "column": 6, + "line": 8, }, "start": Object { - "column": 13, - "line": 7, + "column": 3, + "line": 8, }, }, "range": Array [ - 133, - 135, + 156, + 159, ], - "type": "Punctuator", - "value": "?.", + "type": "Identifier", + "value": "one", }, Object { "loc": Object { "end": Object { - "column": 16, - "line": 7, + "column": 8, + "line": 8, }, "start": Object { - "column": 15, - "line": 7, + "column": 6, + "line": 8, }, }, "range": Array [ - 135, - 136, + 159, + 161, ], "type": "Punctuator", - "value": "[", + "value": "?.", }, Object { "loc": Object { "end": Object { - "column": 17, - "line": 7, + "column": 9, + "line": 8, }, "start": Object { - "column": 16, - "line": 7, + "column": 8, + "line": 8, }, }, "range": Array [ - 136, - 137, + 161, + 162, ], - "type": "Numeric", - "value": "4", + "type": "Punctuator", + "value": "(", }, Object { "loc": Object { "end": Object { - "column": 18, - "line": 7, + "column": 10, + "line": 8, }, "start": Object { - "column": 17, - "line": 7, + "column": 9, + "line": 8, }, }, "range": Array [ - 137, - 138, + 162, + 163, ], "type": "Punctuator", - "value": "]", + "value": ")", }, Object { "loc": Object { "end": Object { - "column": 19, - "line": 7, + "column": 11, + "line": 8, }, "start": Object { - "column": 18, - "line": 7, + "column": 10, + "line": 8, }, }, "range": Array [ - 138, - 139, + 163, + 164, ], "type": "Punctuator", - "value": ";", + "value": ")", }, Object { "loc": Object { "end": Object { - "column": 1, + "column": 12, "line": 8, }, "start": Object { - "column": 0, + "column": 11, "line": 8, }, }, "range": Array [ - 140, - 141, + 164, + 165, ], "type": "Punctuator", - "value": "}", + "value": ";", }, - ], - "type": "Program", -} -`; - -exports[`typescript fixtures/basics/optional-chain-element-access-with-parens.src 1`] = ` -Object { - "body": Array [ Object { - "async": false, - "body": Object { - "body": Array [ - Object { - "expression": Object { - "computed": true, - "loc": Object { - "end": Object { - "column": 11, - "line": 2, - }, - "start": Object { - "column": 3, - "line": 2, - }, - }, - "object": Object { - "loc": Object { - "end": Object { - "column": 6, - "line": 2, - }, - "start": Object { - "column": 3, - "line": 2, - }, - }, - "name": "one", - "range": Array [ - 54, - 57, - ], - "type": "Identifier", - }, - "optional": true, - "property": Object { - "loc": Object { - "end": Object { - "column": 10, - "line": 2, - }, - "start": Object { - "column": 9, - "line": 2, - }, - }, - "range": Array [ - 60, - 61, - ], - "raw": "2", - "type": "Literal", - "value": 2, - }, - "range": Array [ - 54, - 62, - ], - "type": "OptionalMemberExpression", - }, - "loc": Object { - "end": Object { - "column": 13, - "line": 2, - }, - "start": Object { - "column": 2, - "line": 2, - }, - }, - "range": Array [ - 53, - 64, - ], - "type": "ExpressionStatement", - }, - Object { - "expression": Object { - "computed": true, - "loc": Object { - "end": Object { - "column": 15, - "line": 3, - }, - "start": Object { - "column": 2, - "line": 3, - }, - }, - "object": Object { - "computed": true, - "loc": Object { - "end": Object { - "column": 11, - "line": 3, - }, - "start": Object { - "column": 3, - "line": 3, - }, - }, - "object": Object { - "loc": Object { - "end": Object { - "column": 6, - "line": 3, - }, - "start": Object { - "column": 3, - "line": 3, - }, - }, - "name": "one", - "range": Array [ - 68, - 71, - ], - "type": "Identifier", - }, - "optional": true, - "property": Object { - "loc": Object { - "end": Object { - "column": 10, - "line": 3, - }, - "start": Object { - "column": 9, - "line": 3, - }, - }, - "range": Array [ - 74, - 75, - ], - "raw": "2", - "type": "Literal", - "value": 2, - }, - "range": Array [ - 68, - 76, - ], - "type": "OptionalMemberExpression", - }, - "optional": false, - "property": Object { - "loc": Object { - "end": Object { - "column": 14, - "line": 3, - }, - "start": Object { - "column": 13, - "line": 3, - }, - }, - "range": Array [ - 78, - 79, - ], - "raw": "3", - "type": "Literal", - "value": 3, - }, - "range": Array [ - 67, - 80, - ], - "type": "MemberExpression", - }, - "loc": Object { - "end": Object { - "column": 16, - "line": 3, - }, - "start": Object { - "column": 2, - "line": 3, - }, - }, - "range": Array [ - 67, - 81, - ], - "type": "ExpressionStatement", - }, - Object { - "expression": Object { - "computed": true, - "loc": Object { - "end": Object { - "column": 14, - "line": 4, - }, - "start": Object { - "column": 3, - "line": 4, - }, - }, - "object": Object { - "computed": true, - "loc": Object { - "end": Object { - "column": 9, - "line": 4, - }, - "start": Object { - "column": 3, - "line": 4, - }, - }, - "object": Object { - "loc": Object { - "end": Object { - "column": 6, - "line": 4, - }, - "start": Object { - "column": 3, - "line": 4, - }, - }, - "name": "one", - "range": Array [ - 85, - 88, - ], + "loc": Object { + "end": Object { + "column": 3, + "line": 9, + }, + "start": Object { + "column": 2, + "line": 9, + }, + }, + "range": Array [ + 168, + 169, + ], + "type": "Punctuator", + "value": "(", + }, + Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 9, + }, + "start": Object { + "column": 3, + "line": 9, + }, + }, + "range": Array [ + 169, + 172, + ], + "type": "Identifier", + "value": "one", + }, + Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 9, + }, + "start": Object { + "column": 6, + "line": 9, + }, + }, + "range": Array [ + 172, + 174, + ], + "type": "Punctuator", + "value": "?.", + }, + Object { + "loc": Object { + "end": Object { + "column": 9, + "line": 9, + }, + "start": Object { + "column": 8, + "line": 9, + }, + }, + "range": Array [ + 174, + 175, + ], + "type": "Punctuator", + "value": "(", + }, + Object { + "loc": Object { + "end": Object { + "column": 10, + "line": 9, + }, + "start": Object { + "column": 9, + "line": 9, + }, + }, + "range": Array [ + 175, + 176, + ], + "type": "Punctuator", + "value": ")", + }, + Object { + "loc": Object { + "end": Object { + "column": 11, + "line": 9, + }, + "start": Object { + "column": 10, + "line": 9, + }, + }, + "range": Array [ + 176, + 177, + ], + "type": "Punctuator", + "value": ")", + }, + Object { + "loc": Object { + "end": Object { + "column": 12, + "line": 9, + }, + "start": Object { + "column": 11, + "line": 9, + }, + }, + "range": Array [ + 177, + 178, + ], + "type": "Punctuator", + "value": "(", + }, + Object { + "loc": Object { + "end": Object { + "column": 13, + "line": 9, + }, + "start": Object { + "column": 12, + "line": 9, + }, + }, + "range": Array [ + 178, + 179, + ], + "type": "Punctuator", + "value": ")", + }, + Object { + "loc": Object { + "end": Object { + "column": 14, + "line": 9, + }, + "start": Object { + "column": 13, + "line": 9, + }, + }, + "range": Array [ + 179, + 180, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 3, + "line": 10, + }, + "start": Object { + "column": 2, + "line": 10, + }, + }, + "range": Array [ + 183, + 184, + ], + "type": "Punctuator", + "value": "(", + }, + Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 10, + }, + "start": Object { + "column": 3, + "line": 10, + }, + }, + "range": Array [ + 184, + 187, + ], + "type": "Identifier", + "value": "one", + }, + Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 10, + }, + "start": Object { + "column": 6, + "line": 10, + }, + }, + "range": Array [ + 187, + 189, + ], + "type": "Punctuator", + "value": "?.", + }, + Object { + "loc": Object { + "end": Object { + "column": 9, + "line": 10, + }, + "start": Object { + "column": 8, + "line": 10, + }, + }, + "range": Array [ + 189, + 190, + ], + "type": "Punctuator", + "value": "(", + }, + Object { + "loc": Object { + "end": Object { + "column": 10, + "line": 10, + }, + "start": Object { + "column": 9, + "line": 10, + }, + }, + "range": Array [ + 190, + 191, + ], + "type": "Punctuator", + "value": ")", + }, + Object { + "loc": Object { + "end": Object { + "column": 11, + "line": 10, + }, + "start": Object { + "column": 10, + "line": 10, + }, + }, + "range": Array [ + 191, + 192, + ], + "type": "Punctuator", + "value": ")", + }, + Object { + "loc": Object { + "end": Object { + "column": 13, + "line": 10, + }, + "start": Object { + "column": 11, + "line": 10, + }, + }, + "range": Array [ + 192, + 194, + ], + "type": "Punctuator", + "value": "?.", + }, + Object { + "loc": Object { + "end": Object { + "column": 14, + "line": 10, + }, + "start": Object { + "column": 13, + "line": 10, + }, + }, + "range": Array [ + 194, + 195, + ], + "type": "Punctuator", + "value": "(", + }, + Object { + "loc": Object { + "end": Object { + "column": 15, + "line": 10, + }, + "start": Object { + "column": 14, + "line": 10, + }, + }, + "range": Array [ + 195, + 196, + ], + "type": "Punctuator", + "value": ")", + }, + Object { + "loc": Object { + "end": Object { + "column": 16, + "line": 10, + }, + "start": Object { + "column": 15, + "line": 10, + }, + }, + "range": Array [ + 196, + 197, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 3, + "line": 12, + }, + "start": Object { + "column": 2, + "line": 12, + }, + }, + "range": Array [ + 201, + 202, + ], + "type": "Punctuator", + "value": "(", + }, + Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 12, + }, + "start": Object { + "column": 3, + "line": 12, + }, + }, + "range": Array [ + 202, + 205, + ], + "type": "Identifier", + "value": "one", + }, + Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 12, + }, + "start": Object { + "column": 6, + "line": 12, + }, + }, + "range": Array [ + 205, + 207, + ], + "type": "Punctuator", + "value": "?.", + }, + Object { + "loc": Object { + "end": Object { + "column": 9, + "line": 12, + }, + "start": Object { + "column": 8, + "line": 12, + }, + }, + "range": Array [ + 207, + 208, + ], + "type": "Punctuator", + "value": "(", + }, + Object { + "loc": Object { + "end": Object { + "column": 10, + "line": 12, + }, + "start": Object { + "column": 9, + "line": 12, + }, + }, + "range": Array [ + 208, + 209, + ], + "type": "Punctuator", + "value": ")", + }, + Object { + "loc": Object { + "end": Object { + "column": 11, + "line": 12, + }, + "start": Object { + "column": 10, + "line": 12, + }, + }, + "range": Array [ + 209, + 210, + ], + "type": "Punctuator", + "value": ")", + }, + Object { + "loc": Object { + "end": Object { + "column": 12, + "line": 12, + }, + "start": Object { + "column": 11, + "line": 12, + }, + }, + "range": Array [ + 210, + 211, + ], + "type": "Punctuator", + "value": ".", + }, + Object { + "loc": Object { + "end": Object { + "column": 15, + "line": 12, + }, + "start": Object { + "column": 12, + "line": 12, + }, + }, + "range": Array [ + 211, + 214, + ], + "type": "Identifier", + "value": "two", + }, + Object { + "loc": Object { + "end": Object { + "column": 16, + "line": 12, + }, + "start": Object { + "column": 15, + "line": 12, + }, + }, + "range": Array [ + 214, + 215, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 1, + "line": 13, + }, + "start": Object { + "column": 0, + "line": 13, + }, + }, + "range": Array [ + 216, + 217, + ], + "type": "Punctuator", + "value": "}", + }, + ], + "type": "Program", +} +`; + +exports[`typescript fixtures/basics/optional-chain-element-access.src 1`] = ` +Object { + "body": Array [ + Object { + "async": false, + "body": Object { + "body": Array [ + Object { + "expression": Object { + "computed": true, + "loc": Object { + "end": Object { + "column": 10, + "line": 2, + }, + "start": Object { + "column": 2, + "line": 2, + }, + }, + "object": Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 2, + }, + "start": Object { + "column": 2, + "line": 2, + }, + }, + "name": "one", + "range": Array [ + 47, + 50, + ], + "type": "Identifier", + }, + "optional": true, + "property": Object { + "loc": Object { + "end": Object { + "column": 9, + "line": 2, + }, + "start": Object { + "column": 8, + "line": 2, + }, + }, + "range": Array [ + 53, + 54, + ], + "raw": "2", + "type": "Literal", + "value": 2, + }, + "range": Array [ + 47, + 55, + ], + "type": "OptionalMemberExpression", + }, + "loc": Object { + "end": Object { + "column": 11, + "line": 2, + }, + "start": Object { + "column": 2, + "line": 2, + }, + }, + "range": Array [ + 47, + 56, + ], + "type": "ExpressionStatement", + }, + Object { + "expression": Object { + "computed": true, + "loc": Object { + "end": Object { + "column": 13, + "line": 3, + }, + "start": Object { + "column": 2, + "line": 3, + }, + }, + "object": Object { + "computed": true, + "loc": Object { + "end": Object { + "column": 10, + "line": 3, + }, + "start": Object { + "column": 2, + "line": 3, + }, + }, + "object": Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 3, + }, + "start": Object { + "column": 2, + "line": 3, + }, + }, + "name": "one", + "range": Array [ + 59, + 62, + ], + "type": "Identifier", + }, + "optional": true, + "property": Object { + "loc": Object { + "end": Object { + "column": 9, + "line": 3, + }, + "start": Object { + "column": 8, + "line": 3, + }, + }, + "range": Array [ + 65, + 66, + ], + "raw": "2", + "type": "Literal", + "value": 2, + }, + "range": Array [ + 59, + 67, + ], + "type": "OptionalMemberExpression", + }, + "optional": false, + "property": Object { + "loc": Object { + "end": Object { + "column": 12, + "line": 3, + }, + "start": Object { + "column": 11, + "line": 3, + }, + }, + "range": Array [ + 68, + 69, + ], + "raw": "3", + "type": "Literal", + "value": 3, + }, + "range": Array [ + 59, + 70, + ], + "type": "OptionalMemberExpression", + }, + "loc": Object { + "end": Object { + "column": 14, + "line": 3, + }, + "start": Object { + "column": 2, + "line": 3, + }, + }, + "range": Array [ + 59, + 71, + ], + "type": "ExpressionStatement", + }, + Object { + "expression": Object { + "computed": true, + "loc": Object { + "end": Object { + "column": 13, + "line": 4, + }, + "start": Object { + "column": 2, + "line": 4, + }, + }, + "object": Object { + "computed": true, + "loc": Object { + "end": Object { + "column": 8, + "line": 4, + }, + "start": Object { + "column": 2, + "line": 4, + }, + }, + "object": Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 4, + }, + "start": Object { + "column": 2, + "line": 4, + }, + }, + "name": "one", + "range": Array [ + 74, + 77, + ], + "type": "Identifier", + }, + "optional": false, + "property": Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 4, + }, + "start": Object { + "column": 6, + "line": 4, + }, + }, + "range": Array [ + 78, + 79, + ], + "raw": "2", + "type": "Literal", + "value": 2, + }, + "range": Array [ + 74, + 80, + ], + "type": "MemberExpression", + }, + "optional": true, + "property": Object { + "loc": Object { + "end": Object { + "column": 12, + "line": 4, + }, + "start": Object { + "column": 11, + "line": 4, + }, + }, + "range": Array [ + 83, + 84, + ], + "raw": "3", + "type": "Literal", + "value": 3, + }, + "range": Array [ + 74, + 85, + ], + "type": "OptionalMemberExpression", + }, + "loc": Object { + "end": Object { + "column": 14, + "line": 4, + }, + "start": Object { + "column": 2, + "line": 4, + }, + }, + "range": Array [ + 74, + 86, + ], + "type": "ExpressionStatement", + }, + Object { + "expression": Object { + "computed": true, + "loc": Object { + "end": Object { + "column": 13, + "line": 5, + }, + "start": Object { + "column": 2, + "line": 5, + }, + }, + "object": Object { + "computed": true, + "loc": Object { + "end": Object { + "column": 8, + "line": 5, + }, + "start": Object { + "column": 2, + "line": 5, + }, + }, + "object": Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 5, + }, + "start": Object { + "column": 2, + "line": 5, + }, + }, + "name": "one", + "range": Array [ + 89, + 92, + ], + "type": "Identifier", + }, + "optional": false, + "property": Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 5, + }, + "start": Object { + "column": 6, + "line": 5, + }, + }, + "range": Array [ + 93, + 94, + ], + "raw": "2", + "type": "Literal", + "value": 2, + }, + "range": Array [ + 89, + 95, + ], + "type": "MemberExpression", + }, + "optional": true, + "property": Object { + "loc": Object { + "end": Object { + "column": 12, + "line": 5, + }, + "start": Object { + "column": 11, + "line": 5, + }, + }, + "range": Array [ + 98, + 99, + ], + "raw": "3", + "type": "Literal", + "value": 3, + }, + "range": Array [ + 89, + 100, + ], + "type": "OptionalMemberExpression", + }, + "loc": Object { + "end": Object { + "column": 14, + "line": 5, + }, + "start": Object { + "column": 2, + "line": 5, + }, + }, + "range": Array [ + 89, + 101, + ], + "type": "ExpressionStatement", + }, + Object { + "expression": Object { + "computed": true, + "loc": Object { + "end": Object { + "column": 16, + "line": 6, + }, + "start": Object { + "column": 2, + "line": 6, + }, + }, + "object": Object { + "computed": true, + "loc": Object { + "end": Object { + "column": 13, + "line": 6, + }, + "start": Object { + "column": 2, + "line": 6, + }, + }, + "object": Object { + "computed": true, + "loc": Object { + "end": Object { + "column": 8, + "line": 6, + }, + "start": Object { + "column": 2, + "line": 6, + }, + }, + "object": Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 6, + }, + "start": Object { + "column": 2, + "line": 6, + }, + }, + "name": "one", + "range": Array [ + 104, + 107, + ], + "type": "Identifier", + }, + "optional": false, + "property": Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 6, + }, + "start": Object { + "column": 6, + "line": 6, + }, + }, + "range": Array [ + 108, + 109, + ], + "raw": "2", + "type": "Literal", + "value": 2, + }, + "range": Array [ + 104, + 110, + ], + "type": "MemberExpression", + }, + "optional": true, + "property": Object { + "loc": Object { + "end": Object { + "column": 12, + "line": 6, + }, + "start": Object { + "column": 11, + "line": 6, + }, + }, + "range": Array [ + 113, + 114, + ], + "raw": "3", + "type": "Literal", + "value": 3, + }, + "range": Array [ + 104, + 115, + ], + "type": "OptionalMemberExpression", + }, + "optional": false, + "property": Object { + "loc": Object { + "end": Object { + "column": 15, + "line": 6, + }, + "start": Object { + "column": 14, + "line": 6, + }, + }, + "range": Array [ + 116, + 117, + ], + "raw": "4", + "type": "Literal", + "value": 4, + }, + "range": Array [ + 104, + 118, + ], + "type": "OptionalMemberExpression", + }, + "loc": Object { + "end": Object { + "column": 17, + "line": 6, + }, + "start": Object { + "column": 2, + "line": 6, + }, + }, + "range": Array [ + 104, + 119, + ], + "type": "ExpressionStatement", + }, + Object { + "expression": Object { + "computed": true, + "loc": Object { + "end": Object { + "column": 18, + "line": 7, + }, + "start": Object { + "column": 2, + "line": 7, + }, + }, + "object": Object { + "computed": true, + "loc": Object { + "end": Object { + "column": 13, + "line": 7, + }, + "start": Object { + "column": 2, + "line": 7, + }, + }, + "object": Object { + "computed": true, + "loc": Object { + "end": Object { + "column": 8, + "line": 7, + }, + "start": Object { + "column": 2, + "line": 7, + }, + }, + "object": Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 7, + }, + "start": Object { + "column": 2, + "line": 7, + }, + }, + "name": "one", + "range": Array [ + 122, + 125, + ], + "type": "Identifier", + }, + "optional": false, + "property": Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 7, + }, + "start": Object { + "column": 6, + "line": 7, + }, + }, + "range": Array [ + 126, + 127, + ], + "raw": "2", + "type": "Literal", + "value": 2, + }, + "range": Array [ + 122, + 128, + ], + "type": "MemberExpression", + }, + "optional": true, + "property": Object { + "loc": Object { + "end": Object { + "column": 12, + "line": 7, + }, + "start": Object { + "column": 11, + "line": 7, + }, + }, + "range": Array [ + 131, + 132, + ], + "raw": "3", + "type": "Literal", + "value": 3, + }, + "range": Array [ + 122, + 133, + ], + "type": "OptionalMemberExpression", + }, + "optional": true, + "property": Object { + "loc": Object { + "end": Object { + "column": 17, + "line": 7, + }, + "start": Object { + "column": 16, + "line": 7, + }, + }, + "range": Array [ + 136, + 137, + ], + "raw": "4", + "type": "Literal", + "value": 4, + }, + "range": Array [ + 122, + 138, + ], + "type": "OptionalMemberExpression", + }, + "loc": Object { + "end": Object { + "column": 19, + "line": 7, + }, + "start": Object { + "column": 2, + "line": 7, + }, + }, + "range": Array [ + 122, + 139, + ], + "type": "ExpressionStatement", + }, + ], + "loc": Object { + "end": Object { + "column": 1, + "line": 8, + }, + "start": Object { + "column": 43, + "line": 1, + }, + }, + "range": Array [ + 43, + 141, + ], + "type": "BlockStatement", + }, + "expression": false, + "generator": false, + "id": Object { + "loc": Object { + "end": Object { + "column": 31, + "line": 1, + }, + "start": Object { + "column": 9, + "line": 1, + }, + }, + "name": "processOptionalElement", + "range": Array [ + 9, + 31, + ], + "type": "Identifier", + }, + "loc": Object { + "end": Object { + "column": 1, + "line": 8, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "params": Array [ + Object { + "loc": Object { + "end": Object { + "column": 41, + "line": 1, + }, + "start": Object { + "column": 32, + "line": 1, + }, + }, + "name": "one", + "optional": true, + "range": Array [ + 32, + 41, + ], + "type": "Identifier", + "typeAnnotation": Object { + "loc": Object { + "end": Object { + "column": 41, + "line": 1, + }, + "start": Object { + "column": 36, + "line": 1, + }, + }, + "range": Array [ + 36, + 41, + ], + "type": "TSTypeAnnotation", + "typeAnnotation": Object { + "loc": Object { + "end": Object { + "column": 41, + "line": 1, + }, + "start": Object { + "column": 38, + "line": 1, + }, + }, + "range": Array [ + 38, + 41, + ], + "type": "TSAnyKeyword", + }, + }, + }, + ], + "range": Array [ + 0, + 141, + ], + "type": "FunctionDeclaration", + }, + ], + "loc": Object { + "end": Object { + "column": 0, + "line": 9, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "range": Array [ + 0, + 142, + ], + "sourceType": "script", + "tokens": Array [ + Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 1, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "range": Array [ + 0, + 8, + ], + "type": "Keyword", + "value": "function", + }, + Object { + "loc": Object { + "end": Object { + "column": 31, + "line": 1, + }, + "start": Object { + "column": 9, + "line": 1, + }, + }, + "range": Array [ + 9, + 31, + ], + "type": "Identifier", + "value": "processOptionalElement", + }, + Object { + "loc": Object { + "end": Object { + "column": 32, + "line": 1, + }, + "start": Object { + "column": 31, + "line": 1, + }, + }, + "range": Array [ + 31, + 32, + ], + "type": "Punctuator", + "value": "(", + }, + Object { + "loc": Object { + "end": Object { + "column": 35, + "line": 1, + }, + "start": Object { + "column": 32, + "line": 1, + }, + }, + "range": Array [ + 32, + 35, + ], + "type": "Identifier", + "value": "one", + }, + Object { + "loc": Object { + "end": Object { + "column": 36, + "line": 1, + }, + "start": Object { + "column": 35, + "line": 1, + }, + }, + "range": Array [ + 35, + 36, + ], + "type": "Punctuator", + "value": "?", + }, + Object { + "loc": Object { + "end": Object { + "column": 37, + "line": 1, + }, + "start": Object { + "column": 36, + "line": 1, + }, + }, + "range": Array [ + 36, + 37, + ], + "type": "Punctuator", + "value": ":", + }, + Object { + "loc": Object { + "end": Object { + "column": 41, + "line": 1, + }, + "start": Object { + "column": 38, + "line": 1, + }, + }, + "range": Array [ + 38, + 41, + ], + "type": "Identifier", + "value": "any", + }, + Object { + "loc": Object { + "end": Object { + "column": 42, + "line": 1, + }, + "start": Object { + "column": 41, + "line": 1, + }, + }, + "range": Array [ + 41, + 42, + ], + "type": "Punctuator", + "value": ")", + }, + Object { + "loc": Object { + "end": Object { + "column": 44, + "line": 1, + }, + "start": Object { + "column": 43, + "line": 1, + }, + }, + "range": Array [ + 43, + 44, + ], + "type": "Punctuator", + "value": "{", + }, + Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 2, + }, + "start": Object { + "column": 2, + "line": 2, + }, + }, + "range": Array [ + 47, + 50, + ], + "type": "Identifier", + "value": "one", + }, + Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 2, + }, + "start": Object { + "column": 5, + "line": 2, + }, + }, + "range": Array [ + 50, + 52, + ], + "type": "Punctuator", + "value": "?.", + }, + Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 2, + }, + "start": Object { + "column": 7, + "line": 2, + }, + }, + "range": Array [ + 52, + 53, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 9, + "line": 2, + }, + "start": Object { + "column": 8, + "line": 2, + }, + }, + "range": Array [ + 53, + 54, + ], + "type": "Numeric", + "value": "2", + }, + Object { + "loc": Object { + "end": Object { + "column": 10, + "line": 2, + }, + "start": Object { + "column": 9, + "line": 2, + }, + }, + "range": Array [ + 54, + 55, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 11, + "line": 2, + }, + "start": Object { + "column": 10, + "line": 2, + }, + }, + "range": Array [ + 55, + 56, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 3, + }, + "start": Object { + "column": 2, + "line": 3, + }, + }, + "range": Array [ + 59, + 62, + ], + "type": "Identifier", + "value": "one", + }, + Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 3, + }, + "start": Object { + "column": 5, + "line": 3, + }, + }, + "range": Array [ + 62, + 64, + ], + "type": "Punctuator", + "value": "?.", + }, + Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 3, + }, + "start": Object { + "column": 7, + "line": 3, + }, + }, + "range": Array [ + 64, + 65, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 9, + "line": 3, + }, + "start": Object { + "column": 8, + "line": 3, + }, + }, + "range": Array [ + 65, + 66, + ], + "type": "Numeric", + "value": "2", + }, + Object { + "loc": Object { + "end": Object { + "column": 10, + "line": 3, + }, + "start": Object { + "column": 9, + "line": 3, + }, + }, + "range": Array [ + 66, + 67, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 11, + "line": 3, + }, + "start": Object { + "column": 10, + "line": 3, + }, + }, + "range": Array [ + 67, + 68, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 12, + "line": 3, + }, + "start": Object { + "column": 11, + "line": 3, + }, + }, + "range": Array [ + 68, + 69, + ], + "type": "Numeric", + "value": "3", + }, + Object { + "loc": Object { + "end": Object { + "column": 13, + "line": 3, + }, + "start": Object { + "column": 12, + "line": 3, + }, + }, + "range": Array [ + 69, + 70, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 14, + "line": 3, + }, + "start": Object { + "column": 13, + "line": 3, + }, + }, + "range": Array [ + 70, + 71, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 4, + }, + "start": Object { + "column": 2, + "line": 4, + }, + }, + "range": Array [ + 74, + 77, + ], + "type": "Identifier", + "value": "one", + }, + Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 4, + }, + "start": Object { + "column": 5, + "line": 4, + }, + }, + "range": Array [ + 77, + 78, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 4, + }, + "start": Object { + "column": 6, + "line": 4, + }, + }, + "range": Array [ + 78, + 79, + ], + "type": "Numeric", + "value": "2", + }, + Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 4, + }, + "start": Object { + "column": 7, + "line": 4, + }, + }, + "range": Array [ + 79, + 80, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 10, + "line": 4, + }, + "start": Object { + "column": 8, + "line": 4, + }, + }, + "range": Array [ + 80, + 82, + ], + "type": "Punctuator", + "value": "?.", + }, + Object { + "loc": Object { + "end": Object { + "column": 11, + "line": 4, + }, + "start": Object { + "column": 10, + "line": 4, + }, + }, + "range": Array [ + 82, + 83, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 12, + "line": 4, + }, + "start": Object { + "column": 11, + "line": 4, + }, + }, + "range": Array [ + 83, + 84, + ], + "type": "Numeric", + "value": "3", + }, + Object { + "loc": Object { + "end": Object { + "column": 13, + "line": 4, + }, + "start": Object { + "column": 12, + "line": 4, + }, + }, + "range": Array [ + 84, + 85, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 14, + "line": 4, + }, + "start": Object { + "column": 13, + "line": 4, + }, + }, + "range": Array [ + 85, + 86, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 5, + }, + "start": Object { + "column": 2, + "line": 5, + }, + }, + "range": Array [ + 89, + 92, + ], + "type": "Identifier", + "value": "one", + }, + Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 5, + }, + "start": Object { + "column": 5, + "line": 5, + }, + }, + "range": Array [ + 92, + 93, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 5, + }, + "start": Object { + "column": 6, + "line": 5, + }, + }, + "range": Array [ + 93, + 94, + ], + "type": "Numeric", + "value": "2", + }, + Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 5, + }, + "start": Object { + "column": 7, + "line": 5, + }, + }, + "range": Array [ + 94, + 95, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 10, + "line": 5, + }, + "start": Object { + "column": 8, + "line": 5, + }, + }, + "range": Array [ + 95, + 97, + ], + "type": "Punctuator", + "value": "?.", + }, + Object { + "loc": Object { + "end": Object { + "column": 11, + "line": 5, + }, + "start": Object { + "column": 10, + "line": 5, + }, + }, + "range": Array [ + 97, + 98, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 12, + "line": 5, + }, + "start": Object { + "column": 11, + "line": 5, + }, + }, + "range": Array [ + 98, + 99, + ], + "type": "Numeric", + "value": "3", + }, + Object { + "loc": Object { + "end": Object { + "column": 13, + "line": 5, + }, + "start": Object { + "column": 12, + "line": 5, + }, + }, + "range": Array [ + 99, + 100, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 14, + "line": 5, + }, + "start": Object { + "column": 13, + "line": 5, + }, + }, + "range": Array [ + 100, + 101, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 6, + }, + "start": Object { + "column": 2, + "line": 6, + }, + }, + "range": Array [ + 104, + 107, + ], + "type": "Identifier", + "value": "one", + }, + Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 6, + }, + "start": Object { + "column": 5, + "line": 6, + }, + }, + "range": Array [ + 107, + 108, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 6, + }, + "start": Object { + "column": 6, + "line": 6, + }, + }, + "range": Array [ + 108, + 109, + ], + "type": "Numeric", + "value": "2", + }, + Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 6, + }, + "start": Object { + "column": 7, + "line": 6, + }, + }, + "range": Array [ + 109, + 110, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 10, + "line": 6, + }, + "start": Object { + "column": 8, + "line": 6, + }, + }, + "range": Array [ + 110, + 112, + ], + "type": "Punctuator", + "value": "?.", + }, + Object { + "loc": Object { + "end": Object { + "column": 11, + "line": 6, + }, + "start": Object { + "column": 10, + "line": 6, + }, + }, + "range": Array [ + 112, + 113, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 12, + "line": 6, + }, + "start": Object { + "column": 11, + "line": 6, + }, + }, + "range": Array [ + 113, + 114, + ], + "type": "Numeric", + "value": "3", + }, + Object { + "loc": Object { + "end": Object { + "column": 13, + "line": 6, + }, + "start": Object { + "column": 12, + "line": 6, + }, + }, + "range": Array [ + 114, + 115, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 14, + "line": 6, + }, + "start": Object { + "column": 13, + "line": 6, + }, + }, + "range": Array [ + 115, + 116, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 15, + "line": 6, + }, + "start": Object { + "column": 14, + "line": 6, + }, + }, + "range": Array [ + 116, + 117, + ], + "type": "Numeric", + "value": "4", + }, + Object { + "loc": Object { + "end": Object { + "column": 16, + "line": 6, + }, + "start": Object { + "column": 15, + "line": 6, + }, + }, + "range": Array [ + 117, + 118, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 17, + "line": 6, + }, + "start": Object { + "column": 16, + "line": 6, + }, + }, + "range": Array [ + 118, + 119, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 7, + }, + "start": Object { + "column": 2, + "line": 7, + }, + }, + "range": Array [ + 122, + 125, + ], + "type": "Identifier", + "value": "one", + }, + Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 7, + }, + "start": Object { + "column": 5, + "line": 7, + }, + }, + "range": Array [ + 125, + 126, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 7, + }, + "start": Object { + "column": 6, + "line": 7, + }, + }, + "range": Array [ + 126, + 127, + ], + "type": "Numeric", + "value": "2", + }, + Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 7, + }, + "start": Object { + "column": 7, + "line": 7, + }, + }, + "range": Array [ + 127, + 128, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 10, + "line": 7, + }, + "start": Object { + "column": 8, + "line": 7, + }, + }, + "range": Array [ + 128, + 130, + ], + "type": "Punctuator", + "value": "?.", + }, + Object { + "loc": Object { + "end": Object { + "column": 11, + "line": 7, + }, + "start": Object { + "column": 10, + "line": 7, + }, + }, + "range": Array [ + 130, + 131, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 12, + "line": 7, + }, + "start": Object { + "column": 11, + "line": 7, + }, + }, + "range": Array [ + 131, + 132, + ], + "type": "Numeric", + "value": "3", + }, + Object { + "loc": Object { + "end": Object { + "column": 13, + "line": 7, + }, + "start": Object { + "column": 12, + "line": 7, + }, + }, + "range": Array [ + 132, + 133, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 15, + "line": 7, + }, + "start": Object { + "column": 13, + "line": 7, + }, + }, + "range": Array [ + 133, + 135, + ], + "type": "Punctuator", + "value": "?.", + }, + Object { + "loc": Object { + "end": Object { + "column": 16, + "line": 7, + }, + "start": Object { + "column": 15, + "line": 7, + }, + }, + "range": Array [ + 135, + 136, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 17, + "line": 7, + }, + "start": Object { + "column": 16, + "line": 7, + }, + }, + "range": Array [ + 136, + 137, + ], + "type": "Numeric", + "value": "4", + }, + Object { + "loc": Object { + "end": Object { + "column": 18, + "line": 7, + }, + "start": Object { + "column": 17, + "line": 7, + }, + }, + "range": Array [ + 137, + 138, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 19, + "line": 7, + }, + "start": Object { + "column": 18, + "line": 7, + }, + }, + "range": Array [ + 138, + 139, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 1, + "line": 8, + }, + "start": Object { + "column": 0, + "line": 8, + }, + }, + "range": Array [ + 140, + 141, + ], + "type": "Punctuator", + "value": "}", + }, + ], + "type": "Program", +} +`; + +exports[`typescript fixtures/basics/optional-chain-element-access-with-non-null-assertion.src 1`] = ` +Object { + "body": Array [ + Object { + "async": false, + "body": Object { + "body": Array [ + Object { + "expression": Object { + "computed": false, + "loc": Object { + "end": Object { + "column": 21, + "line": 2, + }, + "start": Object { + "column": 2, + "line": 2, + }, + }, + "object": Object { + "expression": Object { + "computed": true, + "loc": Object { + "end": Object { + "column": 14, + "line": 2, + }, + "start": Object { + "column": 2, + "line": 2, + }, + }, + "object": Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 2, + }, + "start": Object { + "column": 2, + "line": 2, + }, + }, + "name": "one", + "range": Array [ + 40, + 43, + ], + "type": "Identifier", + }, + "optional": true, + "property": Object { + "loc": Object { + "end": Object { + "column": 13, + "line": 2, + }, + "start": Object { + "column": 8, + "line": 2, + }, + }, + "range": Array [ + 46, + 51, + ], + "raw": "'two'", + "type": "Literal", + "value": "two", + }, + "range": Array [ + 40, + 52, + ], + "type": "OptionalMemberExpression", + }, + "loc": Object { + "end": Object { + "column": 15, + "line": 2, + }, + "start": Object { + "column": 2, + "line": 2, + }, + }, + "range": Array [ + 40, + 53, + ], + "type": "TSNonNullExpression", + }, + "optional": false, + "property": Object { + "loc": Object { + "end": Object { + "column": 21, + "line": 2, + }, + "start": Object { + "column": 16, + "line": 2, + }, + }, + "name": "three", + "range": Array [ + 54, + 59, + ], + "type": "Identifier", + }, + "range": Array [ + 40, + 59, + ], + "type": "OptionalMemberExpression", + }, + "loc": Object { + "end": Object { + "column": 22, + "line": 2, + }, + "start": Object { + "column": 2, + "line": 2, + }, + }, + "range": Array [ + 40, + 60, + ], + "type": "ExpressionStatement", + }, + Object { + "expression": Object { + "computed": false, + "loc": Object { + "end": Object { + "column": 23, + "line": 3, + }, + "start": Object { + "column": 2, + "line": 3, + }, + }, + "object": Object { + "expression": Object { + "computed": true, + "loc": Object { + "end": Object { + "column": 15, + "line": 3, + }, + "start": Object { + "column": 3, + "line": 3, + }, + }, + "object": Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 3, + }, + "start": Object { + "column": 3, + "line": 3, + }, + }, + "name": "one", + "range": Array [ + 64, + 67, + ], + "type": "Identifier", + }, + "optional": true, + "property": Object { + "loc": Object { + "end": Object { + "column": 14, + "line": 3, + }, + "start": Object { + "column": 9, + "line": 3, + }, + }, + "range": Array [ + 70, + 75, + ], + "raw": "'two'", + "type": "Literal", + "value": "two", + }, + "range": Array [ + 64, + 76, + ], + "type": "OptionalMemberExpression", + }, + "loc": Object { + "end": Object { + "column": 17, + "line": 3, + }, + "start": Object { + "column": 2, + "line": 3, + }, + }, + "range": Array [ + 63, + 78, + ], + "type": "TSNonNullExpression", + }, + "optional": false, + "property": Object { + "loc": Object { + "end": Object { + "column": 23, + "line": 3, + }, + "start": Object { + "column": 18, + "line": 3, + }, + }, + "name": "three", + "range": Array [ + 79, + 84, + ], + "type": "Identifier", + }, + "range": Array [ + 63, + 84, + ], + "type": "MemberExpression", + }, + "loc": Object { + "end": Object { + "column": 24, + "line": 3, + }, + "start": Object { + "column": 2, + "line": 3, + }, + }, + "range": Array [ + 63, + 85, + ], + "type": "ExpressionStatement", + }, + Object { + "expression": Object { + "computed": false, + "loc": Object { + "end": Object { + "column": 23, + "line": 4, + }, + "start": Object { + "column": 2, + "line": 4, + }, + }, + "object": Object { + "expression": Object { + "computed": true, + "loc": Object { + "end": Object { + "column": 15, + "line": 4, + }, + "start": Object { + "column": 3, + "line": 4, + }, + }, + "object": Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 4, + }, + "start": Object { + "column": 3, + "line": 4, + }, + }, + "name": "one", + "range": Array [ + 89, + 92, + ], + "type": "Identifier", + }, + "optional": true, + "property": Object { + "loc": Object { + "end": Object { + "column": 14, + "line": 4, + }, + "start": Object { + "column": 9, + "line": 4, + }, + }, + "range": Array [ + 95, + 100, + ], + "raw": "'two'", + "type": "Literal", + "value": "two", + }, + "range": Array [ + 89, + 101, + ], + "type": "OptionalMemberExpression", + }, + "loc": Object { + "end": Object { + "column": 16, + "line": 4, + }, + "start": Object { + "column": 3, + "line": 4, + }, + }, + "range": Array [ + 89, + 102, + ], + "type": "TSNonNullExpression", + }, + "optional": false, + "property": Object { + "loc": Object { + "end": Object { + "column": 23, + "line": 4, + }, + "start": Object { + "column": 18, + "line": 4, + }, + }, + "name": "three", + "range": Array [ + 104, + 109, + ], + "type": "Identifier", + }, + "range": Array [ + 88, + 109, + ], + "type": "MemberExpression", + }, + "loc": Object { + "end": Object { + "column": 24, + "line": 4, + }, + "start": Object { + "column": 2, + "line": 4, + }, + }, + "range": Array [ + 88, + 110, + ], + "type": "ExpressionStatement", + }, + Object { + "expression": Object { + "computed": true, + "loc": Object { + "end": Object { + "column": 20, + "line": 5, + }, + "start": Object { + "column": 2, + "line": 5, + }, + }, + "object": Object { + "expression": Object { + "computed": false, + "loc": Object { + "end": Object { + "column": 10, + "line": 5, + }, + "start": Object { + "column": 2, + "line": 5, + }, + }, + "object": Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 5, + }, + "start": Object { + "column": 2, + "line": 5, + }, + }, + "name": "one", + "range": Array [ + 113, + 116, + ], + "type": "Identifier", + }, + "optional": true, + "property": Object { + "loc": Object { + "end": Object { + "column": 10, + "line": 5, + }, + "start": Object { + "column": 7, + "line": 5, + }, + }, + "name": "two", + "range": Array [ + 118, + 121, + ], + "type": "Identifier", + }, + "range": Array [ + 113, + 121, + ], + "type": "OptionalMemberExpression", + }, + "loc": Object { + "end": Object { + "column": 11, + "line": 5, + }, + "start": Object { + "column": 2, + "line": 5, + }, + }, + "range": Array [ + 113, + 122, + ], + "type": "TSNonNullExpression", + }, + "optional": false, + "property": Object { + "loc": Object { + "end": Object { + "column": 19, + "line": 5, + }, + "start": Object { + "column": 12, + "line": 5, + }, + }, + "range": Array [ + 123, + 130, + ], + "raw": "'three'", + "type": "Literal", + "value": "three", + }, + "range": Array [ + 113, + 131, + ], + "type": "OptionalMemberExpression", + }, + "loc": Object { + "end": Object { + "column": 21, + "line": 5, + }, + "start": Object { + "column": 2, + "line": 5, + }, + }, + "range": Array [ + 113, + 132, + ], + "type": "ExpressionStatement", + }, + Object { + "expression": Object { + "computed": true, + "loc": Object { + "end": Object { + "column": 22, + "line": 6, + }, + "start": Object { + "column": 2, + "line": 6, + }, + }, + "object": Object { + "expression": Object { + "computed": false, + "loc": Object { + "end": Object { + "column": 11, + "line": 6, + }, + "start": Object { + "column": 3, + "line": 6, + }, + }, + "object": Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 6, + }, + "start": Object { + "column": 3, + "line": 6, + }, + }, + "name": "one", + "range": Array [ + 136, + 139, + ], + "type": "Identifier", + }, + "optional": true, + "property": Object { + "loc": Object { + "end": Object { + "column": 11, + "line": 6, + }, + "start": Object { + "column": 8, + "line": 6, + }, + }, + "name": "two", + "range": Array [ + 141, + 144, + ], + "type": "Identifier", + }, + "range": Array [ + 136, + 144, + ], + "type": "OptionalMemberExpression", + }, + "loc": Object { + "end": Object { + "column": 13, + "line": 6, + }, + "start": Object { + "column": 2, + "line": 6, + }, + }, + "range": Array [ + 135, + 146, + ], + "type": "TSNonNullExpression", + }, + "optional": false, + "property": Object { + "loc": Object { + "end": Object { + "column": 21, + "line": 6, + }, + "start": Object { + "column": 14, + "line": 6, + }, + }, + "range": Array [ + 147, + 154, + ], + "raw": "'three'", + "type": "Literal", + "value": "three", + }, + "range": Array [ + 135, + 155, + ], + "type": "MemberExpression", + }, + "loc": Object { + "end": Object { + "column": 23, + "line": 6, + }, + "start": Object { + "column": 2, + "line": 6, + }, + }, + "range": Array [ + 135, + 156, + ], + "type": "ExpressionStatement", + }, + Object { + "expression": Object { + "computed": true, + "loc": Object { + "end": Object { + "column": 22, + "line": 7, + }, + "start": Object { + "column": 2, + "line": 7, + }, + }, + "object": Object { + "expression": Object { + "computed": false, + "loc": Object { + "end": Object { + "column": 11, + "line": 7, + }, + "start": Object { + "column": 3, + "line": 7, + }, + }, + "object": Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 7, + }, + "start": Object { + "column": 3, + "line": 7, + }, + }, + "name": "one", + "range": Array [ + 160, + 163, + ], + "type": "Identifier", + }, + "optional": true, + "property": Object { + "loc": Object { + "end": Object { + "column": 11, + "line": 7, + }, + "start": Object { + "column": 8, + "line": 7, + }, + }, + "name": "two", + "range": Array [ + 165, + 168, + ], + "type": "Identifier", + }, + "range": Array [ + 160, + 168, + ], + "type": "OptionalMemberExpression", + }, + "loc": Object { + "end": Object { + "column": 12, + "line": 7, + }, + "start": Object { + "column": 3, + "line": 7, + }, + }, + "range": Array [ + 160, + 169, + ], + "type": "TSNonNullExpression", + }, + "optional": false, + "property": Object { + "loc": Object { + "end": Object { + "column": 21, + "line": 7, + }, + "start": Object { + "column": 14, + "line": 7, + }, + }, + "range": Array [ + 171, + 178, + ], + "raw": "'three'", + "type": "Literal", + "value": "three", + }, + "range": Array [ + 159, + 179, + ], + "type": "MemberExpression", + }, + "loc": Object { + "end": Object { + "column": 23, + "line": 7, + }, + "start": Object { + "column": 2, + "line": 7, + }, + }, + "range": Array [ + 159, + 180, + ], + "type": "ExpressionStatement", + }, + ], + "loc": Object { + "end": Object { + "column": 1, + "line": 8, + }, + "start": Object { + "column": 36, + "line": 1, + }, + }, + "range": Array [ + 36, + 182, + ], + "type": "BlockStatement", + }, + "expression": false, + "generator": false, + "id": Object { + "loc": Object { + "end": Object { + "column": 24, + "line": 1, + }, + "start": Object { + "column": 9, + "line": 1, + }, + }, + "name": "processOptional", + "range": Array [ + 9, + 24, + ], + "type": "Identifier", + }, + "loc": Object { + "end": Object { + "column": 1, + "line": 8, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "params": Array [ + Object { + "loc": Object { + "end": Object { + "column": 34, + "line": 1, + }, + "start": Object { + "column": 25, + "line": 1, + }, + }, + "name": "one", + "optional": true, + "range": Array [ + 25, + 34, + ], + "type": "Identifier", + "typeAnnotation": Object { + "loc": Object { + "end": Object { + "column": 34, + "line": 1, + }, + "start": Object { + "column": 29, + "line": 1, + }, + }, + "range": Array [ + 29, + 34, + ], + "type": "TSTypeAnnotation", + "typeAnnotation": Object { + "loc": Object { + "end": Object { + "column": 34, + "line": 1, + }, + "start": Object { + "column": 31, + "line": 1, + }, + }, + "range": Array [ + 31, + 34, + ], + "type": "TSAnyKeyword", + }, + }, + }, + ], + "range": Array [ + 0, + 182, + ], + "type": "FunctionDeclaration", + }, + ], + "loc": Object { + "end": Object { + "column": 0, + "line": 9, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "range": Array [ + 0, + 183, + ], + "sourceType": "script", + "tokens": Array [ + Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 1, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "range": Array [ + 0, + 8, + ], + "type": "Keyword", + "value": "function", + }, + Object { + "loc": Object { + "end": Object { + "column": 24, + "line": 1, + }, + "start": Object { + "column": 9, + "line": 1, + }, + }, + "range": Array [ + 9, + 24, + ], + "type": "Identifier", + "value": "processOptional", + }, + Object { + "loc": Object { + "end": Object { + "column": 25, + "line": 1, + }, + "start": Object { + "column": 24, + "line": 1, + }, + }, + "range": Array [ + 24, + 25, + ], + "type": "Punctuator", + "value": "(", + }, + Object { + "loc": Object { + "end": Object { + "column": 28, + "line": 1, + }, + "start": Object { + "column": 25, + "line": 1, + }, + }, + "range": Array [ + 25, + 28, + ], + "type": "Identifier", + "value": "one", + }, + Object { + "loc": Object { + "end": Object { + "column": 29, + "line": 1, + }, + "start": Object { + "column": 28, + "line": 1, + }, + }, + "range": Array [ + 28, + 29, + ], + "type": "Punctuator", + "value": "?", + }, + Object { + "loc": Object { + "end": Object { + "column": 30, + "line": 1, + }, + "start": Object { + "column": 29, + "line": 1, + }, + }, + "range": Array [ + 29, + 30, + ], + "type": "Punctuator", + "value": ":", + }, + Object { + "loc": Object { + "end": Object { + "column": 34, + "line": 1, + }, + "start": Object { + "column": 31, + "line": 1, + }, + }, + "range": Array [ + 31, + 34, + ], + "type": "Identifier", + "value": "any", + }, + Object { + "loc": Object { + "end": Object { + "column": 35, + "line": 1, + }, + "start": Object { + "column": 34, + "line": 1, + }, + }, + "range": Array [ + 34, + 35, + ], + "type": "Punctuator", + "value": ")", + }, + Object { + "loc": Object { + "end": Object { + "column": 37, + "line": 1, + }, + "start": Object { + "column": 36, + "line": 1, + }, + }, + "range": Array [ + 36, + 37, + ], + "type": "Punctuator", + "value": "{", + }, + Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 2, + }, + "start": Object { + "column": 2, + "line": 2, + }, + }, + "range": Array [ + 40, + 43, + ], + "type": "Identifier", + "value": "one", + }, + Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 2, + }, + "start": Object { + "column": 5, + "line": 2, + }, + }, + "range": Array [ + 43, + 45, + ], + "type": "Punctuator", + "value": "?.", + }, + Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 2, + }, + "start": Object { + "column": 7, + "line": 2, + }, + }, + "range": Array [ + 45, + 46, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 13, + "line": 2, + }, + "start": Object { + "column": 8, + "line": 2, + }, + }, + "range": Array [ + 46, + 51, + ], + "type": "String", + "value": "'two'", + }, + Object { + "loc": Object { + "end": Object { + "column": 14, + "line": 2, + }, + "start": Object { + "column": 13, + "line": 2, + }, + }, + "range": Array [ + 51, + 52, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 15, + "line": 2, + }, + "start": Object { + "column": 14, + "line": 2, + }, + }, + "range": Array [ + 52, + 53, + ], + "type": "Punctuator", + "value": "!", + }, + Object { + "loc": Object { + "end": Object { + "column": 16, + "line": 2, + }, + "start": Object { + "column": 15, + "line": 2, + }, + }, + "range": Array [ + 53, + 54, + ], + "type": "Punctuator", + "value": ".", + }, + Object { + "loc": Object { + "end": Object { + "column": 21, + "line": 2, + }, + "start": Object { + "column": 16, + "line": 2, + }, + }, + "range": Array [ + 54, + 59, + ], + "type": "Identifier", + "value": "three", + }, + Object { + "loc": Object { + "end": Object { + "column": 22, + "line": 2, + }, + "start": Object { + "column": 21, + "line": 2, + }, + }, + "range": Array [ + 59, + 60, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 3, + "line": 3, + }, + "start": Object { + "column": 2, + "line": 3, + }, + }, + "range": Array [ + 63, + 64, + ], + "type": "Punctuator", + "value": "(", + }, + Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 3, + }, + "start": Object { + "column": 3, + "line": 3, + }, + }, + "range": Array [ + 64, + 67, + ], + "type": "Identifier", + "value": "one", + }, + Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 3, + }, + "start": Object { + "column": 6, + "line": 3, + }, + }, + "range": Array [ + 67, + 69, + ], + "type": "Punctuator", + "value": "?.", + }, + Object { + "loc": Object { + "end": Object { + "column": 9, + "line": 3, + }, + "start": Object { + "column": 8, + "line": 3, + }, + }, + "range": Array [ + 69, + 70, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 14, + "line": 3, + }, + "start": Object { + "column": 9, + "line": 3, + }, + }, + "range": Array [ + 70, + 75, + ], + "type": "String", + "value": "'two'", + }, + Object { + "loc": Object { + "end": Object { + "column": 15, + "line": 3, + }, + "start": Object { + "column": 14, + "line": 3, + }, + }, + "range": Array [ + 75, + 76, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 16, + "line": 3, + }, + "start": Object { + "column": 15, + "line": 3, + }, + }, + "range": Array [ + 76, + 77, + ], + "type": "Punctuator", + "value": ")", + }, + Object { + "loc": Object { + "end": Object { + "column": 17, + "line": 3, + }, + "start": Object { + "column": 16, + "line": 3, + }, + }, + "range": Array [ + 77, + 78, + ], + "type": "Punctuator", + "value": "!", + }, + Object { + "loc": Object { + "end": Object { + "column": 18, + "line": 3, + }, + "start": Object { + "column": 17, + "line": 3, + }, + }, + "range": Array [ + 78, + 79, + ], + "type": "Punctuator", + "value": ".", + }, + Object { + "loc": Object { + "end": Object { + "column": 23, + "line": 3, + }, + "start": Object { + "column": 18, + "line": 3, + }, + }, + "range": Array [ + 79, + 84, + ], + "type": "Identifier", + "value": "three", + }, + Object { + "loc": Object { + "end": Object { + "column": 24, + "line": 3, + }, + "start": Object { + "column": 23, + "line": 3, + }, + }, + "range": Array [ + 84, + 85, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 3, + "line": 4, + }, + "start": Object { + "column": 2, + "line": 4, + }, + }, + "range": Array [ + 88, + 89, + ], + "type": "Punctuator", + "value": "(", + }, + Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 4, + }, + "start": Object { + "column": 3, + "line": 4, + }, + }, + "range": Array [ + 89, + 92, + ], + "type": "Identifier", + "value": "one", + }, + Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 4, + }, + "start": Object { + "column": 6, + "line": 4, + }, + }, + "range": Array [ + 92, + 94, + ], + "type": "Punctuator", + "value": "?.", + }, + Object { + "loc": Object { + "end": Object { + "column": 9, + "line": 4, + }, + "start": Object { + "column": 8, + "line": 4, + }, + }, + "range": Array [ + 94, + 95, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 14, + "line": 4, + }, + "start": Object { + "column": 9, + "line": 4, + }, + }, + "range": Array [ + 95, + 100, + ], + "type": "String", + "value": "'two'", + }, + Object { + "loc": Object { + "end": Object { + "column": 15, + "line": 4, + }, + "start": Object { + "column": 14, + "line": 4, + }, + }, + "range": Array [ + 100, + 101, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 16, + "line": 4, + }, + "start": Object { + "column": 15, + "line": 4, + }, + }, + "range": Array [ + 101, + 102, + ], + "type": "Punctuator", + "value": "!", + }, + Object { + "loc": Object { + "end": Object { + "column": 17, + "line": 4, + }, + "start": Object { + "column": 16, + "line": 4, + }, + }, + "range": Array [ + 102, + 103, + ], + "type": "Punctuator", + "value": ")", + }, + Object { + "loc": Object { + "end": Object { + "column": 18, + "line": 4, + }, + "start": Object { + "column": 17, + "line": 4, + }, + }, + "range": Array [ + 103, + 104, + ], + "type": "Punctuator", + "value": ".", + }, + Object { + "loc": Object { + "end": Object { + "column": 23, + "line": 4, + }, + "start": Object { + "column": 18, + "line": 4, + }, + }, + "range": Array [ + 104, + 109, + ], + "type": "Identifier", + "value": "three", + }, + Object { + "loc": Object { + "end": Object { + "column": 24, + "line": 4, + }, + "start": Object { + "column": 23, + "line": 4, + }, + }, + "range": Array [ + 109, + 110, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 5, + }, + "start": Object { + "column": 2, + "line": 5, + }, + }, + "range": Array [ + 113, + 116, + ], + "type": "Identifier", + "value": "one", + }, + Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 5, + }, + "start": Object { + "column": 5, + "line": 5, + }, + }, + "range": Array [ + 116, + 118, + ], + "type": "Punctuator", + "value": "?.", + }, + Object { + "loc": Object { + "end": Object { + "column": 10, + "line": 5, + }, + "start": Object { + "column": 7, + "line": 5, + }, + }, + "range": Array [ + 118, + 121, + ], + "type": "Identifier", + "value": "two", + }, + Object { + "loc": Object { + "end": Object { + "column": 11, + "line": 5, + }, + "start": Object { + "column": 10, + "line": 5, + }, + }, + "range": Array [ + 121, + 122, + ], + "type": "Punctuator", + "value": "!", + }, + Object { + "loc": Object { + "end": Object { + "column": 12, + "line": 5, + }, + "start": Object { + "column": 11, + "line": 5, + }, + }, + "range": Array [ + 122, + 123, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 19, + "line": 5, + }, + "start": Object { + "column": 12, + "line": 5, + }, + }, + "range": Array [ + 123, + 130, + ], + "type": "String", + "value": "'three'", + }, + Object { + "loc": Object { + "end": Object { + "column": 20, + "line": 5, + }, + "start": Object { + "column": 19, + "line": 5, + }, + }, + "range": Array [ + 130, + 131, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 21, + "line": 5, + }, + "start": Object { + "column": 20, + "line": 5, + }, + }, + "range": Array [ + 131, + 132, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 3, + "line": 6, + }, + "start": Object { + "column": 2, + "line": 6, + }, + }, + "range": Array [ + 135, + 136, + ], + "type": "Punctuator", + "value": "(", + }, + Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 6, + }, + "start": Object { + "column": 3, + "line": 6, + }, + }, + "range": Array [ + 136, + 139, + ], + "type": "Identifier", + "value": "one", + }, + Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 6, + }, + "start": Object { + "column": 6, + "line": 6, + }, + }, + "range": Array [ + 139, + 141, + ], + "type": "Punctuator", + "value": "?.", + }, + Object { + "loc": Object { + "end": Object { + "column": 11, + "line": 6, + }, + "start": Object { + "column": 8, + "line": 6, + }, + }, + "range": Array [ + 141, + 144, + ], + "type": "Identifier", + "value": "two", + }, + Object { + "loc": Object { + "end": Object { + "column": 12, + "line": 6, + }, + "start": Object { + "column": 11, + "line": 6, + }, + }, + "range": Array [ + 144, + 145, + ], + "type": "Punctuator", + "value": ")", + }, + Object { + "loc": Object { + "end": Object { + "column": 13, + "line": 6, + }, + "start": Object { + "column": 12, + "line": 6, + }, + }, + "range": Array [ + 145, + 146, + ], + "type": "Punctuator", + "value": "!", + }, + Object { + "loc": Object { + "end": Object { + "column": 14, + "line": 6, + }, + "start": Object { + "column": 13, + "line": 6, + }, + }, + "range": Array [ + 146, + 147, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 21, + "line": 6, + }, + "start": Object { + "column": 14, + "line": 6, + }, + }, + "range": Array [ + 147, + 154, + ], + "type": "String", + "value": "'three'", + }, + Object { + "loc": Object { + "end": Object { + "column": 22, + "line": 6, + }, + "start": Object { + "column": 21, + "line": 6, + }, + }, + "range": Array [ + 154, + 155, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 23, + "line": 6, + }, + "start": Object { + "column": 22, + "line": 6, + }, + }, + "range": Array [ + 155, + 156, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 3, + "line": 7, + }, + "start": Object { + "column": 2, + "line": 7, + }, + }, + "range": Array [ + 159, + 160, + ], + "type": "Punctuator", + "value": "(", + }, + Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 7, + }, + "start": Object { + "column": 3, + "line": 7, + }, + }, + "range": Array [ + 160, + 163, + ], + "type": "Identifier", + "value": "one", + }, + Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 7, + }, + "start": Object { + "column": 6, + "line": 7, + }, + }, + "range": Array [ + 163, + 165, + ], + "type": "Punctuator", + "value": "?.", + }, + Object { + "loc": Object { + "end": Object { + "column": 11, + "line": 7, + }, + "start": Object { + "column": 8, + "line": 7, + }, + }, + "range": Array [ + 165, + 168, + ], + "type": "Identifier", + "value": "two", + }, + Object { + "loc": Object { + "end": Object { + "column": 12, + "line": 7, + }, + "start": Object { + "column": 11, + "line": 7, + }, + }, + "range": Array [ + 168, + 169, + ], + "type": "Punctuator", + "value": "!", + }, + Object { + "loc": Object { + "end": Object { + "column": 13, + "line": 7, + }, + "start": Object { + "column": 12, + "line": 7, + }, + }, + "range": Array [ + 169, + 170, + ], + "type": "Punctuator", + "value": ")", + }, + Object { + "loc": Object { + "end": Object { + "column": 14, + "line": 7, + }, + "start": Object { + "column": 13, + "line": 7, + }, + }, + "range": Array [ + 170, + 171, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 21, + "line": 7, + }, + "start": Object { + "column": 14, + "line": 7, + }, + }, + "range": Array [ + 171, + 178, + ], + "type": "String", + "value": "'three'", + }, + Object { + "loc": Object { + "end": Object { + "column": 22, + "line": 7, + }, + "start": Object { + "column": 21, + "line": 7, + }, + }, + "range": Array [ + 178, + 179, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 23, + "line": 7, + }, + "start": Object { + "column": 22, + "line": 7, + }, + }, + "range": Array [ + 179, + 180, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 1, + "line": 8, + }, + "start": Object { + "column": 0, + "line": 8, + }, + }, + "range": Array [ + 181, + 182, + ], + "type": "Punctuator", + "value": "}", + }, + ], + "type": "Program", +} +`; + +exports[`typescript fixtures/basics/optional-chain-element-access-with-parens.src 1`] = ` +Object { + "body": Array [ + Object { + "async": false, + "body": Object { + "body": Array [ + Object { + "expression": Object { + "computed": true, + "loc": Object { + "end": Object { + "column": 11, + "line": 2, + }, + "start": Object { + "column": 3, + "line": 2, + }, + }, + "object": Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 2, + }, + "start": Object { + "column": 3, + "line": 2, + }, + }, + "name": "one", + "range": Array [ + 54, + 57, + ], + "type": "Identifier", + }, + "optional": true, + "property": Object { + "loc": Object { + "end": Object { + "column": 10, + "line": 2, + }, + "start": Object { + "column": 9, + "line": 2, + }, + }, + "range": Array [ + 60, + 61, + ], + "raw": "2", + "type": "Literal", + "value": 2, + }, + "range": Array [ + 54, + 62, + ], + "type": "OptionalMemberExpression", + }, + "loc": Object { + "end": Object { + "column": 13, + "line": 2, + }, + "start": Object { + "column": 2, + "line": 2, + }, + }, + "range": Array [ + 53, + 64, + ], + "type": "ExpressionStatement", + }, + Object { + "expression": Object { + "computed": true, + "loc": Object { + "end": Object { + "column": 15, + "line": 3, + }, + "start": Object { + "column": 2, + "line": 3, + }, + }, + "object": Object { + "computed": true, + "loc": Object { + "end": Object { + "column": 11, + "line": 3, + }, + "start": Object { + "column": 3, + "line": 3, + }, + }, + "object": Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 3, + }, + "start": Object { + "column": 3, + "line": 3, + }, + }, + "name": "one", + "range": Array [ + 68, + 71, + ], + "type": "Identifier", + }, + "optional": true, + "property": Object { + "loc": Object { + "end": Object { + "column": 10, + "line": 3, + }, + "start": Object { + "column": 9, + "line": 3, + }, + }, + "range": Array [ + 74, + 75, + ], + "raw": "2", + "type": "Literal", + "value": 2, + }, + "range": Array [ + 68, + 76, + ], + "type": "OptionalMemberExpression", + }, + "optional": false, + "property": Object { + "loc": Object { + "end": Object { + "column": 14, + "line": 3, + }, + "start": Object { + "column": 13, + "line": 3, + }, + }, + "range": Array [ + 78, + 79, + ], + "raw": "3", + "type": "Literal", + "value": 3, + }, + "range": Array [ + 67, + 80, + ], + "type": "MemberExpression", + }, + "loc": Object { + "end": Object { + "column": 16, + "line": 3, + }, + "start": Object { + "column": 2, + "line": 3, + }, + }, + "range": Array [ + 67, + 81, + ], + "type": "ExpressionStatement", + }, + Object { + "expression": Object { + "computed": true, + "loc": Object { + "end": Object { + "column": 14, + "line": 4, + }, + "start": Object { + "column": 3, + "line": 4, + }, + }, + "object": Object { + "computed": true, + "loc": Object { + "end": Object { + "column": 9, + "line": 4, + }, + "start": Object { + "column": 3, + "line": 4, + }, + }, + "object": Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 4, + }, + "start": Object { + "column": 3, + "line": 4, + }, + }, + "name": "one", + "range": Array [ + 85, + 88, + ], "type": "Identifier", }, "optional": false, @@ -91222,187 +95447,853 @@ Object { "line": 7, }, }, - "range": Array [ - 143, - 165, - ], - "type": "ExpressionStatement", - }, - ], - "loc": Object { - "end": Object { - "column": 1, - "line": 8, - }, - "start": Object { - "column": 49, - "line": 1, + "range": Array [ + 143, + 165, + ], + "type": "ExpressionStatement", + }, + ], + "loc": Object { + "end": Object { + "column": 1, + "line": 8, + }, + "start": Object { + "column": 49, + "line": 1, + }, + }, + "range": Array [ + 49, + 167, + ], + "type": "BlockStatement", + }, + "expression": false, + "generator": false, + "id": Object { + "loc": Object { + "end": Object { + "column": 37, + "line": 1, + }, + "start": Object { + "column": 9, + "line": 1, + }, + }, + "name": "processOptionalElementParens", + "range": Array [ + 9, + 37, + ], + "type": "Identifier", + }, + "loc": Object { + "end": Object { + "column": 1, + "line": 8, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "params": Array [ + Object { + "loc": Object { + "end": Object { + "column": 47, + "line": 1, + }, + "start": Object { + "column": 38, + "line": 1, + }, + }, + "name": "one", + "optional": true, + "range": Array [ + 38, + 47, + ], + "type": "Identifier", + "typeAnnotation": Object { + "loc": Object { + "end": Object { + "column": 47, + "line": 1, + }, + "start": Object { + "column": 42, + "line": 1, + }, + }, + "range": Array [ + 42, + 47, + ], + "type": "TSTypeAnnotation", + "typeAnnotation": Object { + "loc": Object { + "end": Object { + "column": 47, + "line": 1, + }, + "start": Object { + "column": 44, + "line": 1, + }, + }, + "range": Array [ + 44, + 47, + ], + "type": "TSAnyKeyword", + }, }, }, - "range": Array [ - 49, - 167, - ], - "type": "BlockStatement", + ], + "range": Array [ + 0, + 167, + ], + "type": "FunctionDeclaration", + }, + ], + "loc": Object { + "end": Object { + "column": 0, + "line": 9, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "range": Array [ + 0, + 168, + ], + "sourceType": "script", + "tokens": Array [ + Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 1, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "range": Array [ + 0, + 8, + ], + "type": "Keyword", + "value": "function", + }, + Object { + "loc": Object { + "end": Object { + "column": 37, + "line": 1, + }, + "start": Object { + "column": 9, + "line": 1, + }, + }, + "range": Array [ + 9, + 37, + ], + "type": "Identifier", + "value": "processOptionalElementParens", + }, + Object { + "loc": Object { + "end": Object { + "column": 38, + "line": 1, + }, + "start": Object { + "column": 37, + "line": 1, + }, + }, + "range": Array [ + 37, + 38, + ], + "type": "Punctuator", + "value": "(", + }, + Object { + "loc": Object { + "end": Object { + "column": 41, + "line": 1, + }, + "start": Object { + "column": 38, + "line": 1, + }, + }, + "range": Array [ + 38, + 41, + ], + "type": "Identifier", + "value": "one", + }, + Object { + "loc": Object { + "end": Object { + "column": 42, + "line": 1, + }, + "start": Object { + "column": 41, + "line": 1, + }, + }, + "range": Array [ + 41, + 42, + ], + "type": "Punctuator", + "value": "?", + }, + Object { + "loc": Object { + "end": Object { + "column": 43, + "line": 1, + }, + "start": Object { + "column": 42, + "line": 1, + }, + }, + "range": Array [ + 42, + 43, + ], + "type": "Punctuator", + "value": ":", + }, + Object { + "loc": Object { + "end": Object { + "column": 47, + "line": 1, + }, + "start": Object { + "column": 44, + "line": 1, + }, + }, + "range": Array [ + 44, + 47, + ], + "type": "Identifier", + "value": "any", + }, + Object { + "loc": Object { + "end": Object { + "column": 48, + "line": 1, + }, + "start": Object { + "column": 47, + "line": 1, + }, + }, + "range": Array [ + 47, + 48, + ], + "type": "Punctuator", + "value": ")", + }, + Object { + "loc": Object { + "end": Object { + "column": 50, + "line": 1, + }, + "start": Object { + "column": 49, + "line": 1, + }, + }, + "range": Array [ + 49, + 50, + ], + "type": "Punctuator", + "value": "{", + }, + Object { + "loc": Object { + "end": Object { + "column": 3, + "line": 2, + }, + "start": Object { + "column": 2, + "line": 2, + }, + }, + "range": Array [ + 53, + 54, + ], + "type": "Punctuator", + "value": "(", + }, + Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 2, + }, + "start": Object { + "column": 3, + "line": 2, + }, + }, + "range": Array [ + 54, + 57, + ], + "type": "Identifier", + "value": "one", + }, + Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 2, + }, + "start": Object { + "column": 6, + "line": 2, + }, + }, + "range": Array [ + 57, + 59, + ], + "type": "Punctuator", + "value": "?.", + }, + Object { + "loc": Object { + "end": Object { + "column": 9, + "line": 2, + }, + "start": Object { + "column": 8, + "line": 2, + }, + }, + "range": Array [ + 59, + 60, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 10, + "line": 2, + }, + "start": Object { + "column": 9, + "line": 2, + }, + }, + "range": Array [ + 60, + 61, + ], + "type": "Numeric", + "value": "2", + }, + Object { + "loc": Object { + "end": Object { + "column": 11, + "line": 2, + }, + "start": Object { + "column": 10, + "line": 2, + }, + }, + "range": Array [ + 61, + 62, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 12, + "line": 2, + }, + "start": Object { + "column": 11, + "line": 2, + }, + }, + "range": Array [ + 62, + 63, + ], + "type": "Punctuator", + "value": ")", + }, + Object { + "loc": Object { + "end": Object { + "column": 13, + "line": 2, + }, + "start": Object { + "column": 12, + "line": 2, + }, + }, + "range": Array [ + 63, + 64, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 3, + "line": 3, + }, + "start": Object { + "column": 2, + "line": 3, + }, + }, + "range": Array [ + 67, + 68, + ], + "type": "Punctuator", + "value": "(", + }, + Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 3, + }, + "start": Object { + "column": 3, + "line": 3, + }, + }, + "range": Array [ + 68, + 71, + ], + "type": "Identifier", + "value": "one", + }, + Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 3, + }, + "start": Object { + "column": 6, + "line": 3, + }, + }, + "range": Array [ + 71, + 73, + ], + "type": "Punctuator", + "value": "?.", + }, + Object { + "loc": Object { + "end": Object { + "column": 9, + "line": 3, + }, + "start": Object { + "column": 8, + "line": 3, + }, + }, + "range": Array [ + 73, + 74, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 10, + "line": 3, + }, + "start": Object { + "column": 9, + "line": 3, + }, + }, + "range": Array [ + 74, + 75, + ], + "type": "Numeric", + "value": "2", + }, + Object { + "loc": Object { + "end": Object { + "column": 11, + "line": 3, + }, + "start": Object { + "column": 10, + "line": 3, + }, + }, + "range": Array [ + 75, + 76, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 12, + "line": 3, + }, + "start": Object { + "column": 11, + "line": 3, + }, + }, + "range": Array [ + 76, + 77, + ], + "type": "Punctuator", + "value": ")", + }, + Object { + "loc": Object { + "end": Object { + "column": 13, + "line": 3, + }, + "start": Object { + "column": 12, + "line": 3, + }, + }, + "range": Array [ + 77, + 78, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 14, + "line": 3, + }, + "start": Object { + "column": 13, + "line": 3, + }, + }, + "range": Array [ + 78, + 79, + ], + "type": "Numeric", + "value": "3", + }, + Object { + "loc": Object { + "end": Object { + "column": 15, + "line": 3, + }, + "start": Object { + "column": 14, + "line": 3, + }, }, - "expression": false, - "generator": false, - "id": Object { - "loc": Object { - "end": Object { - "column": 37, - "line": 1, - }, - "start": Object { - "column": 9, - "line": 1, - }, + "range": Array [ + 79, + 80, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 16, + "line": 3, + }, + "start": Object { + "column": 15, + "line": 3, }, - "name": "processOptionalElementParens", - "range": Array [ - 9, - 37, - ], - "type": "Identifier", }, + "range": Array [ + 80, + 81, + ], + "type": "Punctuator", + "value": ";", + }, + Object { "loc": Object { "end": Object { - "column": 1, - "line": 8, + "column": 3, + "line": 4, }, "start": Object { - "column": 0, - "line": 1, + "column": 2, + "line": 4, }, }, - "params": Array [ - Object { - "loc": Object { - "end": Object { - "column": 47, - "line": 1, - }, - "start": Object { - "column": 38, - "line": 1, - }, - }, - "name": "one", - "optional": true, - "range": Array [ - 38, - 47, - ], - "type": "Identifier", - "typeAnnotation": Object { - "loc": Object { - "end": Object { - "column": 47, - "line": 1, - }, - "start": Object { - "column": 42, - "line": 1, - }, - }, - "range": Array [ - 42, - 47, - ], - "type": "TSTypeAnnotation", - "typeAnnotation": Object { - "loc": Object { - "end": Object { - "column": 47, - "line": 1, - }, - "start": Object { - "column": 44, - "line": 1, - }, - }, - "range": Array [ - 44, - 47, - ], - "type": "TSAnyKeyword", - }, - }, + "range": Array [ + 84, + 85, + ], + "type": "Punctuator", + "value": "(", + }, + Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 4, + }, + "start": Object { + "column": 3, + "line": 4, + }, + }, + "range": Array [ + 85, + 88, + ], + "type": "Identifier", + "value": "one", + }, + Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 4, + }, + "start": Object { + "column": 6, + "line": 4, + }, + }, + "range": Array [ + 88, + 89, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 4, + }, + "start": Object { + "column": 7, + "line": 4, + }, + }, + "range": Array [ + 89, + 90, + ], + "type": "Numeric", + "value": "2", + }, + Object { + "loc": Object { + "end": Object { + "column": 9, + "line": 4, + }, + "start": Object { + "column": 8, + "line": 4, + }, + }, + "range": Array [ + 90, + 91, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 11, + "line": 4, + }, + "start": Object { + "column": 9, + "line": 4, + }, + }, + "range": Array [ + 91, + 93, + ], + "type": "Punctuator", + "value": "?.", + }, + Object { + "loc": Object { + "end": Object { + "column": 12, + "line": 4, + }, + "start": Object { + "column": 11, + "line": 4, + }, + }, + "range": Array [ + 93, + 94, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 13, + "line": 4, + }, + "start": Object { + "column": 12, + "line": 4, + }, + }, + "range": Array [ + 94, + 95, + ], + "type": "Numeric", + "value": "3", + }, + Object { + "loc": Object { + "end": Object { + "column": 14, + "line": 4, + }, + "start": Object { + "column": 13, + "line": 4, }, - ], + }, "range": Array [ - 0, - 167, + 95, + 96, ], - "type": "FunctionDeclaration", - }, - ], - "loc": Object { - "end": Object { - "column": 0, - "line": 9, - }, - "start": Object { - "column": 0, - "line": 1, + "type": "Punctuator", + "value": "]", }, - }, - "range": Array [ - 0, - 168, - ], - "sourceType": "script", - "tokens": Array [ Object { "loc": Object { "end": Object { - "column": 8, - "line": 1, + "column": 15, + "line": 4, }, "start": Object { - "column": 0, - "line": 1, + "column": 14, + "line": 4, }, }, "range": Array [ - 0, - 8, + 96, + 97, ], - "type": "Keyword", - "value": "function", + "type": "Punctuator", + "value": ")", }, Object { "loc": Object { "end": Object { - "column": 37, - "line": 1, + "column": 16, + "line": 4, }, "start": Object { - "column": 9, - "line": 1, + "column": 15, + "line": 4, }, }, "range": Array [ - 9, - 37, + 97, + 98, ], - "type": "Identifier", - "value": "processOptionalElementParens", + "type": "Punctuator", + "value": ";", }, Object { "loc": Object { "end": Object { - "column": 38, - "line": 1, + "column": 3, + "line": 5, }, "start": Object { - "column": 37, - "line": 1, + "column": 2, + "line": 5, }, }, "range": Array [ - 37, - 38, + 101, + 102, ], "type": "Punctuator", "value": "(", @@ -91410,17 +96301,17 @@ Object { Object { "loc": Object { "end": Object { - "column": 41, - "line": 1, + "column": 6, + "line": 5, }, "start": Object { - "column": 38, - "line": 1, + "column": 3, + "line": 5, }, }, "range": Array [ - 38, - 41, + 102, + 105, ], "type": "Identifier", "value": "one", @@ -91428,161 +96319,161 @@ Object { Object { "loc": Object { "end": Object { - "column": 42, - "line": 1, + "column": 7, + "line": 5, }, "start": Object { - "column": 41, - "line": 1, + "column": 6, + "line": 5, }, }, "range": Array [ - 41, - 42, + 105, + 106, ], "type": "Punctuator", - "value": "?", + "value": "[", }, Object { "loc": Object { "end": Object { - "column": 43, - "line": 1, + "column": 8, + "line": 5, }, "start": Object { - "column": 42, - "line": 1, + "column": 7, + "line": 5, }, }, "range": Array [ - 42, - 43, + 106, + 107, ], - "type": "Punctuator", - "value": ":", + "type": "Numeric", + "value": "2", }, Object { "loc": Object { "end": Object { - "column": 47, - "line": 1, + "column": 9, + "line": 5, }, "start": Object { - "column": 44, - "line": 1, + "column": 8, + "line": 5, }, }, "range": Array [ - 44, - 47, + 107, + 108, ], - "type": "Identifier", - "value": "any", + "type": "Punctuator", + "value": "]", }, Object { "loc": Object { "end": Object { - "column": 48, - "line": 1, + "column": 11, + "line": 5, }, "start": Object { - "column": 47, - "line": 1, + "column": 9, + "line": 5, }, }, "range": Array [ - 47, - 48, + 108, + 110, ], "type": "Punctuator", - "value": ")", + "value": "?.", }, Object { "loc": Object { "end": Object { - "column": 50, - "line": 1, + "column": 12, + "line": 5, }, "start": Object { - "column": 49, - "line": 1, + "column": 11, + "line": 5, }, }, "range": Array [ - 49, - 50, + 110, + 111, ], "type": "Punctuator", - "value": "{", + "value": "[", }, Object { "loc": Object { "end": Object { - "column": 3, - "line": 2, + "column": 13, + "line": 5, }, "start": Object { - "column": 2, - "line": 2, + "column": 12, + "line": 5, }, }, "range": Array [ - 53, - 54, + 111, + 112, ], - "type": "Punctuator", - "value": "(", + "type": "Numeric", + "value": "3", }, Object { "loc": Object { "end": Object { - "column": 6, - "line": 2, + "column": 14, + "line": 5, }, "start": Object { - "column": 3, - "line": 2, + "column": 13, + "line": 5, }, }, "range": Array [ - 54, - 57, + 112, + 113, ], - "type": "Identifier", - "value": "one", + "type": "Punctuator", + "value": "]", }, Object { "loc": Object { "end": Object { - "column": 8, - "line": 2, + "column": 15, + "line": 5, }, "start": Object { - "column": 6, - "line": 2, + "column": 14, + "line": 5, }, }, "range": Array [ - 57, - 59, + 113, + 114, ], "type": "Punctuator", - "value": "?.", + "value": ")", }, Object { "loc": Object { "end": Object { - "column": 9, - "line": 2, + "column": 16, + "line": 5, }, "start": Object { - "column": 8, - "line": 2, + "column": 15, + "line": 5, }, }, "range": Array [ - 59, - 60, + 114, + 115, ], "type": "Punctuator", "value": "[", @@ -91590,125 +96481,161 @@ Object { Object { "loc": Object { "end": Object { - "column": 10, - "line": 2, + "column": 17, + "line": 5, + }, + "start": Object { + "column": 16, + "line": 5, + }, + }, + "range": Array [ + 115, + 116, + ], + "type": "Numeric", + "value": "4", + }, + Object { + "loc": Object { + "end": Object { + "column": 18, + "line": 5, + }, + "start": Object { + "column": 17, + "line": 5, + }, + }, + "range": Array [ + 116, + 117, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 19, + "line": 5, }, "start": Object { - "column": 9, - "line": 2, + "column": 18, + "line": 5, }, }, "range": Array [ - 60, - 61, + 117, + 118, ], - "type": "Numeric", - "value": "2", + "type": "Punctuator", + "value": ";", }, Object { "loc": Object { "end": Object { - "column": 11, - "line": 2, + "column": 3, + "line": 6, }, "start": Object { - "column": 10, - "line": 2, + "column": 2, + "line": 6, }, }, "range": Array [ - 61, - 62, + 121, + 122, ], "type": "Punctuator", - "value": "]", + "value": "(", }, Object { "loc": Object { "end": Object { - "column": 12, - "line": 2, + "column": 6, + "line": 6, }, "start": Object { - "column": 11, - "line": 2, + "column": 3, + "line": 6, }, }, "range": Array [ - 62, - 63, + 122, + 125, ], - "type": "Punctuator", - "value": ")", + "type": "Identifier", + "value": "one", }, Object { "loc": Object { "end": Object { - "column": 13, - "line": 2, + "column": 7, + "line": 6, }, "start": Object { - "column": 12, - "line": 2, + "column": 6, + "line": 6, }, }, "range": Array [ - 63, - 64, + 125, + 126, ], "type": "Punctuator", - "value": ";", + "value": "[", }, Object { "loc": Object { "end": Object { - "column": 3, - "line": 3, + "column": 8, + "line": 6, }, "start": Object { - "column": 2, - "line": 3, + "column": 7, + "line": 6, }, }, "range": Array [ - 67, - 68, + 126, + 127, ], - "type": "Punctuator", - "value": "(", + "type": "Numeric", + "value": "2", }, Object { "loc": Object { "end": Object { - "column": 6, - "line": 3, + "column": 9, + "line": 6, }, "start": Object { - "column": 3, - "line": 3, + "column": 8, + "line": 6, }, }, "range": Array [ - 68, - 71, + 127, + 128, ], - "type": "Identifier", - "value": "one", + "type": "Punctuator", + "value": "]", }, Object { "loc": Object { "end": Object { - "column": 8, - "line": 3, + "column": 11, + "line": 6, }, "start": Object { - "column": 6, - "line": 3, + "column": 9, + "line": 6, }, }, "range": Array [ - 71, - 73, + 128, + 130, ], "type": "Punctuator", "value": "?.", @@ -91716,17 +96643,17 @@ Object { Object { "loc": Object { "end": Object { - "column": 9, - "line": 3, + "column": 12, + "line": 6, }, "start": Object { - "column": 8, - "line": 3, + "column": 11, + "line": 6, }, }, "range": Array [ - 73, - 74, + 130, + 131, ], "type": "Punctuator", "value": "[", @@ -91734,35 +96661,35 @@ Object { Object { "loc": Object { "end": Object { - "column": 10, - "line": 3, + "column": 13, + "line": 6, }, "start": Object { - "column": 9, - "line": 3, + "column": 12, + "line": 6, }, }, "range": Array [ - 74, - 75, + 131, + 132, ], "type": "Numeric", - "value": "2", + "value": "3", }, Object { "loc": Object { "end": Object { - "column": 11, - "line": 3, + "column": 14, + "line": 6, }, "start": Object { - "column": 10, - "line": 3, + "column": 13, + "line": 6, }, }, "range": Array [ - 75, - 76, + 132, + 133, ], "type": "Punctuator", "value": "]", @@ -91770,35 +96697,35 @@ Object { Object { "loc": Object { "end": Object { - "column": 12, - "line": 3, + "column": 16, + "line": 6, }, "start": Object { - "column": 11, - "line": 3, + "column": 14, + "line": 6, }, }, "range": Array [ - 76, - 77, + 133, + 135, ], "type": "Punctuator", - "value": ")", + "value": "?.", }, Object { "loc": Object { "end": Object { - "column": 13, - "line": 3, + "column": 17, + "line": 6, }, "start": Object { - "column": 12, - "line": 3, + "column": 16, + "line": 6, }, }, "range": Array [ - 77, - 78, + 135, + 136, ], "type": "Punctuator", "value": "[", @@ -91806,35 +96733,35 @@ Object { Object { "loc": Object { "end": Object { - "column": 14, - "line": 3, + "column": 18, + "line": 6, }, "start": Object { - "column": 13, - "line": 3, + "column": 17, + "line": 6, }, }, "range": Array [ - 78, - 79, + 136, + 137, ], "type": "Numeric", - "value": "3", + "value": "4", }, Object { "loc": Object { "end": Object { - "column": 15, - "line": 3, + "column": 19, + "line": 6, }, "start": Object { - "column": 14, - "line": 3, + "column": 18, + "line": 6, }, }, "range": Array [ - 79, - 80, + 137, + 138, ], "type": "Punctuator", "value": "]", @@ -91842,17 +96769,35 @@ Object { Object { "loc": Object { "end": Object { - "column": 16, - "line": 3, + "column": 20, + "line": 6, }, "start": Object { - "column": 15, - "line": 3, + "column": 19, + "line": 6, }, }, "range": Array [ - 80, - 81, + 138, + 139, + ], + "type": "Punctuator", + "value": ")", + }, + Object { + "loc": Object { + "end": Object { + "column": 21, + "line": 6, + }, + "start": Object { + "column": 20, + "line": 6, + }, + }, + "range": Array [ + 139, + 140, ], "type": "Punctuator", "value": ";", @@ -91861,16 +96806,16 @@ Object { "loc": Object { "end": Object { "column": 3, - "line": 4, + "line": 7, }, "start": Object { "column": 2, - "line": 4, + "line": 7, }, }, "range": Array [ - 84, - 85, + 143, + 144, ], "type": "Punctuator", "value": "(", @@ -91879,16 +96824,16 @@ Object { "loc": Object { "end": Object { "column": 6, - "line": 4, + "line": 7, }, "start": Object { "column": 3, - "line": 4, + "line": 7, }, }, "range": Array [ - 85, - 88, + 144, + 147, ], "type": "Identifier", "value": "one", @@ -91897,16 +96842,16 @@ Object { "loc": Object { "end": Object { "column": 7, - "line": 4, + "line": 7, }, "start": Object { "column": 6, - "line": 4, + "line": 7, }, }, "range": Array [ - 88, - 89, + 147, + 148, ], "type": "Punctuator", "value": "[", @@ -91915,16 +96860,16 @@ Object { "loc": Object { "end": Object { "column": 8, - "line": 4, + "line": 7, }, "start": Object { "column": 7, - "line": 4, + "line": 7, }, }, "range": Array [ - 89, - 90, + 148, + 149, ], "type": "Numeric", "value": "2", @@ -91933,16 +96878,16 @@ Object { "loc": Object { "end": Object { "column": 9, - "line": 4, + "line": 7, }, "start": Object { "column": 8, - "line": 4, + "line": 7, }, }, "range": Array [ - 90, - 91, + 149, + 150, ], "type": "Punctuator", "value": "]", @@ -91951,16 +96896,16 @@ Object { "loc": Object { "end": Object { "column": 11, - "line": 4, + "line": 7, }, "start": Object { "column": 9, - "line": 4, + "line": 7, }, }, "range": Array [ - 91, - 93, + 150, + 152, ], "type": "Punctuator", "value": "?.", @@ -91969,16 +96914,16 @@ Object { "loc": Object { "end": Object { "column": 12, - "line": 4, + "line": 7, }, "start": Object { "column": 11, - "line": 4, + "line": 7, }, }, "range": Array [ - 93, - 94, + 152, + 153, ], "type": "Punctuator", "value": "[", @@ -91987,16 +96932,16 @@ Object { "loc": Object { "end": Object { "column": 13, - "line": 4, + "line": 7, }, "start": Object { "column": 12, - "line": 4, + "line": 7, }, }, "range": Array [ - 94, - 95, + 153, + 154, ], "type": "Numeric", "value": "3", @@ -92005,16 +96950,16 @@ Object { "loc": Object { "end": Object { "column": 14, - "line": 4, + "line": 7, }, "start": Object { "column": 13, - "line": 4, + "line": 7, }, }, "range": Array [ - 95, - 96, + 154, + 155, ], "type": "Punctuator", "value": "]", @@ -92022,89 +96967,107 @@ Object { Object { "loc": Object { "end": Object { - "column": 15, - "line": 4, + "column": 16, + "line": 7, }, "start": Object { "column": 14, - "line": 4, + "line": 7, }, }, "range": Array [ - 96, - 97, + 155, + 157, ], "type": "Punctuator", - "value": ")", + "value": "?.", }, Object { "loc": Object { "end": Object { - "column": 16, - "line": 4, + "column": 17, + "line": 7, }, "start": Object { - "column": 15, - "line": 4, + "column": 16, + "line": 7, }, }, "range": Array [ - 97, - 98, + 157, + 158, ], "type": "Punctuator", - "value": ";", + "value": "[", }, Object { "loc": Object { "end": Object { - "column": 3, - "line": 5, + "column": 18, + "line": 7, }, "start": Object { - "column": 2, - "line": 5, + "column": 17, + "line": 7, }, }, "range": Array [ - 101, - 102, + 158, + 159, + ], + "type": "Numeric", + "value": "4", + }, + Object { + "loc": Object { + "end": Object { + "column": 19, + "line": 7, + }, + "start": Object { + "column": 18, + "line": 7, + }, + }, + "range": Array [ + 159, + 160, ], "type": "Punctuator", - "value": "(", + "value": "]", }, Object { "loc": Object { "end": Object { - "column": 6, - "line": 5, + "column": 20, + "line": 7, }, "start": Object { - "column": 3, - "line": 5, + "column": 19, + "line": 7, }, }, "range": Array [ - 102, - 105, + 160, + 161, ], - "type": "Identifier", - "value": "one", + "type": "Punctuator", + "value": ")", }, Object { "loc": Object { "end": Object { - "column": 7, - "line": 5, + "column": 21, + "line": 7, }, "start": Object { - "column": 6, - "line": 5, + "column": 20, + "line": 7, }, }, "range": Array [ - 105, - 106, + 161, + 162, ], "type": "Punctuator", "value": "[", @@ -92112,35 +97075,35 @@ Object { Object { "loc": Object { "end": Object { - "column": 8, - "line": 5, + "column": 22, + "line": 7, }, "start": Object { - "column": 7, - "line": 5, + "column": 21, + "line": 7, }, }, "range": Array [ - 106, - 107, + 162, + 163, ], "type": "Numeric", - "value": "2", + "value": "5", }, Object { "loc": Object { "end": Object { - "column": 9, - "line": 5, + "column": 23, + "line": 7, }, "start": Object { - "column": 8, - "line": 5, + "column": 22, + "line": 7, }, }, "range": Array [ - 107, - 108, + 163, + 164, ], "type": "Punctuator", "value": "]", @@ -92148,179 +97111,604 @@ Object { Object { "loc": Object { "end": Object { - "column": 11, - "line": 5, + "column": 24, + "line": 7, }, "start": Object { - "column": 9, - "line": 5, + "column": 23, + "line": 7, + }, + }, + "range": Array [ + 164, + 165, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 1, + "line": 8, + }, + "start": Object { + "column": 0, + "line": 8, + }, + }, + "range": Array [ + 166, + 167, + ], + "type": "Punctuator", + "value": "}", + }, + ], + "type": "Program", +} +`; + +exports[`typescript fixtures/basics/optional-chain-with-non-null-assertion.src 1`] = ` +Object { + "body": Array [ + Object { + "async": false, + "body": Object { + "body": Array [ + Object { + "expression": Object { + "computed": false, + "loc": Object { + "end": Object { + "column": 17, + "line": 2, + }, + "start": Object { + "column": 2, + "line": 2, + }, + }, + "object": Object { + "expression": Object { + "computed": false, + "loc": Object { + "end": Object { + "column": 10, + "line": 2, + }, + "start": Object { + "column": 2, + "line": 2, + }, + }, + "object": Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 2, + }, + "start": Object { + "column": 2, + "line": 2, + }, + }, + "name": "one", + "range": Array [ + 40, + 43, + ], + "type": "Identifier", + }, + "optional": true, + "property": Object { + "loc": Object { + "end": Object { + "column": 10, + "line": 2, + }, + "start": Object { + "column": 7, + "line": 2, + }, + }, + "name": "two", + "range": Array [ + 45, + 48, + ], + "type": "Identifier", + }, + "range": Array [ + 40, + 48, + ], + "type": "OptionalMemberExpression", + }, + "loc": Object { + "end": Object { + "column": 11, + "line": 2, + }, + "start": Object { + "column": 2, + "line": 2, + }, + }, + "range": Array [ + 40, + 49, + ], + "type": "TSNonNullExpression", + }, + "optional": false, + "property": Object { + "loc": Object { + "end": Object { + "column": 17, + "line": 2, + }, + "start": Object { + "column": 12, + "line": 2, + }, + }, + "name": "three", + "range": Array [ + 50, + 55, + ], + "type": "Identifier", + }, + "range": Array [ + 40, + 55, + ], + "type": "OptionalMemberExpression", + }, + "loc": Object { + "end": Object { + "column": 18, + "line": 2, + }, + "start": Object { + "column": 2, + "line": 2, + }, + }, + "range": Array [ + 40, + 56, + ], + "type": "ExpressionStatement", + }, + Object { + "expression": Object { + "computed": false, + "loc": Object { + "end": Object { + "column": 19, + "line": 3, + }, + "start": Object { + "column": 2, + "line": 3, + }, + }, + "object": Object { + "expression": Object { + "computed": false, + "loc": Object { + "end": Object { + "column": 11, + "line": 3, + }, + "start": Object { + "column": 3, + "line": 3, + }, + }, + "object": Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 3, + }, + "start": Object { + "column": 3, + "line": 3, + }, + }, + "name": "one", + "range": Array [ + 60, + 63, + ], + "type": "Identifier", + }, + "optional": true, + "property": Object { + "loc": Object { + "end": Object { + "column": 11, + "line": 3, + }, + "start": Object { + "column": 8, + "line": 3, + }, + }, + "name": "two", + "range": Array [ + 65, + 68, + ], + "type": "Identifier", + }, + "range": Array [ + 60, + 68, + ], + "type": "OptionalMemberExpression", + }, + "loc": Object { + "end": Object { + "column": 13, + "line": 3, + }, + "start": Object { + "column": 2, + "line": 3, + }, + }, + "range": Array [ + 59, + 70, + ], + "type": "TSNonNullExpression", + }, + "optional": false, + "property": Object { + "loc": Object { + "end": Object { + "column": 19, + "line": 3, + }, + "start": Object { + "column": 14, + "line": 3, + }, + }, + "name": "three", + "range": Array [ + 71, + 76, + ], + "type": "Identifier", + }, + "range": Array [ + 59, + 76, + ], + "type": "MemberExpression", + }, + "loc": Object { + "end": Object { + "column": 20, + "line": 3, + }, + "start": Object { + "column": 2, + "line": 3, + }, + }, + "range": Array [ + 59, + 77, + ], + "type": "ExpressionStatement", + }, + Object { + "expression": Object { + "computed": false, + "loc": Object { + "end": Object { + "column": 19, + "line": 4, + }, + "start": Object { + "column": 2, + "line": 4, + }, + }, + "object": Object { + "expression": Object { + "computed": false, + "loc": Object { + "end": Object { + "column": 11, + "line": 4, + }, + "start": Object { + "column": 3, + "line": 4, + }, + }, + "object": Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 4, + }, + "start": Object { + "column": 3, + "line": 4, + }, + }, + "name": "one", + "range": Array [ + 81, + 84, + ], + "type": "Identifier", + }, + "optional": true, + "property": Object { + "loc": Object { + "end": Object { + "column": 11, + "line": 4, + }, + "start": Object { + "column": 8, + "line": 4, + }, + }, + "name": "two", + "range": Array [ + 86, + 89, + ], + "type": "Identifier", + }, + "range": Array [ + 81, + 89, + ], + "type": "OptionalMemberExpression", + }, + "loc": Object { + "end": Object { + "column": 12, + "line": 4, + }, + "start": Object { + "column": 3, + "line": 4, + }, + }, + "range": Array [ + 81, + 90, + ], + "type": "TSNonNullExpression", + }, + "optional": false, + "property": Object { + "loc": Object { + "end": Object { + "column": 19, + "line": 4, + }, + "start": Object { + "column": 14, + "line": 4, + }, + }, + "name": "three", + "range": Array [ + 92, + 97, + ], + "type": "Identifier", + }, + "range": Array [ + 80, + 97, + ], + "type": "MemberExpression", + }, + "loc": Object { + "end": Object { + "column": 20, + "line": 4, + }, + "start": Object { + "column": 2, + "line": 4, + }, + }, + "range": Array [ + 80, + 98, + ], + "type": "ExpressionStatement", + }, + ], + "loc": Object { + "end": Object { + "column": 1, + "line": 5, + }, + "start": Object { + "column": 36, + "line": 1, + }, }, + "range": Array [ + 36, + 100, + ], + "type": "BlockStatement", }, - "range": Array [ - 108, - 110, - ], - "type": "Punctuator", - "value": "?.", - }, - Object { - "loc": Object { - "end": Object { - "column": 12, - "line": 5, - }, - "start": Object { - "column": 11, - "line": 5, + "expression": false, + "generator": false, + "id": Object { + "loc": Object { + "end": Object { + "column": 24, + "line": 1, + }, + "start": Object { + "column": 9, + "line": 1, + }, }, + "name": "processOptional", + "range": Array [ + 9, + 24, + ], + "type": "Identifier", }, - "range": Array [ - 110, - 111, - ], - "type": "Punctuator", - "value": "[", - }, - Object { "loc": Object { "end": Object { - "column": 13, + "column": 1, "line": 5, }, "start": Object { - "column": 12, - "line": 5, + "column": 0, + "line": 1, }, }, - "range": Array [ - 111, - 112, - ], - "type": "Numeric", - "value": "3", - }, - Object { - "loc": Object { - "end": Object { - "column": 14, - "line": 5, - }, - "start": Object { - "column": 13, - "line": 5, + "params": Array [ + Object { + "loc": Object { + "end": Object { + "column": 34, + "line": 1, + }, + "start": Object { + "column": 25, + "line": 1, + }, + }, + "name": "one", + "optional": true, + "range": Array [ + 25, + 34, + ], + "type": "Identifier", + "typeAnnotation": Object { + "loc": Object { + "end": Object { + "column": 34, + "line": 1, + }, + "start": Object { + "column": 29, + "line": 1, + }, + }, + "range": Array [ + 29, + 34, + ], + "type": "TSTypeAnnotation", + "typeAnnotation": Object { + "loc": Object { + "end": Object { + "column": 34, + "line": 1, + }, + "start": Object { + "column": 31, + "line": 1, + }, + }, + "range": Array [ + 31, + 34, + ], + "type": "TSAnyKeyword", + }, + }, }, - }, - "range": Array [ - 112, - 113, ], - "type": "Punctuator", - "value": "]", - }, - Object { - "loc": Object { - "end": Object { - "column": 15, - "line": 5, - }, - "start": Object { - "column": 14, - "line": 5, - }, - }, "range": Array [ - 113, - 114, + 0, + 100, ], - "type": "Punctuator", - "value": ")", + "type": "FunctionDeclaration", }, - Object { - "loc": Object { - "end": Object { - "column": 16, - "line": 5, - }, - "start": Object { - "column": 15, - "line": 5, - }, - }, - "range": Array [ - 114, - 115, - ], - "type": "Punctuator", - "value": "[", + ], + "loc": Object { + "end": Object { + "column": 0, + "line": 6, }, - Object { - "loc": Object { - "end": Object { - "column": 17, - "line": 5, - }, - "start": Object { - "column": 16, - "line": 5, - }, - }, - "range": Array [ - 115, - 116, - ], - "type": "Numeric", - "value": "4", + "start": Object { + "column": 0, + "line": 1, }, + }, + "range": Array [ + 0, + 101, + ], + "sourceType": "script", + "tokens": Array [ Object { "loc": Object { "end": Object { - "column": 18, - "line": 5, + "column": 8, + "line": 1, }, "start": Object { - "column": 17, - "line": 5, + "column": 0, + "line": 1, }, }, "range": Array [ - 116, - 117, + 0, + 8, ], - "type": "Punctuator", - "value": "]", + "type": "Keyword", + "value": "function", }, Object { "loc": Object { "end": Object { - "column": 19, - "line": 5, + "column": 24, + "line": 1, }, "start": Object { - "column": 18, - "line": 5, + "column": 9, + "line": 1, }, }, "range": Array [ - 117, - 118, + 9, + 24, ], - "type": "Punctuator", - "value": ";", + "type": "Identifier", + "value": "processOptional", }, Object { "loc": Object { "end": Object { - "column": 3, - "line": 6, + "column": 25, + "line": 1, }, "start": Object { - "column": 2, - "line": 6, + "column": 24, + "line": 1, }, }, "range": Array [ - 121, - 122, + 24, + 25, ], "type": "Punctuator", "value": "(", @@ -92328,17 +97716,17 @@ Object { Object { "loc": Object { "end": Object { - "column": 6, - "line": 6, + "column": 28, + "line": 1, }, "start": Object { - "column": 3, - "line": 6, + "column": 25, + "line": 1, }, }, "range": Array [ - 122, - 125, + 25, + 28, ], "type": "Identifier", "value": "one", @@ -92346,143 +97734,125 @@ Object { Object { "loc": Object { "end": Object { - "column": 7, - "line": 6, + "column": 29, + "line": 1, }, "start": Object { - "column": 6, - "line": 6, + "column": 28, + "line": 1, }, }, "range": Array [ - 125, - 126, + 28, + 29, ], "type": "Punctuator", - "value": "[", - }, - Object { - "loc": Object { - "end": Object { - "column": 8, - "line": 6, - }, - "start": Object { - "column": 7, - "line": 6, - }, - }, - "range": Array [ - 126, - 127, - ], - "type": "Numeric", - "value": "2", + "value": "?", }, Object { "loc": Object { "end": Object { - "column": 9, - "line": 6, + "column": 30, + "line": 1, }, "start": Object { - "column": 8, - "line": 6, + "column": 29, + "line": 1, }, }, "range": Array [ - 127, - 128, + 29, + 30, ], "type": "Punctuator", - "value": "]", + "value": ":", }, Object { "loc": Object { "end": Object { - "column": 11, - "line": 6, + "column": 34, + "line": 1, }, "start": Object { - "column": 9, - "line": 6, + "column": 31, + "line": 1, }, }, "range": Array [ - 128, - 130, + 31, + 34, ], - "type": "Punctuator", - "value": "?.", + "type": "Identifier", + "value": "any", }, Object { "loc": Object { "end": Object { - "column": 12, - "line": 6, + "column": 35, + "line": 1, }, "start": Object { - "column": 11, - "line": 6, + "column": 34, + "line": 1, }, }, "range": Array [ - 130, - 131, + 34, + 35, ], "type": "Punctuator", - "value": "[", + "value": ")", }, Object { "loc": Object { "end": Object { - "column": 13, - "line": 6, + "column": 37, + "line": 1, }, "start": Object { - "column": 12, - "line": 6, + "column": 36, + "line": 1, }, }, "range": Array [ - 131, - 132, + 36, + 37, ], - "type": "Numeric", - "value": "3", + "type": "Punctuator", + "value": "{", }, Object { "loc": Object { "end": Object { - "column": 14, - "line": 6, + "column": 5, + "line": 2, }, "start": Object { - "column": 13, - "line": 6, + "column": 2, + "line": 2, }, }, "range": Array [ - 132, - 133, + 40, + 43, ], - "type": "Punctuator", - "value": "]", + "type": "Identifier", + "value": "one", }, Object { "loc": Object { "end": Object { - "column": 16, - "line": 6, + "column": 7, + "line": 2, }, "start": Object { - "column": 14, - "line": 6, + "column": 5, + "line": 2, }, }, "range": Array [ - 133, - 135, + 43, + 45, ], "type": "Punctuator", "value": "?.", @@ -92490,89 +97860,89 @@ Object { Object { "loc": Object { "end": Object { - "column": 17, - "line": 6, + "column": 10, + "line": 2, }, "start": Object { - "column": 16, - "line": 6, + "column": 7, + "line": 2, }, }, "range": Array [ - 135, - 136, + 45, + 48, ], - "type": "Punctuator", - "value": "[", + "type": "Identifier", + "value": "two", }, Object { "loc": Object { "end": Object { - "column": 18, - "line": 6, + "column": 11, + "line": 2, }, "start": Object { - "column": 17, - "line": 6, + "column": 10, + "line": 2, }, }, "range": Array [ - 136, - 137, + 48, + 49, ], - "type": "Numeric", - "value": "4", + "type": "Punctuator", + "value": "!", }, Object { "loc": Object { "end": Object { - "column": 19, - "line": 6, + "column": 12, + "line": 2, }, "start": Object { - "column": 18, - "line": 6, + "column": 11, + "line": 2, }, }, "range": Array [ - 137, - 138, + 49, + 50, ], "type": "Punctuator", - "value": "]", + "value": ".", }, Object { "loc": Object { "end": Object { - "column": 20, - "line": 6, + "column": 17, + "line": 2, }, "start": Object { - "column": 19, - "line": 6, + "column": 12, + "line": 2, }, }, "range": Array [ - 138, - 139, + 50, + 55, ], - "type": "Punctuator", - "value": ")", + "type": "Identifier", + "value": "three", }, Object { "loc": Object { "end": Object { - "column": 21, - "line": 6, + "column": 18, + "line": 2, }, "start": Object { - "column": 20, - "line": 6, + "column": 17, + "line": 2, }, }, "range": Array [ - 139, - 140, + 55, + 56, ], "type": "Punctuator", "value": ";", @@ -92581,16 +97951,16 @@ Object { "loc": Object { "end": Object { "column": 3, - "line": 7, + "line": 3, }, "start": Object { "column": 2, - "line": 7, + "line": 3, }, }, "range": Array [ - 143, - 144, + 59, + 60, ], "type": "Punctuator", "value": "(", @@ -92599,16 +97969,16 @@ Object { "loc": Object { "end": Object { "column": 6, - "line": 7, + "line": 3, }, "start": Object { "column": 3, - "line": 7, + "line": 3, }, }, "range": Array [ - 144, - 147, + 60, + 63, ], "type": "Identifier", "value": "one", @@ -92616,287 +97986,287 @@ Object { Object { "loc": Object { "end": Object { - "column": 7, - "line": 7, + "column": 8, + "line": 3, }, "start": Object { "column": 6, - "line": 7, + "line": 3, }, }, "range": Array [ - 147, - 148, + 63, + 65, ], "type": "Punctuator", - "value": "[", + "value": "?.", }, Object { "loc": Object { "end": Object { - "column": 8, - "line": 7, + "column": 11, + "line": 3, }, "start": Object { - "column": 7, - "line": 7, + "column": 8, + "line": 3, }, }, "range": Array [ - 148, - 149, + 65, + 68, ], - "type": "Numeric", - "value": "2", + "type": "Identifier", + "value": "two", }, Object { "loc": Object { "end": Object { - "column": 9, - "line": 7, + "column": 12, + "line": 3, }, "start": Object { - "column": 8, - "line": 7, + "column": 11, + "line": 3, }, }, "range": Array [ - 149, - 150, + 68, + 69, ], "type": "Punctuator", - "value": "]", + "value": ")", }, Object { "loc": Object { "end": Object { - "column": 11, - "line": 7, + "column": 13, + "line": 3, }, "start": Object { - "column": 9, - "line": 7, + "column": 12, + "line": 3, }, }, "range": Array [ - 150, - 152, + 69, + 70, ], "type": "Punctuator", - "value": "?.", + "value": "!", }, Object { "loc": Object { "end": Object { - "column": 12, - "line": 7, + "column": 14, + "line": 3, }, "start": Object { - "column": 11, - "line": 7, + "column": 13, + "line": 3, }, }, "range": Array [ - 152, - 153, + 70, + 71, ], "type": "Punctuator", - "value": "[", + "value": ".", }, Object { "loc": Object { "end": Object { - "column": 13, - "line": 7, + "column": 19, + "line": 3, }, "start": Object { - "column": 12, - "line": 7, + "column": 14, + "line": 3, }, }, "range": Array [ - 153, - 154, + 71, + 76, ], - "type": "Numeric", - "value": "3", + "type": "Identifier", + "value": "three", }, Object { "loc": Object { "end": Object { - "column": 14, - "line": 7, + "column": 20, + "line": 3, }, "start": Object { - "column": 13, - "line": 7, + "column": 19, + "line": 3, }, }, "range": Array [ - 154, - 155, + 76, + 77, ], "type": "Punctuator", - "value": "]", + "value": ";", }, Object { "loc": Object { "end": Object { - "column": 16, - "line": 7, + "column": 3, + "line": 4, }, "start": Object { - "column": 14, - "line": 7, + "column": 2, + "line": 4, }, }, "range": Array [ - 155, - 157, + 80, + 81, ], "type": "Punctuator", - "value": "?.", + "value": "(", }, Object { "loc": Object { "end": Object { - "column": 17, - "line": 7, + "column": 6, + "line": 4, }, "start": Object { - "column": 16, - "line": 7, + "column": 3, + "line": 4, }, }, "range": Array [ - 157, - 158, + 81, + 84, ], - "type": "Punctuator", - "value": "[", + "type": "Identifier", + "value": "one", }, Object { "loc": Object { "end": Object { - "column": 18, - "line": 7, + "column": 8, + "line": 4, }, "start": Object { - "column": 17, - "line": 7, + "column": 6, + "line": 4, }, }, "range": Array [ - 158, - 159, + 84, + 86, ], - "type": "Numeric", - "value": "4", + "type": "Punctuator", + "value": "?.", }, Object { "loc": Object { "end": Object { - "column": 19, - "line": 7, + "column": 11, + "line": 4, }, "start": Object { - "column": 18, - "line": 7, + "column": 8, + "line": 4, }, }, "range": Array [ - 159, - 160, + 86, + 89, ], - "type": "Punctuator", - "value": "]", + "type": "Identifier", + "value": "two", }, Object { "loc": Object { "end": Object { - "column": 20, - "line": 7, + "column": 12, + "line": 4, }, "start": Object { - "column": 19, - "line": 7, + "column": 11, + "line": 4, }, }, "range": Array [ - 160, - 161, + 89, + 90, ], "type": "Punctuator", - "value": ")", + "value": "!", }, Object { "loc": Object { "end": Object { - "column": 21, - "line": 7, + "column": 13, + "line": 4, }, "start": Object { - "column": 20, - "line": 7, + "column": 12, + "line": 4, }, }, "range": Array [ - 161, - 162, + 90, + 91, ], "type": "Punctuator", - "value": "[", + "value": ")", }, Object { "loc": Object { "end": Object { - "column": 22, - "line": 7, + "column": 14, + "line": 4, }, "start": Object { - "column": 21, - "line": 7, + "column": 13, + "line": 4, }, }, "range": Array [ - 162, - 163, + 91, + 92, ], - "type": "Numeric", - "value": "5", + "type": "Punctuator", + "value": ".", }, Object { "loc": Object { "end": Object { - "column": 23, - "line": 7, + "column": 19, + "line": 4, }, "start": Object { - "column": 22, - "line": 7, + "column": 14, + "line": 4, }, }, "range": Array [ - 163, - 164, + 92, + 97, ], - "type": "Punctuator", - "value": "]", + "type": "Identifier", + "value": "three", }, Object { "loc": Object { "end": Object { - "column": 24, - "line": 7, + "column": 20, + "line": 4, }, "start": Object { - "column": 23, - "line": 7, + "column": 19, + "line": 4, }, }, "range": Array [ - 164, - 165, + 97, + 98, ], "type": "Punctuator", "value": ";", @@ -92905,16 +98275,16 @@ Object { "loc": Object { "end": Object { "column": 1, - "line": 8, + "line": 5, }, "start": Object { "column": 0, - "line": 8, + "line": 5, }, }, "range": Array [ - 166, - 167, + 99, + 100, ], "type": "Punctuator", "value": "}", diff --git a/packages/typescript-estree/tests/lib/semanticInfo.ts b/packages/typescript-estree/tests/lib/semanticInfo.ts index 5f979fb94add..ba617b57744e 100644 --- a/packages/typescript-estree/tests/lib/semanticInfo.ts +++ b/packages/typescript-estree/tests/lib/semanticInfo.ts @@ -247,7 +247,7 @@ describe('semanticInfo', () => { badConfig.project = './tsconfigs.json'; expect(() => parseCodeAndGenerateServices(readFileSync(fileName, 'utf8'), badConfig), - ).toThrow(/File .+tsconfigs\.json' not found/); + ).toThrow(/Cannot read file .+tsconfigs\.json'/); }); it('fail to read project file', () => { @@ -258,7 +258,7 @@ describe('semanticInfo', () => { parseCodeAndGenerateServices(readFileSync(fileName, 'utf8'), badConfig), ).toThrow( // case insensitive because unix based systems are case insensitive - /File .+semanticInfo' not found/i, + /Cannot read file .+semanticInfo'./i, ); }); diff --git a/yarn.lock b/yarn.lock index e14dc9e7b496..8990a0267b14 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8451,10 +8451,10 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@*, "typescript@>=3.2.1 <3.9.0", typescript@^3.8.3: - version "3.8.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" - integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w== +typescript@*, "typescript@>=3.2.1 <4.0.0", typescript@^3.8.3: + version "3.9.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.2.tgz#64e9c8e9be6ea583c54607677dd4680a1cf35db9" + integrity sha512-q2ktq4n/uLuNNShyayit+DTobV2ApPEo/6so68JaD5ojvc/6GClBipedB9zNWYxRSAlZXAe405Rlijzl6qDiSw== uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.6" From b9ca14c5f5ec28a3fde1a9b2d2f6a4dc74d903e4 Mon Sep 17 00:00:00 2001 From: Oliver Sieweke Date: Sun, 10 May 2020 00:02:11 +0200 Subject: [PATCH 04/33] feat(eslint-plugin): eslint-recommended: disable no-obj-calls (#1000) BREAKING CHANGE --- packages/eslint-plugin/src/configs/eslint-recommended.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/eslint-plugin/src/configs/eslint-recommended.ts b/packages/eslint-plugin/src/configs/eslint-recommended.ts index 696cd612d2de..6e65cdc2f6c2 100644 --- a/packages/eslint-plugin/src/configs/eslint-recommended.ts +++ b/packages/eslint-plugin/src/configs/eslint-recommended.ts @@ -21,6 +21,8 @@ export default { 'no-const-assign': 'off', // Checked by Typescript - ts(2588) 'no-new-symbol': 'off', + // Checked by Typescript - ts(2349) + 'no-obj-calls': 'off', // Checked by Typescript - ts(2376) 'no-this-before-super': 'off', // This is checked by Typescript using the option `strictNullChecks`. From ae9b8a9c73c0328287de956466257d8bbfbdb20f Mon Sep 17 00:00:00 2001 From: Oliver Sieweke Date: Sun, 10 May 2020 00:03:02 +0200 Subject: [PATCH 05/33] feat(eslint-plugin): eslint-recommended: disable no-func-assign (#984) BREAKING CHANGE --- packages/eslint-plugin/src/configs/eslint-recommended.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/eslint-plugin/src/configs/eslint-recommended.ts b/packages/eslint-plugin/src/configs/eslint-recommended.ts index 6e65cdc2f6c2..263180cbf3bc 100644 --- a/packages/eslint-plugin/src/configs/eslint-recommended.ts +++ b/packages/eslint-plugin/src/configs/eslint-recommended.ts @@ -19,6 +19,8 @@ export default { 'valid-typeof': 'off', // Checked by Typescript - ts(2588) 'no-const-assign': 'off', + // Checked by Typescript - ts(2539) + 'no-func-assign': 'off', // Checked by Typescript - ts(2588) 'no-new-symbol': 'off', // Checked by Typescript - ts(2349) From 8e31d5dbe9fe5227fdbefcecfd50ce5dd51360c3 Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Sat, 9 May 2020 16:16:27 -0700 Subject: [PATCH 06/33] feat(eslint-plugin): [ban-types] rework default options (#848) --- .markdownlint.json | 13 +- .../eslint-plugin/docs/rules/ban-types.md | 224 ++++++++++++------ packages/eslint-plugin/src/rules/ban-types.ts | 115 +++++---- .../src/rules/member-ordering.ts | 7 +- packages/eslint-plugin/src/util/index.ts | 1 + .../eslint-plugin/src/util/objectIterators.ts | 34 +++ .../tests/rules/ban-types.test.ts | 105 ++++---- .../src/eslint-utils/applyDefault.ts | 4 +- .../src/ts-eslint-scope/analyze.ts | 5 +- packages/parser/tests/lib/services.ts | 4 +- .../typescript-estree/src/parser-options.ts | 4 +- packages/typescript-estree/src/parser.ts | 8 +- packages/typescript-estree/tests/lib/parse.ts | 2 +- 13 files changed, 353 insertions(+), 173 deletions(-) create mode 100644 packages/eslint-plugin/src/util/objectIterators.ts diff --git a/.markdownlint.json b/.markdownlint.json index 77f01355394d..9dc1aa860029 100644 --- a/.markdownlint.json +++ b/.markdownlint.json @@ -58,7 +58,18 @@ // MD032/blanks-around-lists - Lists should be surrounded by blank lines "MD032": false, // MD033/no-inline-html - Inline HTML - "MD033": { "allowed_elements": ["a", "img", "br", "sup", "h1", "p"] }, + "MD033": { + "allowed_elements": [ + "a", + "img", + "br", + "sup", + "h1", + "p", + "details", + "summary" + ] + }, // MD034/no-bare-urls - Bare URL used "MD034": false, // MD035/hr-style - Horizontal rule style diff --git a/packages/eslint-plugin/docs/rules/ban-types.md b/packages/eslint-plugin/docs/rules/ban-types.md index e92e57b521f2..e5eacd40c245 100644 --- a/packages/eslint-plugin/docs/rules/ban-types.md +++ b/packages/eslint-plugin/docs/rules/ban-types.md @@ -1,93 +1,61 @@ # Bans specific types from being used (`ban-types`) -This rule bans specific types and can suggest alternatives. It does not ban the -corresponding runtime objects from being used. +Some builtin types have aliases, some types are considered dangerous or harmful. +It's often a good idea to ban certain types to help with consistency and safety. ## Rule Details -Examples of **incorrect** code for this rule `"String": "Use string instead"` - -```ts -class Foo extends Bar implements Baz { - constructor(foo: String) {} - - exit(): Array { - const foo: String = 1 as String; - } -} -``` - -Examples of **correct** code for this rule `"String": "Use string instead"` - -```ts -class Foo extends Bar implements Baz { - constructor(foo: string) {} - - exit(): Array { - const foo: string = 1 as string; - } -} -``` +This rule bans specific types and can suggest alternatives. +Note that it does not ban the corresponding runtime objects from being used. ## Options -The banned type can either be a type name literal (`Foo`), a type name with generic parameter instantiations(s) (`Foo`), or the empty object literal (`{}`). - -```CJSON -{ - "@typescript-eslint/ban-types": ["error", { - "types": { - // report usages of the type using the default error message - "Foo": null, - - // add a custom message to help explain why not to use it - "Bar": "Don't use bar!", - - // add a custom message, AND tell the plugin how to fix it - "String": { - "message": "Use string instead", - "fixWith": "string" - } - - "{}": { - "message": "Use object instead", - "fixWith": "object" - } - } - }] -} +```ts +type Options = { + types?: { + [typeName: string]: + | string + | { + message: string; + fixWith?: string; + }; + }; + extendDefaults?: boolean; +}; ``` -By default, this rule includes types which are likely to be mistakes, such as `String` and `Number`. If you don't want these enabled, set the `extendDefaults` option to `false`: +The rule accepts a single object as options, with the following keys: -```CJSON -{ - "@typescript-eslint/ban-types": ["error", { - "types": { - // add a custom message, AND tell the plugin how to fix it - "String": { - "message": "Use string instead", - "fixWith": "string" - } - }, - "extendDefaults": false - }] -} -``` +- `types` - An object whose keys are the types you want to ban, and the values are error messages. + - The type can either be a type name literal (`Foo`), a type name with generic parameter instantiation(s) (`Foo`), or the empty object literal (`{}`). + - The values can be a string, which is the error message to be reported, + or it can be an object with the following properties: + - `message: string` - the message to display when the type is matched. + - `fixWith?: string` - a string to replace the banned type with when the fixer is run. If this is omitted, no fix will be done. +- `extendDefaults` - if you're specifying custom `types`, you can set this to `true` to extend the default `types` configuration. + - This is a convenience option to save you copying across the defaults when adding another type. + - If this is `false`, the rule will _only_ use the types defined in your configuration. -### Example +Example configuration: -```json +```jsonc { "@typescript-eslint/ban-types": [ "error", { "types": { - "Array": null, - "Object": "Use {} instead", + // add a custom message to help explain why not to use it + "Foo": "Don't use Far because it is unsafe", + + // add a custom message, AND tell the plugin how to fix it "String": { "message": "Use string instead", "fixWith": "string" + }, + + "{}": { + "message": "Use object instead", + "fixWith": "object" } } } @@ -95,6 +63,124 @@ By default, this rule includes types which are likely to be mistakes, such as `S } ``` +### Default Options + +The default options provide a set of "best practices", intended to provide safety and standardization in your codebase: + +- Don't use the upper-case primitive types, you should use the lower-case types for consistency. +- Avoid the `Function` type, as it provides little safety for the following reasons: + - It provides no type safety when calling the value, which means it's easy to provide the wrong arguments. + - It accepts class declarations, which will fail when called, as they are called without the `new` keyword. +- Avoid the `Object` and `{}` types, as they mean "any non-nullish value". + - This is a point of confusion for many developers, who think it means "any object type". +- Avoid the `object` type, as it is currently hard to use due to not being able to assert that keys exist. + - See [microsoft/TypeScript#21732](https://github.com/microsoft/TypeScript/issues/21732). + +**_Important note:_** the default options suggest using `Record`; this was a stylistic decision, as the built-in `Record` type is considered to look cleaner. + +
+Default Options + +```ts +const defaultTypes = { + String: { + message: 'Use string instead', + fixWith: 'string', + }, + Boolean: { + message: 'Use boolean instead', + fixWith: 'boolean', + }, + Number: { + message: 'Use number instead', + fixWith: 'number', + }, + Symbol: { + message: 'Use symbol instead', + fixWith: 'symbol', + }, + + Function: { + message: [ + 'The `Function` type accepts any function-like value.', + 'It provides no type safety when calling the function, which can be a common source of bugs.', + 'It also accepts things like class declarations, which will throw at runtime as they will not be called with `new`.', + 'If you are expecting the function to accept certain arguments, you should explicitly define the function shape.', + ].join('\n'), + }, + + // object typing + Object: { + message: [ + 'The `Object` type actually means "any non-nullish value", so it is marginally better than `unknown`.', + '- If you want a type meaning "any object", you probably want `Record` instead.', + '- If you want a type meaning "any value", you probably want `unknown` instead.', + ].join('\n'), + }, + '{}': { + message: [ + '`{}` actually means "any non-nullish value".', + '- If you want a type meaning "any object", you probably want `Record` instead.', + '- If you want a type meaning "any value", you probably want `unknown` instead.', + ].join('\n'), + }, + object: { + message: [ + 'The `object` type is currently hard to use ([see this issue](https://github.com/microsoft/TypeScript/issues/21732)).', + 'Consider using `Record` instead, as it allows you to more easily inspect and use the keys.', + ].join('\n'), + }, +}; +``` + +
+ +### Examples + +Examples of **incorrect** code with the default options: + +```ts +// use lower-case primitives for consistency +const str: String = 'foo'; +const bool: Boolean = true; +const num: Number = 1; +const symb: Symbol = Symbol('foo'); + +// use a proper function type +const func: Function = () => 1; + +// use safer object types +const lowerObj: object = {}; + +const capitalObj1: Object = 1; +const capitalObj2: Object = { a: 'string' }; + +const curly1: {} = 1; +const curly2: {} = { a: 'string' }; +``` + +Examples of **correct** code with the default options: + +```ts +// use lower-case primitives for consistency +const str: string = 'foo'; +const bool: boolean = true; +const num: number = 1; +const symb: symbol = Symbol('foo'); + +// use a proper function type +const func: () => number = () => 1; + +// use safer object types +const lowerObj: Record = {}; + +const capitalObj1: number = 1; +const capitalObj2: { a: string } = { a: 'string' }; + +const curly1: number = 1; +const curly2: Record<'a', string> = { a: 'string' }; +``` + ## Compatibility - TSLint: [ban-types](https://palantir.github.io/tslint/rules/ban-types/) diff --git a/packages/eslint-plugin/src/rules/ban-types.ts b/packages/eslint-plugin/src/rules/ban-types.ts index 7e056959a3f7..51048df9a661 100644 --- a/packages/eslint-plugin/src/rules/ban-types.ts +++ b/packages/eslint-plugin/src/rules/ban-types.ts @@ -1,4 +1,8 @@ -import { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils'; +import { + TSESLint, + TSESTree, + AST_NODE_TYPES, +} from '@typescript-eslint/experimental-utils'; import * as util from '../util'; type Types = Record< @@ -11,24 +15,20 @@ type Types = Record< } >; -type Options = [ +export type Options = [ { types?: Types; extendDefaults?: boolean; }, ]; -type MessageIds = 'bannedTypeMessage'; +export type MessageIds = 'bannedTypeMessage'; function removeSpaces(str: string): string { return str.replace(/ /g, ''); } function stringifyTypeName( - node: - | TSESTree.EntityName - | TSESTree.TSTypeLiteral - | TSESTree.TSNullKeyword - | TSESTree.TSUndefinedKeyword, + node: TSESTree.Node, sourceCode: TSESLint.SourceCode, ): string { return removeSpaces(sourceCode.getText(node)); @@ -52,13 +52,7 @@ function getCustomMessage( return ''; } -/* - Defaults for this rule should be treated as an "all or nothing" - merge, so we need special handling here. - - See: https://github.com/typescript-eslint/typescript-eslint/issues/686 - */ -const defaultTypes = { +const defaultTypes: Types = { String: { message: 'Use string instead', fixWith: 'string', @@ -71,14 +65,55 @@ const defaultTypes = { message: 'Use number instead', fixWith: 'number', }, - Object: { - message: 'Use Record instead', - fixWith: 'Record', - }, Symbol: { message: 'Use symbol instead', fixWith: 'symbol', }, + + Function: { + message: [ + 'The `Function` type accepts any function-like value.', + 'It provides no type safety when calling the function, which can be a common source of bugs.', + 'It also accepts things like class declarations, which will throw at runtime as they will not be called with `new`.', + 'If you are expecting the function to accept certain arguments, you should explicitly define the function shape.', + ].join('\n'), + }, + + // object typing + Object: { + message: [ + 'The `Object` type actually means "any non-nullish value", so it is marginally better than `unknown`.', + '- If you want a type meaning "any object", you probably want `Record` instead.', + '- If you want a type meaning "any value", you probably want `unknown` instead.', + ].join('\n'), + }, + '{}': { + message: [ + '`{}` actually means "any non-nullish value".', + '- If you want a type meaning "any object", you probably want `Record` instead.', + '- If you want a type meaning "any value", you probably want `unknown` instead.', + ].join('\n'), + }, + object: { + message: [ + 'The `object` type is currently hard to use ([see this issue](https://github.com/microsoft/TypeScript/issues/21732)).', + 'Consider using `Record` instead, as it allows you to more easily inspect and use the keys.', + ].join('\n'), + }, +}; + +export const TYPE_KEYWORDS = { + bigint: AST_NODE_TYPES.TSBigIntKeyword, + boolean: AST_NODE_TYPES.TSBooleanKeyword, + never: AST_NODE_TYPES.TSNeverKeyword, + null: AST_NODE_TYPES.TSNullKeyword, + number: AST_NODE_TYPES.TSNumberKeyword, + object: AST_NODE_TYPES.TSObjectKeyword, + string: AST_NODE_TYPES.TSStringKeyword, + symbol: AST_NODE_TYPES.TSSymbolKeyword, + undefined: AST_NODE_TYPES.TSUndefinedKeyword, + unknown: AST_NODE_TYPES.TSUnknownKeyword, + void: AST_NODE_TYPES.TSVoidKeyword, }; export default util.createRule({ @@ -92,7 +127,7 @@ export default util.createRule({ }, fixable: 'code', messages: { - bannedTypeMessage: "Don't use '{{name}}' as a type.{{customMessage}}", + bannedTypeMessage: "Don't use `{{name}}` as a type.{{customMessage}}", }, schema: [ { @@ -127,20 +162,17 @@ export default util.createRule({ create(context, [options]) { const extendDefaults = options.extendDefaults ?? true; const customTypes = options.types ?? {}; - const types: Types = { - ...(extendDefaults ? defaultTypes : {}), - ...customTypes, - }; + const types = Object.assign( + {}, + extendDefaults ? defaultTypes : {}, + customTypes, + ); const bannedTypes = new Map( Object.entries(types).map(([type, data]) => [removeSpaces(type), data]), ); function checkBannedTypes( - typeNode: - | TSESTree.EntityName - | TSESTree.TSTypeLiteral - | TSESTree.TSNullKeyword - | TSESTree.TSUndefinedKeyword, + typeNode: TSESTree.Node, name = stringifyTypeName(typeNode, context.getSourceCode()), ): void { const bannedType = bannedTypes.get(name); @@ -164,18 +196,21 @@ export default util.createRule({ } } - return { - ...(bannedTypes.has('null') && { - TSNullKeyword(node): void { - checkBannedTypes(node, 'null'); - }, - }), + const keywordSelectors = util.objectReduceKey( + TYPE_KEYWORDS, + (acc: TSESLint.RuleListener, keyword) => { + if (bannedTypes.has(keyword)) { + acc[TYPE_KEYWORDS[keyword]] = (node: TSESTree.Node): void => + checkBannedTypes(node, keyword); + } - ...(bannedTypes.has('undefined') && { - TSUndefinedKeyword(node): void { - checkBannedTypes(node, 'undefined'); - }, - }), + return acc; + }, + {}, + ); + + return { + ...keywordSelectors, TSTypeLiteral(node): void { if (node.members.length) { diff --git a/packages/eslint-plugin/src/rules/member-ordering.ts b/packages/eslint-plugin/src/rules/member-ordering.ts index 411823c8de71..de5b971f5339 100644 --- a/packages/eslint-plugin/src/rules/member-ordering.ts +++ b/packages/eslint-plugin/src/rules/member-ordering.ts @@ -2,6 +2,7 @@ import { AST_NODE_TYPES, TSESLint, TSESTree, + JSONSchema, } from '@typescript-eslint/experimental-utils'; import * as util from '../util'; @@ -25,19 +26,19 @@ export type Options = [ }, ]; -const neverConfig = { +const neverConfig: JSONSchema.JSONSchema4 = { type: 'string', enum: ['never'], }; -const arrayConfig = (memberTypes: string[]): object => ({ +const arrayConfig = (memberTypes: string[]): JSONSchema.JSONSchema4 => ({ type: 'array', items: { enum: memberTypes, }, }); -const objectConfig = (memberTypes: string[]): object => ({ +const objectConfig = (memberTypes: string[]): JSONSchema.JSONSchema4 => ({ type: 'object', properties: { memberTypes: { diff --git a/packages/eslint-plugin/src/util/index.ts b/packages/eslint-plugin/src/util/index.ts index 381012acfec1..2a0d891f5f1f 100644 --- a/packages/eslint-plugin/src/util/index.ts +++ b/packages/eslint-plugin/src/util/index.ts @@ -5,6 +5,7 @@ export * from './createRule'; export * from './isTypeReadonly'; export * from './misc'; export * from './nullThrows'; +export * from './objectIterators'; export * from './types'; // this is done for convenience - saves migrating all of the old rules diff --git a/packages/eslint-plugin/src/util/objectIterators.ts b/packages/eslint-plugin/src/util/objectIterators.ts new file mode 100644 index 000000000000..474d64349ff6 --- /dev/null +++ b/packages/eslint-plugin/src/util/objectIterators.ts @@ -0,0 +1,34 @@ +function objectForEachKey>( + obj: T, + callback: (key: keyof T) => void, +): void { + const keys = Object.keys(obj); + for (const key of keys) { + callback(key); + } +} + +function objectMapKey, TReturn>( + obj: T, + callback: (key: keyof T) => TReturn, +): TReturn[] { + const values: TReturn[] = []; + objectForEachKey(obj, key => { + values.push(callback(key)); + }); + return values; +} + +function objectReduceKey, TAccumulator>( + obj: T, + callback: (acc: TAccumulator, key: keyof T) => TAccumulator, + initial: TAccumulator, +): TAccumulator { + let accumulator = initial; + objectForEachKey(obj, key => { + accumulator = callback(accumulator, key); + }); + return accumulator; +} + +export { objectForEachKey, objectMapKey, objectReduceKey }; diff --git a/packages/eslint-plugin/tests/rules/ban-types.test.ts b/packages/eslint-plugin/tests/rules/ban-types.test.ts index 772fa7716f8f..9f11202a07f6 100644 --- a/packages/eslint-plugin/tests/rules/ban-types.test.ts +++ b/packages/eslint-plugin/tests/rules/ban-types.test.ts @@ -1,12 +1,17 @@ -import rule from '../../src/rules/ban-types'; +import { TSESLint } from '@typescript-eslint/experimental-utils'; +import rule, { + MessageIds, + Options, + TYPE_KEYWORDS, +} from '../../src/rules/ban-types'; +import { objectReduceKey } from '../../src/util'; import { RuleTester, noFormat } from '../RuleTester'; -import { InferOptionsTypeFromRule } from '../../src/util'; const ruleTester = new RuleTester({ parser: '@typescript-eslint/parser', }); -const options: InferOptionsTypeFromRule = [ +const options: Options = [ { types: { String: { @@ -21,32 +26,13 @@ const options: InferOptionsTypeFromRule = [ fixWith: 'NS.Good', }, }, - }, -]; - -const options2: InferOptionsTypeFromRule = [ - { - types: { - null: { - message: 'Use undefined instead.', - fixWith: 'undefined', - }, - }, - }, -]; - -const options3: InferOptionsTypeFromRule = [ - { - types: { - undefined: null, - }, + extendDefaults: false, }, ]; ruleTester.run('ban-types', rule, { valid: [ 'let f = Object();', // Should not fail if there is no options set - 'let f: {} = {};', 'let f: { x: number; y: number } = { x: 1, y: 1 };', { code: 'let f = Object();', @@ -89,11 +75,27 @@ ruleTester.run('ban-types', rule, { }, { code: 'let a: undefined;', - options: options2, + options: [ + { + types: { + null: { + message: 'Use undefined instead.', + fixWith: 'undefined', + }, + }, + }, + ], }, { code: 'let a: null;', - options: options3, + options: [ + { + types: { + undefined: null, + }, + extendDefaults: false, + }, + ], }, ], invalid: [ @@ -122,30 +124,6 @@ ruleTester.run('ban-types', rule, { ], options, }, - { - code: 'let a: undefined;', - errors: [ - { - messageId: 'bannedTypeMessage', - data: { name: 'undefined', customMessage: '' }, - line: 1, - column: 8, - }, - ], - options: options3, - }, - { - code: 'let a: null;', - errors: [ - { - messageId: 'bannedTypeMessage', - data: { name: 'null', customMessage: ' Use undefined instead.' }, - line: 1, - column: 8, - }, - ], - options: options2, - }, { code: 'let aa: Foo;', errors: [ @@ -497,5 +475,34 @@ let bar: object = {}; }, ], }, + ...objectReduceKey( + TYPE_KEYWORDS, + (acc: TSESLint.InvalidTestCase[], key) => { + acc.push({ + code: `function foo(x: ${key}) {}`, + errors: [ + { + messageId: 'bannedTypeMessage', + data: { + name: key, + customMessage: '', + }, + line: 1, + column: 17, + }, + ], + options: [ + { + extendDefaults: false, + types: { + [key]: null, + }, + }, + ], + }); + return acc; + }, + [], + ), ], }); diff --git a/packages/experimental-utils/src/eslint-utils/applyDefault.ts b/packages/experimental-utils/src/eslint-utils/applyDefault.ts index 9b4f6513ecc6..a9984b563a17 100644 --- a/packages/experimental-utils/src/eslint-utils/applyDefault.ts +++ b/packages/experimental-utils/src/eslint-utils/applyDefault.ts @@ -35,6 +35,8 @@ function applyDefault( return options; } -type AsMutable = { -readonly [TKey in keyof T]: T[TKey] }; +type AsMutable = { + -readonly [TKey in keyof T]: T[TKey]; +}; export { applyDefault }; diff --git a/packages/experimental-utils/src/ts-eslint-scope/analyze.ts b/packages/experimental-utils/src/ts-eslint-scope/analyze.ts index 9bbe1c1118e7..51d69ba8cbec 100644 --- a/packages/experimental-utils/src/ts-eslint-scope/analyze.ts +++ b/packages/experimental-utils/src/ts-eslint-scope/analyze.ts @@ -1,5 +1,6 @@ import { analyze as ESLintAnalyze } from 'eslint-scope'; import { EcmaVersion } from '../ts-eslint'; +import { TSESTree } from '../ts-estree'; import { ScopeManager } from './ScopeManager'; interface AnalysisOptions { @@ -8,12 +9,12 @@ interface AnalysisOptions { ignoreEval?: boolean; nodejsScope?: boolean; impliedStrict?: boolean; - fallback?: string | ((node: {}) => string[]); + fallback?: string | ((node: TSESTree.Node) => string[]); sourceType?: 'script' | 'module'; ecmaVersion?: EcmaVersion; } const analyze = ESLintAnalyze as ( - ast: {}, + ast: TSESTree.Node, options?: AnalysisOptions, ) => ScopeManager; diff --git a/packages/parser/tests/lib/services.ts b/packages/parser/tests/lib/services.ts index 37ddf0fadcf4..210cd39e1ea3 100644 --- a/packages/parser/tests/lib/services.ts +++ b/packages/parser/tests/lib/services.ts @@ -1,6 +1,7 @@ import path from 'path'; import fs from 'fs'; import glob from 'glob'; +import { ParserOptions } from '../../src/parser-options'; import { createSnapshotTestBlock, formatSnapshotName, @@ -16,10 +17,9 @@ const testFiles = glob.sync(`**/*.src.ts`, { cwd: FIXTURES_DIR, }); -function createConfig(filename: string): object { +function createConfig(filename: string): ParserOptions { return { filePath: filename, - generateServices: true, project: './tsconfig.json', tsconfigRootDir: path.resolve(FIXTURES_DIR), }; diff --git a/packages/typescript-estree/src/parser-options.ts b/packages/typescript-estree/src/parser-options.ts index c55ace5adb03..e901ee74957c 100644 --- a/packages/typescript-estree/src/parser-options.ts +++ b/packages/typescript-estree/src/parser-options.ts @@ -15,7 +15,7 @@ export interface Extra { filePath: string; jsx: boolean; loc: boolean; - log: Function; + log: (message: string) => void; preserveNodeMaps?: boolean; projects: string[]; range: boolean; @@ -81,7 +81,7 @@ interface ParseOptions { * When value is `false`, no logging will occur. * When value is not provided, `console.log()` will be used. */ - loggerFn?: Function | false; + loggerFn?: ((message: string) => void) | false; /** * Controls whether the `range` property is included on AST nodes. diff --git a/packages/typescript-estree/src/parser.ts b/packages/typescript-estree/src/parser.ts index 5e3e9b90261b..069e8af19601 100644 --- a/packages/typescript-estree/src/parser.ts +++ b/packages/typescript-estree/src/parser.ts @@ -272,7 +272,7 @@ function applyParserOptionsToExtra(options: TSESTreeOptions): void { if (typeof options.loggerFn === 'function') { extra.log = options.loggerFn; } else if (options.loggerFn === false) { - extra.log = Function.prototype; + extra.log = (): void => {}; } if (typeof options.tsconfigRootDir === 'string') { @@ -337,9 +337,11 @@ function warnAboutTSVersion(): void { // Parser //------------------------------------------------------------------------------ +// eslint-disable-next-line @typescript-eslint/no-empty-interface +interface EmptyObject {} type AST = TSESTree.Program & - (T['tokens'] extends true ? { tokens: TSESTree.Token[] } : {}) & - (T['comment'] extends true ? { comments: TSESTree.Comment[] } : {}); + (T['tokens'] extends true ? { tokens: TSESTree.Token[] } : EmptyObject) & + (T['comment'] extends true ? { comments: TSESTree.Comment[] } : EmptyObject); interface ParseAndGenerateServicesResult { ast: AST; diff --git a/packages/typescript-estree/tests/lib/parse.ts b/packages/typescript-estree/tests/lib/parse.ts index c6435508eacc..9c049ae882d5 100644 --- a/packages/typescript-estree/tests/lib/parse.ts +++ b/packages/typescript-estree/tests/lib/parse.ts @@ -83,7 +83,7 @@ describe('parse()', () => { it('output tokens, comments, locs, and ranges when called with those options', () => { const spy = jest.spyOn(astConverter, 'astConverter'); - const loggerFn = jest.fn(() => true); + const loggerFn = jest.fn(() => {}); parser.parse('let foo = bar;', { loggerFn, From ee8dd8f8a9e6c25ac426ce9bb71c5f012c51f264 Mon Sep 17 00:00:00 2001 From: Retsam Date: Sat, 9 May 2020 19:27:48 -0400 Subject: [PATCH 07/33] feat(eslint-plugin): [no-unnecessary-condition] remove option `ignoreRHS` (#1163) --- .../src/rules/no-unnecessary-condition.ts | 45 ++++-------- .../rules/no-unnecessary-condition.test.ts | 73 ++++++++++--------- 2 files changed, 53 insertions(+), 65 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts b/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts index a64a3ddc9c94..919e182a7490 100644 --- a/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts +++ b/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts @@ -60,7 +60,6 @@ const isLiteral = (type: ts.Type): boolean => export type Options = [ { allowConstantLoopConditions?: boolean; - ignoreRhs?: boolean; checkArrayPredicates?: boolean; }, ]; @@ -93,9 +92,6 @@ export default createRule({ allowConstantLoopConditions: { type: 'boolean', }, - ignoreRhs: { - type: 'boolean', - }, checkArrayPredicates: { type: 'boolean', }, @@ -124,14 +120,10 @@ export default createRule({ defaultOptions: [ { allowConstantLoopConditions: false, - ignoreRhs: false, checkArrayPredicates: false, }, ], - create( - context, - [{ allowConstantLoopConditions, checkArrayPredicates, ignoreRhs }], - ) { + create(context, [{ allowConstantLoopConditions, checkArrayPredicates }]) { const service = getParserServices(context); const checker = service.program.getTypeChecker(); const sourceCode = context.getSourceCode(); @@ -176,6 +168,12 @@ export default createRule({ return; } + // When checking logical expressions, only check the right side + // as the left side has been checked by checkLogicalExpressionForUnnecessaryConditionals + if (node.type === AST_NODE_TYPES.LogicalExpression) { + return checkNode(node.right); + } + const type = getNodeType(node); // Conditional is always necessary if it involves: @@ -259,20 +257,6 @@ export default createRule({ } } - /** - * Checks that a testable expression is necessarily conditional, reports otherwise. - * Filters all LogicalExpressions to prevent some duplicate reports. - */ - function checkIfTestExpressionIsNecessaryConditional( - node: TSESTree.ConditionalExpression | TSESTree.IfStatement, - ): void { - if (node.test.type === AST_NODE_TYPES.LogicalExpression) { - return; - } - - checkNode(node.test); - } - /** * Checks that a logical expression contains a boolean, reports otherwise. */ @@ -283,10 +267,9 @@ export default createRule({ checkNodeForNullish(node.left); return; } + // Only checks the left side, since the right side might not be "conditional" at all. + // The right side will be checked if the LogicalExpression is used in a conditional context checkNode(node.left); - if (!ignoreRhs) { - checkNode(node.right); - } } /** @@ -298,10 +281,8 @@ export default createRule({ | TSESTree.ForStatement | TSESTree.WhileStatement, ): void { - if ( - node.test === null || - node.test.type === AST_NODE_TYPES.LogicalExpression - ) { + if (node.test === null) { + // e.g. `for(;;)` return; } @@ -480,10 +461,10 @@ export default createRule({ return { BinaryExpression: checkIfBinaryExpressionIsNecessaryConditional, CallExpression: checkCallExpression, - ConditionalExpression: checkIfTestExpressionIsNecessaryConditional, + ConditionalExpression: (node): void => checkNode(node.test), DoWhileStatement: checkIfLoopIsNecessaryConditional, ForStatement: checkIfLoopIsNecessaryConditional, - IfStatement: checkIfTestExpressionIsNecessaryConditional, + IfStatement: (node): void => checkNode(node.test), LogicalExpression: checkLogicalExpressionForUnnecessaryConditionals, WhileStatement: checkIfLoopIsNecessaryConditional, OptionalMemberExpression: checkOptionalMemberExpression, diff --git a/packages/eslint-plugin/tests/rules/no-unnecessary-condition.test.ts b/packages/eslint-plugin/tests/rules/no-unnecessary-condition.test.ts index 42f9e288b234..913aca555655 100644 --- a/packages/eslint-plugin/tests/rules/no-unnecessary-condition.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unnecessary-condition.test.ts @@ -56,6 +56,14 @@ for (let i = 0; b1 && b2; i++) { break; } const t1 = b1 && b2 ? 'yes' : 'no'; +if (b1 && b2) { +} +while (b1 && b2) {} +for (let i = 0; b1 && b2; i++) { + break; +} +const t1 = b1 && b2 ? 'yes' : 'no'; +for (;;) {} `, necessaryConditionTest('false | 5'), // Truthy literal and falsy literal necessaryConditionTest('boolean | "foo"'), // boolean and truthy literal @@ -203,15 +211,14 @@ returnsArr?.()[42]?.toUpperCase(); declare const arr: string[][]; arr[x] ?? []; `, - // Supports ignoring the RHS + // Doesn't check the right-hand side of a logical expression + // in a non-conditional context { code: ` declare const b1: boolean; declare const b2: true; -if (b1 && b2) { -} +const x = b1 && b2; `, - options: [{ ignoreRhs: true }], }, { code: ` @@ -289,19 +296,26 @@ const t1 = b1 && b2; const t2 = b1 || b2; if (b1 && b2) { } +if (b2 && b1) { +} while (b1 && b2) {} +while (b2 && b1) {} for (let i = 0; b1 && b2; i++) { break; } const t1 = b1 && b2 ? 'yes' : 'no'; +const t1 = b2 && b1 ? 'yes' : 'no'; `, errors: [ ruleError(4, 12, 'alwaysTruthy'), ruleError(5, 12, 'alwaysTruthy'), ruleError(6, 5, 'alwaysTruthy'), - ruleError(8, 8, 'alwaysTruthy'), - ruleError(9, 17, 'alwaysTruthy'), - ruleError(12, 12, 'alwaysTruthy'), + ruleError(8, 11, 'alwaysTruthy'), + ruleError(10, 8, 'alwaysTruthy'), + ruleError(11, 14, 'alwaysTruthy'), + ruleError(12, 17, 'alwaysTruthy'), + ruleError(15, 12, 'alwaysTruthy'), + ruleError(16, 18, 'alwaysTruthy'), ], }, // Ensure that it's complaining about the right things @@ -314,6 +328,25 @@ const t1 = b1 && b2 ? 'yes' : 'no'; unnecessaryConditionTest('void', 'alwaysFalsy'), unnecessaryConditionTest('never', 'never'), + // More complex logical expressions + { + code: ` +declare const b1: boolean; +declare const b2: boolean; +if (true && b1 && b2) { +} +if (b1 && false && b2) { +} +if (b1 || b2 || true) { +} + `, + errors: [ + ruleError(4, 5, 'alwaysTruthy'), + ruleError(6, 11, 'alwaysFalsy'), + ruleError(8, 17, 'alwaysTruthy'), + ], + }, + // Generic type params { code: ` @@ -497,32 +530,6 @@ function falsy() {} // `, // errors: [ruleError(6, 23, 'alwaysTruthyFunc')], // }, - - // Still errors on in the expected locations when ignoring RHS - { - options: [{ ignoreRhs: true }], - code: ` -const b1 = true; -const b2 = false; -const t1 = b1 && b2; -const t2 = b1 || b2; -if (b1 && b2) { -} -while (b1 && b2) {} -for (let i = 0; b1 && b2; i++) { - break; -} -const t1 = b1 && b2 ? 'yes' : 'no'; - `, - errors: [ - ruleError(4, 12, 'alwaysTruthy'), - ruleError(5, 12, 'alwaysTruthy'), - ruleError(6, 5, 'alwaysTruthy'), - ruleError(8, 8, 'alwaysTruthy'), - ruleError(9, 17, 'alwaysTruthy'), - ruleError(12, 12, 'alwaysTruthy'), - ], - }, { code: ` while (true) {} From 82e7163214b56ccde93ba97807b161669a50a60b Mon Sep 17 00:00:00 2001 From: Gareth Jones Date: Sun, 10 May 2020 12:17:16 +1200 Subject: [PATCH 08/33] fix(typescript-estree): use `TSEmptyBodyFunctionExpression` for body-less nodes (#1289) --- .../src/rules/indent-new-do-not-use/index.ts | 2 +- .../src/rules/no-unsafe-assignment.ts | 5 ++++- .../src/util/explicitReturnTypeUtils.ts | 2 +- packages/parser/src/parser.ts | 16 -------------- packages/typescript-estree/src/convert.ts | 22 +++++++++++++------ .../src/ts-estree/ts-estree.ts | 7 +++++- .../lib/__snapshots__/typescript.ts.snap | 16 +++++++------- 7 files changed, 35 insertions(+), 35 deletions(-) diff --git a/packages/eslint-plugin/src/rules/indent-new-do-not-use/index.ts b/packages/eslint-plugin/src/rules/indent-new-do-not-use/index.ts index 3c24f29ad9e5..73123355a324 100644 --- a/packages/eslint-plugin/src/rules/indent-new-do-not-use/index.ts +++ b/packages/eslint-plugin/src/rules/indent-new-do-not-use/index.ts @@ -1115,7 +1115,7 @@ export default createRule({ 'FunctionDeclaration, FunctionExpression'( node: TSESTree.FunctionDeclaration | TSESTree.FunctionExpression, ) { - const closingParen = sourceCode.getTokenBefore(node.body!)!; + const closingParen = sourceCode.getTokenBefore(node.body)!; const openingParen = sourceCode.getTokenBefore( node.params.length ? node.params[0] : closingParen, )!; diff --git a/packages/eslint-plugin/src/rules/no-unsafe-assignment.ts b/packages/eslint-plugin/src/rules/no-unsafe-assignment.ts index b7f339e19440..638d30363112 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-assignment.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-assignment.ts @@ -326,7 +326,10 @@ export default util.createRule({ }, // object pattern props are checked via assignments ':not(ObjectPattern) > Property'(node: TSESTree.Property): void { - if (node.value.type === AST_NODE_TYPES.AssignmentPattern) { + if ( + node.value.type === AST_NODE_TYPES.AssignmentPattern || + node.value.type === AST_NODE_TYPES.TSEmptyBodyFunctionExpression + ) { // handled by other selector return; } diff --git a/packages/eslint-plugin/src/util/explicitReturnTypeUtils.ts b/packages/eslint-plugin/src/util/explicitReturnTypeUtils.ts index 03a2260289ee..2725a6ab3d3b 100644 --- a/packages/eslint-plugin/src/util/explicitReturnTypeUtils.ts +++ b/packages/eslint-plugin/src/util/explicitReturnTypeUtils.ts @@ -62,7 +62,7 @@ function getReporLoc( )!.loc.end; } - return sourceCode.getTokenBefore(node.body!)!.loc.end; + return sourceCode.getTokenBefore(node.body)!.loc.end; } return { diff --git a/packages/parser/src/parser.ts b/packages/parser/src/parser.ts index 86469cea2552..00c0fe57d431 100644 --- a/packages/parser/src/parser.ts +++ b/packages/parser/src/parser.ts @@ -5,7 +5,6 @@ import { ParserServices, TSESTreeOptions, TSESTree, - simpleTraverse, visitorKeys, } from '@typescript-eslint/typescript-estree'; import { analyzeScope } from './analyze-scope'; @@ -95,21 +94,6 @@ export function parseForESLint( const { ast, services } = parseAndGenerateServices(code, parserOptions); ast.sourceType = options.sourceType; - simpleTraverse(ast, { - enter(node) { - switch (node.type) { - // Function#body cannot be null in ESTree spec. - case AST_NODE_TYPES.FunctionExpression: - if (!node.body) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - node.type = `TSEmptyBody${node.type}` as any; - } - break; - // no default - } - }, - }); - const scopeManager = analyzeScope(ast, options); return { ast, services, scopeManager, visitorKeys }; } diff --git a/packages/typescript-estree/src/convert.ts b/packages/typescript-estree/src/convert.ts index 66111f488403..f6770453581a 100644 --- a/packages/typescript-estree/src/convert.ts +++ b/packages/typescript-estree/src/convert.ts @@ -14,21 +14,21 @@ import { getTextForTokenKind, getTSNodeAccessibility, hasModifier, + isChildOptionalChain, isComma, isComputedProperty, isESTreeClassMember, isOptional, - isChildOptionalChain, - unescapeStringLiteralText, TSError, + unescapeStringLiteralText, } from './node-utils'; +import { ParserWeakMap, ParserWeakMapESTreeToTSNode } from './parser-options'; import { AST_NODE_TYPES, TSESTree, TSNode, TSESTreeToTSNode, } from './ts-estree'; -import { ParserWeakMap, ParserWeakMapESTreeToTSNode } from './parser-options'; const SyntaxKind = ts.SyntaxKind; @@ -999,8 +999,12 @@ export class Converter { case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: case SyntaxKind.MethodDeclaration: { - const method = this.createNode(node, { - type: AST_NODE_TYPES.FunctionExpression, + const method = this.createNode< + TSESTree.TSEmptyBodyFunctionExpression | TSESTree.FunctionExpression + >(node, { + type: !node.body + ? AST_NODE_TYPES.TSEmptyBodyFunctionExpression + : AST_NODE_TYPES.FunctionExpression, id: null, generator: !!node.asteriskToken, expression: false, // ESTreeNode as ESTreeNode here @@ -1109,8 +1113,12 @@ export class Converter { (lastModifier && findNextToken(lastModifier, node, this.ast)) || node.getFirstToken()!; - const constructor = this.createNode(node, { - type: AST_NODE_TYPES.FunctionExpression, + const constructor = this.createNode< + TSESTree.TSEmptyBodyFunctionExpression | TSESTree.FunctionExpression + >(node, { + type: !node.body + ? AST_NODE_TYPES.TSEmptyBodyFunctionExpression + : AST_NODE_TYPES.FunctionExpression, id: null, params: this.convertParameters(node.parameters), generator: false, diff --git a/packages/typescript-estree/src/ts-estree/ts-estree.ts b/packages/typescript-estree/src/ts-estree/ts-estree.ts index afccf30fefbc..1bfb323e3d76 100644 --- a/packages/typescript-estree/src/ts-estree/ts-estree.ts +++ b/packages/typescript-estree/src/ts-estree/ts-estree.ts @@ -674,7 +674,11 @@ interface MethodDefinitionNonComputedNameBase extends MethodDefinitionBase { interface PropertyBase extends BaseNode { type: AST_NODE_TYPES.Property; key: PropertyName; - value: Expression | AssignmentPattern | BindingName; + value: + | Expression + | AssignmentPattern + | BindingName + | TSEmptyBodyFunctionExpression; computed: boolean; method: boolean; shorthand: boolean; @@ -928,6 +932,7 @@ export interface FunctionDeclaration extends FunctionDeclarationBase { export interface FunctionExpression extends FunctionDeclarationBase { type: AST_NODE_TYPES.FunctionExpression; + body: BlockStatement; } export interface Identifier extends BaseNode { diff --git a/packages/typescript-estree/tests/lib/__snapshots__/typescript.ts.snap b/packages/typescript-estree/tests/lib/__snapshots__/typescript.ts.snap index 5143a42c849d..e71820fc060e 100644 --- a/packages/typescript-estree/tests/lib/__snapshots__/typescript.ts.snap +++ b/packages/typescript-estree/tests/lib/__snapshots__/typescript.ts.snap @@ -768,7 +768,7 @@ Object { 63, 66, ], - "type": "FunctionExpression", + "type": "TSEmptyBodyFunctionExpression", }, }, ], @@ -1216,7 +1216,7 @@ Object { }, }, }, - "type": "FunctionExpression", + "type": "TSEmptyBodyFunctionExpression", }, }, ], @@ -2433,7 +2433,7 @@ Object { 68, 71, ], - "type": "FunctionExpression", + "type": "TSEmptyBodyFunctionExpression", }, }, ], @@ -4034,7 +4034,7 @@ Object { }, }, }, - "type": "FunctionExpression", + "type": "TSEmptyBodyFunctionExpression", }, }, ], @@ -24208,7 +24208,7 @@ Object { 18, 21, ], - "type": "FunctionExpression", + "type": "TSEmptyBodyFunctionExpression", }, }, Object { @@ -24304,7 +24304,7 @@ Object { "type": "TSStringKeyword", }, }, - "type": "FunctionExpression", + "type": "TSEmptyBodyFunctionExpression", }, }, Object { @@ -24401,7 +24401,7 @@ Object { "type": "TSStringKeyword", }, }, - "type": "FunctionExpression", + "type": "TSEmptyBodyFunctionExpression", }, }, ], @@ -38261,7 +38261,7 @@ Object { "type": "TSAnyKeyword", }, }, - "type": "FunctionExpression", + "type": "TSEmptyBodyFunctionExpression", }, }, ], From 9a96e18400e0a0d738d159d9d01faf41d3586249 Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Sat, 9 May 2020 17:17:36 -0700 Subject: [PATCH 09/33] feat(eslint-plugin): update `eslint-recommended` set (#1996) --- .../src/configs/eslint-recommended.ts | 42 +++++++------------ 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/packages/eslint-plugin/src/configs/eslint-recommended.ts b/packages/eslint-plugin/src/configs/eslint-recommended.ts index 263180cbf3bc..4999a528bdf8 100644 --- a/packages/eslint-plugin/src/configs/eslint-recommended.ts +++ b/packages/eslint-plugin/src/configs/eslint-recommended.ts @@ -7,32 +7,22 @@ export default { { files: ['*.ts', '*.tsx'], rules: { - // Checked by Typescript - ts(2378) - 'getter-return': 'off', - // Checked by Typescript - ts(2300) - 'no-dupe-args': 'off', - // Checked by Typescript - ts(1117) - 'no-dupe-keys': 'off', - // Checked by Typescript - ts(7027) - 'no-unreachable': 'off', - // Checked by Typescript - ts(2367) - 'valid-typeof': 'off', - // Checked by Typescript - ts(2588) - 'no-const-assign': 'off', - // Checked by Typescript - ts(2539) - 'no-func-assign': 'off', - // Checked by Typescript - ts(2588) - 'no-new-symbol': 'off', - // Checked by Typescript - ts(2349) - 'no-obj-calls': 'off', - // Checked by Typescript - ts(2376) - 'no-this-before-super': 'off', - // This is checked by Typescript using the option `strictNullChecks`. - 'no-undef': 'off', - // This is already checked by Typescript. - 'no-dupe-class-members': 'off', - // This is already checked by Typescript. - 'no-redeclare': 'off', + 'constructor-super': 'off', // ts(2335) & ts(2377) + 'getter-return': 'off', // ts(2378) + 'no-const-assign': 'off', // ts(2588) + 'no-dupe-args': 'off', // ts(2300) + 'no-dupe-class-members': 'off', // ts(2393) & ts(2300) + 'no-dupe-keys': 'off', // ts(1117) + 'no-func-assign': 'off', // ts(2539) + 'no-new-symbol': 'off', // ts(2588) + 'no-obj-calls': 'off', // ts(2349) + 'no-redeclare': 'off', // ts(2451) + 'no-setter-return': 'off', // ts(2408) + 'no-this-before-super': 'off', // ts(2376) + 'no-undef': 'off', // ts(2304) + 'no-unreachable': 'off', // ts(7027) + 'no-unsafe-negation': 'off', // ts(2365) & ts(2360) & ts(2358) + 'valid-typeof': 'off', // ts(2367) }, }, ], From 5b23443c48f3f62424db3e742243f3568080b946 Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Sat, 9 May 2020 17:44:52 -0700 Subject: [PATCH 10/33] feat(typescript-estree): always return parserServices (#716) --- packages/eslint-plugin/README.md | 2 +- .../src/rules/no-unused-vars-experimental.ts | 5 +- packages/eslint-plugin/tests/docs.test.ts | 7 +- .../rules/no-unused-vars-experimental.test.ts | 2 - .../tests/util/isUnsafeAssignment.test.ts | 4 +- .../src/eslint-utils/getParserServices.ts | 31 +++-- .../typescript-estree/src/ast-converter.ts | 4 +- .../create-program/createProjectProgram.ts | 1 - .../src/create-program/shared.ts | 5 +- .../typescript-estree/src/parser-options.ts | 9 +- packages/typescript-estree/src/parser.ts | 48 ++----- .../tests/lib/__snapshots__/parse.ts.snap | 126 ++++++++++-------- .../typescript-estree/tests/lib/convert.ts | 16 +-- packages/typescript-estree/tests/lib/parse.ts | 112 +++++++++------- .../tests/lib/semanticInfo.ts | 30 ++--- 15 files changed, 211 insertions(+), 191 deletions(-) diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md index 31a96173d90f..c57d8d09cd62 100644 --- a/packages/eslint-plugin/README.md +++ b/packages/eslint-plugin/README.md @@ -139,7 +139,7 @@ Pro Tip: For larger codebases you may want to consider splitting our linting int | [`@typescript-eslint/no-unsafe-call`](./docs/rules/no-unsafe-call.md) | Disallows calling an any type value | | | :thought_balloon: | | [`@typescript-eslint/no-unsafe-member-access`](./docs/rules/no-unsafe-member-access.md) | Disallows member access on any typed variables | | | :thought_balloon: | | [`@typescript-eslint/no-unsafe-return`](./docs/rules/no-unsafe-return.md) | Disallows returning any from a function | | | :thought_balloon: | -| [`@typescript-eslint/no-unused-vars-experimental`](./docs/rules/no-unused-vars-experimental.md) | Disallow unused variables and arguments | | | :thought_balloon: | +| [`@typescript-eslint/no-unused-vars-experimental`](./docs/rules/no-unused-vars-experimental.md) | Disallow unused variables and arguments | | | | | [`@typescript-eslint/no-var-requires`](./docs/rules/no-var-requires.md) | Disallows the use of require statements except in import statements | :heavy_check_mark: | | | | [`@typescript-eslint/prefer-as-const`](./docs/rules/prefer-as-const.md) | Prefer usage of `as const` over literal type | | :wrench: | | | [`@typescript-eslint/prefer-for-of`](./docs/rules/prefer-for-of.md) | Prefer a ‘for-of’ loop over a standard ‘for’ loop if the index is only used to access the array being iterated | | | | diff --git a/packages/eslint-plugin/src/rules/no-unused-vars-experimental.ts b/packages/eslint-plugin/src/rules/no-unused-vars-experimental.ts index ca46ef0527c3..c85869738617 100644 --- a/packages/eslint-plugin/src/rules/no-unused-vars-experimental.ts +++ b/packages/eslint-plugin/src/rules/no-unused-vars-experimental.ts @@ -29,7 +29,6 @@ export default util.createRule({ description: 'Disallow unused variables and arguments', category: 'Best Practices', recommended: false, - requiresTypeChecking: true, }, schema: [ { @@ -68,7 +67,7 @@ export default util.createRule({ }, ], create(context, [userOptions]) { - const parserServices = util.getParserServices(context); + const parserServices = util.getParserServices(context, true); const tsProgram = parserServices.program; const afterAllDiagnosticsCallbacks: (() => void)[] = []; @@ -191,7 +190,7 @@ export default util.createRule({ parent: ts.ParameterDeclaration, ): void { const name = identifier.getText(); - // regardless of if the paramter is ignored, track that it had a diagnostic fired on it + // regardless of if the parameter is ignored, track that it had a diagnostic fired on it unusedParameters.add(identifier); /* diff --git a/packages/eslint-plugin/tests/docs.test.ts b/packages/eslint-plugin/tests/docs.test.ts index d7bc5ce97b9d..9376af4daa5c 100644 --- a/packages/eslint-plugin/tests/docs.test.ts +++ b/packages/eslint-plugin/tests/docs.test.ts @@ -70,6 +70,10 @@ describe('Validating rule docs', () => { }); describe('Validating rule metadata', () => { + function requiresFullTypeInformation(content: string): boolean { + return /getParserServices(\(\s*[^,\s)]+)\s*(,\s*false\s*)?\)/.test(content); + } + for (const [ruleName, rule] of rulesData) { describe(`${ruleName}`, () => { it('`name` field in rule must match the filename', () => { @@ -85,9 +89,10 @@ describe('Validating rule metadata', () => { // not perfect but should be good enough const ruleFileContents = fs.readFileSync( path.resolve(__dirname, `../src/rules/${ruleName}.ts`), + 'utf-8', ); - expect(ruleFileContents.includes('getParserServices')).toEqual( + expect(requiresFullTypeInformation(ruleFileContents)).toEqual( rule.meta.docs?.requiresTypeChecking ?? false, ); }); diff --git a/packages/eslint-plugin/tests/rules/no-unused-vars-experimental.test.ts b/packages/eslint-plugin/tests/rules/no-unused-vars-experimental.test.ts index 335b3986437e..172dfdd793a0 100644 --- a/packages/eslint-plugin/tests/rules/no-unused-vars-experimental.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unused-vars-experimental.test.ts @@ -14,8 +14,6 @@ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2018, sourceType: 'module', - project: './tsconfig.json', - tsconfigRootDir: rootDir, }, parser: '@typescript-eslint/parser', }); diff --git a/packages/eslint-plugin/tests/util/isUnsafeAssignment.test.ts b/packages/eslint-plugin/tests/util/isUnsafeAssignment.test.ts index bd644832b30f..3862b38902ca 100644 --- a/packages/eslint-plugin/tests/util/isUnsafeAssignment.test.ts +++ b/packages/eslint-plugin/tests/util/isUnsafeAssignment.test.ts @@ -16,8 +16,8 @@ describe('isUnsafeAssignment', () => { filePath: path.join(rootDir, 'file.ts'), tsconfigRootDir: rootDir, }); - const checker = services.program!.getTypeChecker(); - const esTreeNodeToTSNodeMap = services.esTreeNodeToTSNodeMap!; + const checker = services.program.getTypeChecker(); + const esTreeNodeToTSNodeMap = services.esTreeNodeToTSNodeMap; const declaration = ast.body[0] as TSESTree.VariableDeclaration; const declarator = declaration.declarations[0]; diff --git a/packages/experimental-utils/src/eslint-utils/getParserServices.ts b/packages/experimental-utils/src/eslint-utils/getParserServices.ts index 57b6bc59f656..481603d7ed51 100644 --- a/packages/experimental-utils/src/eslint-utils/getParserServices.ts +++ b/packages/experimental-utils/src/eslint-utils/getParserServices.ts @@ -4,31 +4,38 @@ import { ParserServices } from '../ts-estree'; const ERROR_MESSAGE = 'You have used a rule which requires parserServices to be generated. You must therefore provide a value for the "parserOptions.project" property for @typescript-eslint/parser.'; -type RequiredParserServices = { - [k in keyof ParserServices]: Exclude; -}; - /** * Try to retrieve typescript parser service from context */ function getParserServices< TMessageIds extends string, - TOptions extends unknown[] + TOptions extends readonly unknown[] >( context: TSESLint.RuleContext, -): RequiredParserServices { + allowWithoutFullTypeInformation = false, +): ParserServices { + // backwards compatibility check + // old versions of the parser would not return any parserServices unless parserOptions.project was set if ( !context.parserServices || !context.parserServices.program || - !context.parserServices.esTreeNodeToTSNodeMap + !context.parserServices.esTreeNodeToTSNodeMap || + !context.parserServices.tsNodeToESTreeNodeMap ) { - /** - * The user needs to have configured "project" in their parserOptions - * for @typescript-eslint/parser - */ throw new Error(ERROR_MESSAGE); } - return context.parserServices as RequiredParserServices; + + const hasFullTypeInformation = + context.parserServices.hasFullTypeInformation ?? + /* backwards compatible */ true; + + // if a rule requires full type information, then hard fail if it doesn't exist + // this forces the user to supply parserOptions.project + if (!hasFullTypeInformation && !allowWithoutFullTypeInformation) { + throw new Error(ERROR_MESSAGE); + } + + return context.parserServices; } export { getParserServices }; diff --git a/packages/typescript-estree/src/ast-converter.ts b/packages/typescript-estree/src/ast-converter.ts index 54f325429dff..36ca1830ccd7 100644 --- a/packages/typescript-estree/src/ast-converter.ts +++ b/packages/typescript-estree/src/ast-converter.ts @@ -10,7 +10,7 @@ export function astConverter( ast: SourceFile, extra: Extra, shouldPreserveNodeMaps: boolean, -): { estree: TSESTree.Program; astMaps: ASTMaps | undefined } { +): { estree: TSESTree.Program; astMaps: ASTMaps } { /** * The TypeScript compiler produced fundamental parse errors when parsing the * source. @@ -63,7 +63,7 @@ export function astConverter( estree.comments = convertComments(ast, extra.code); } - const astMaps = shouldPreserveNodeMaps ? instance.getASTMaps() : undefined; + const astMaps = instance.getASTMaps(); return { estree, astMaps }; } diff --git a/packages/typescript-estree/src/create-program/createProjectProgram.ts b/packages/typescript-estree/src/create-program/createProjectProgram.ts index c7949b02811a..bca6fda10051 100644 --- a/packages/typescript-estree/src/create-program/createProjectProgram.ts +++ b/packages/typescript-estree/src/create-program/createProjectProgram.ts @@ -93,7 +93,6 @@ function createProjectProgram( errorLines.push( 'The file must be included in at least one of the projects provided.', ); - hasMatchedAnError = true; } throw new Error(errorLines.join('\n')); diff --git a/packages/typescript-estree/src/create-program/shared.ts b/packages/typescript-estree/src/create-program/shared.ts index 1aa6a4fe3c0c..702e7884ccb5 100644 --- a/packages/typescript-estree/src/create-program/shared.ts +++ b/packages/typescript-estree/src/create-program/shared.ts @@ -4,7 +4,7 @@ import { Extra } from '../parser-options'; interface ASTAndProgram { ast: ts.SourceFile; - program: ts.Program | undefined; + program: ts.Program; } /** @@ -16,6 +16,9 @@ const DEFAULT_COMPILER_OPTIONS: ts.CompilerOptions = { checkJs: true, noEmit: true, // extendedDiagnostics: true, + /** + * Flags required to make no-unused-vars work + */ noUnusedLocals: true, noUnusedParameters: true, }; diff --git a/packages/typescript-estree/src/parser-options.ts b/packages/typescript-estree/src/parser-options.ts index e901ee74957c..0f423abb0cfb 100644 --- a/packages/typescript-estree/src/parser-options.ts +++ b/packages/typescript-estree/src/parser-options.ts @@ -184,9 +184,8 @@ export interface ParserWeakMapESTreeToTSNode< } export interface ParserServices { - program: Program | undefined; - esTreeNodeToTSNodeMap: ParserWeakMapESTreeToTSNode | undefined; - tsNodeToESTreeNodeMap: - | ParserWeakMap - | undefined; + program: Program; + esTreeNodeToTSNodeMap: ParserWeakMapESTreeToTSNode; + tsNodeToESTreeNodeMap: ParserWeakMap; + hasFullTypeInformation: boolean; } diff --git a/packages/typescript-estree/src/parser.ts b/packages/typescript-estree/src/parser.ts index 069e8af19601..57fbc01abab5 100644 --- a/packages/typescript-estree/src/parser.ts +++ b/packages/typescript-estree/src/parser.ts @@ -12,7 +12,7 @@ import { createSourceFile } from './create-program/createSourceFile'; import { Extra, TSESTreeOptions, ParserServices } from './parser-options'; import { getFirstSemanticOrSyntacticError } from './semantic-or-syntactic-errors'; import { TSESTree } from './ts-estree'; -import { ensureAbsolutePath } from './create-program/shared'; +import { ASTAndProgram, ensureAbsolutePath } from './create-program/shared'; const log = debug('typescript-eslint:typescript-estree:parser'); @@ -48,11 +48,6 @@ function enforceString(code: unknown): string { return code; } -interface ASTAndProgram { - ast: ts.SourceFile; - program: ts.Program | undefined; -} - /** * @param code The code of the file being linted * @param shouldProvideParserServices True if the program should be attempted to be calculated from provided tsconfig files @@ -63,7 +58,7 @@ function getProgramAndAST( code: string, shouldProvideParserServices: boolean, shouldCreateDefaultProgram: boolean, -): ASTAndProgram | undefined { +): ASTAndProgram { return ( (shouldProvideParserServices && createProjectProgram(code, shouldCreateDefaultProgram, extra)) || @@ -103,7 +98,7 @@ function resetExtra(): void { jsx: false, loc: false, log: console.log, // eslint-disable-line no-console - preserveNodeMaps: undefined, + preserveNodeMaps: true, projects: [], range: false, strict: false, @@ -236,7 +231,7 @@ function applyParserOptionsToExtra(options: TSESTreeOptions): void { } /** - * Get the file extension + * Get the file path */ if (typeof options.filePath === 'string' && options.filePath !== '') { extra.filePath = options.filePath; @@ -298,14 +293,9 @@ function applyParserOptionsToExtra(options: TSESTreeOptions): void { /** * Allow the user to enable or disable the preservation of the AST node maps * during the conversion process. - * - * NOTE: For backwards compatibility we also preserve node maps in the case where `project` is set, - * and `preserveNodeMaps` is not explicitly set to anything. */ - extra.preserveNodeMaps = - typeof options.preserveNodeMaps === 'boolean' && options.preserveNodeMaps; - if (options.preserveNodeMaps === undefined && extra.projects.length > 0) { - extra.preserveNodeMaps = true; + if (typeof options.preserveNodeMaps === 'boolean') { + extra.preserveNodeMaps = options.preserveNodeMaps; } extra.createDefaultProgram = @@ -449,20 +439,13 @@ function parseAndGenerateServices( extra.createDefaultProgram, )!; - /** - * Determine if two-way maps of converted AST nodes should be preserved - * during the conversion process - */ - const shouldPreserveNodeMaps = - extra.preserveNodeMaps !== undefined - ? extra.preserveNodeMaps - : shouldProvideParserServices; - /** * Convert the TypeScript AST to an ESTree-compatible one, and optionally preserve * mappings between converted and original AST nodes */ - const { estree, astMaps } = astConverter(ast, extra, shouldPreserveNodeMaps); + const preserveNodeMaps = + typeof extra.preserveNodeMaps === 'boolean' ? extra.preserveNodeMaps : true; + const { estree, astMaps } = astConverter(ast, extra, preserveNodeMaps); /** * Even if TypeScript parsed the source code ok, and we had no problems converting the AST, @@ -481,15 +464,10 @@ function parseAndGenerateServices( return { ast: estree as AST, services: { - program: shouldProvideParserServices ? program : undefined, - esTreeNodeToTSNodeMap: - shouldPreserveNodeMaps && astMaps - ? astMaps.esTreeNodeToTSNodeMap - : undefined, - tsNodeToESTreeNodeMap: - shouldPreserveNodeMaps && astMaps - ? astMaps.tsNodeToESTreeNodeMap - : undefined, + hasFullTypeInformation: shouldProvideParserServices, + program, + esTreeNodeToTSNodeMap: astMaps.esTreeNodeToTSNodeMap, + tsNodeToESTreeNodeMap: astMaps.tsNodeToESTreeNodeMap, }, }; } diff --git a/packages/typescript-estree/tests/lib/__snapshots__/parse.ts.snap b/packages/typescript-estree/tests/lib/__snapshots__/parse.ts.snap index 4b6d7f2c7839..8ea937e0cd9b 100644 --- a/packages/typescript-estree/tests/lib/__snapshots__/parse.ts.snap +++ b/packages/typescript-estree/tests/lib/__snapshots__/parse.ts.snap @@ -649,9 +649,10 @@ Object { "type": "Program", }, "services": Object { - "esTreeNodeToTSNodeMap": undefined, - "program": undefined, - "tsNodeToESTreeNodeMap": undefined, + "esTreeNodeToTSNodeMap": WeakMap {}, + "hasFullTypeInformation": false, + "program": Object {}, + "tsNodeToESTreeNodeMap": WeakMap {}, }, } `; @@ -938,9 +939,10 @@ Object { "type": "Program", }, "services": Object { - "esTreeNodeToTSNodeMap": undefined, - "program": undefined, - "tsNodeToESTreeNodeMap": undefined, + "esTreeNodeToTSNodeMap": WeakMap {}, + "hasFullTypeInformation": false, + "program": Object {}, + "tsNodeToESTreeNodeMap": WeakMap {}, }, } `; @@ -1117,9 +1119,10 @@ Object { "type": "Program", }, "services": Object { - "esTreeNodeToTSNodeMap": undefined, - "program": undefined, - "tsNodeToESTreeNodeMap": undefined, + "esTreeNodeToTSNodeMap": WeakMap {}, + "hasFullTypeInformation": false, + "program": Object {}, + "tsNodeToESTreeNodeMap": WeakMap {}, }, } `; @@ -1296,9 +1299,10 @@ Object { "type": "Program", }, "services": Object { - "esTreeNodeToTSNodeMap": undefined, - "program": undefined, - "tsNodeToESTreeNodeMap": undefined, + "esTreeNodeToTSNodeMap": WeakMap {}, + "hasFullTypeInformation": false, + "program": Object {}, + "tsNodeToESTreeNodeMap": WeakMap {}, }, } `; @@ -1514,9 +1518,10 @@ Object { "type": "Program", }, "services": Object { - "esTreeNodeToTSNodeMap": undefined, - "program": undefined, - "tsNodeToESTreeNodeMap": undefined, + "esTreeNodeToTSNodeMap": WeakMap {}, + "hasFullTypeInformation": false, + "program": Object {}, + "tsNodeToESTreeNodeMap": WeakMap {}, }, } `; @@ -1803,9 +1808,10 @@ Object { "type": "Program", }, "services": Object { - "esTreeNodeToTSNodeMap": undefined, - "program": undefined, - "tsNodeToESTreeNodeMap": undefined, + "esTreeNodeToTSNodeMap": WeakMap {}, + "hasFullTypeInformation": false, + "program": Object {}, + "tsNodeToESTreeNodeMap": WeakMap {}, }, } `; @@ -2092,9 +2098,10 @@ Object { "type": "Program", }, "services": Object { - "esTreeNodeToTSNodeMap": undefined, - "program": undefined, - "tsNodeToESTreeNodeMap": undefined, + "esTreeNodeToTSNodeMap": WeakMap {}, + "hasFullTypeInformation": false, + "program": Object {}, + "tsNodeToESTreeNodeMap": WeakMap {}, }, } `; @@ -2271,9 +2278,10 @@ Object { "type": "Program", }, "services": Object { - "esTreeNodeToTSNodeMap": undefined, - "program": undefined, - "tsNodeToESTreeNodeMap": undefined, + "esTreeNodeToTSNodeMap": WeakMap {}, + "hasFullTypeInformation": false, + "program": Object {}, + "tsNodeToESTreeNodeMap": WeakMap {}, }, } `; @@ -2450,9 +2458,10 @@ Object { "type": "Program", }, "services": Object { - "esTreeNodeToTSNodeMap": undefined, - "program": undefined, - "tsNodeToESTreeNodeMap": undefined, + "esTreeNodeToTSNodeMap": WeakMap {}, + "hasFullTypeInformation": false, + "program": Object {}, + "tsNodeToESTreeNodeMap": WeakMap {}, }, } `; @@ -2629,9 +2638,10 @@ Object { "type": "Program", }, "services": Object { - "esTreeNodeToTSNodeMap": undefined, - "program": undefined, - "tsNodeToESTreeNodeMap": undefined, + "esTreeNodeToTSNodeMap": WeakMap {}, + "hasFullTypeInformation": false, + "program": Object {}, + "tsNodeToESTreeNodeMap": WeakMap {}, }, } `; @@ -2808,9 +2818,10 @@ Object { "type": "Program", }, "services": Object { - "esTreeNodeToTSNodeMap": undefined, - "program": undefined, - "tsNodeToESTreeNodeMap": undefined, + "esTreeNodeToTSNodeMap": WeakMap {}, + "hasFullTypeInformation": false, + "program": Object {}, + "tsNodeToESTreeNodeMap": WeakMap {}, }, } `; @@ -3097,9 +3108,10 @@ Object { "type": "Program", }, "services": Object { - "esTreeNodeToTSNodeMap": undefined, - "program": undefined, - "tsNodeToESTreeNodeMap": undefined, + "esTreeNodeToTSNodeMap": WeakMap {}, + "hasFullTypeInformation": false, + "program": Object {}, + "tsNodeToESTreeNodeMap": WeakMap {}, }, } `; @@ -3386,9 +3398,10 @@ Object { "type": "Program", }, "services": Object { - "esTreeNodeToTSNodeMap": undefined, - "program": undefined, - "tsNodeToESTreeNodeMap": undefined, + "esTreeNodeToTSNodeMap": WeakMap {}, + "hasFullTypeInformation": false, + "program": Object {}, + "tsNodeToESTreeNodeMap": WeakMap {}, }, } `; @@ -3565,9 +3578,10 @@ Object { "type": "Program", }, "services": Object { - "esTreeNodeToTSNodeMap": undefined, - "program": undefined, - "tsNodeToESTreeNodeMap": undefined, + "esTreeNodeToTSNodeMap": WeakMap {}, + "hasFullTypeInformation": false, + "program": Object {}, + "tsNodeToESTreeNodeMap": WeakMap {}, }, } `; @@ -3744,9 +3758,10 @@ Object { "type": "Program", }, "services": Object { - "esTreeNodeToTSNodeMap": undefined, - "program": undefined, - "tsNodeToESTreeNodeMap": undefined, + "esTreeNodeToTSNodeMap": WeakMap {}, + "hasFullTypeInformation": false, + "program": Object {}, + "tsNodeToESTreeNodeMap": WeakMap {}, }, } `; @@ -4033,9 +4048,10 @@ Object { "type": "Program", }, "services": Object { - "esTreeNodeToTSNodeMap": undefined, - "program": undefined, - "tsNodeToESTreeNodeMap": undefined, + "esTreeNodeToTSNodeMap": WeakMap {}, + "hasFullTypeInformation": false, + "program": Object {}, + "tsNodeToESTreeNodeMap": WeakMap {}, }, } `; @@ -4212,9 +4228,10 @@ Object { "type": "Program", }, "services": Object { - "esTreeNodeToTSNodeMap": undefined, - "program": undefined, - "tsNodeToESTreeNodeMap": undefined, + "esTreeNodeToTSNodeMap": WeakMap {}, + "hasFullTypeInformation": false, + "program": Object {}, + "tsNodeToESTreeNodeMap": WeakMap {}, }, } `; @@ -4391,9 +4408,10 @@ Object { "type": "Program", }, "services": Object { - "esTreeNodeToTSNodeMap": undefined, - "program": undefined, - "tsNodeToESTreeNodeMap": undefined, + "esTreeNodeToTSNodeMap": WeakMap {}, + "hasFullTypeInformation": false, + "program": Object {}, + "tsNodeToESTreeNodeMap": WeakMap {}, }, } `; diff --git a/packages/typescript-estree/tests/lib/convert.ts b/packages/typescript-estree/tests/lib/convert.ts index 749f26737f09..0dd26908dd6d 100644 --- a/packages/typescript-estree/tests/lib/convert.ts +++ b/packages/typescript-estree/tests/lib/convert.ts @@ -111,8 +111,8 @@ describe('convert', () => { instance.convertProgram(); const maps = instance.getASTMaps(); - function checkMaps(child: any): void { - child.forEachChild((node: any) => { + function checkMaps(child: ts.SourceFile | ts.Node): void { + child.forEachChild(node => { if ( node.kind !== ts.SyntaxKind.EndOfFileToken && node.kind !== ts.SyntaxKind.JsxAttributes && @@ -120,7 +120,7 @@ describe('convert', () => { ) { expect(node).toBe( maps.esTreeNodeToTSNodeMap.get( - maps.tsNodeToESTreeNodeMap.get(node), + maps.tsNodeToESTreeNodeMap.get(node as any), ), ); } @@ -145,15 +145,15 @@ describe('convert', () => { instance.convertProgram(); const maps = instance.getASTMaps(); - function checkMaps(child: any): void { - child.forEachChild((node: any) => { + function checkMaps(child: ts.SourceFile | ts.Node): void { + child.forEachChild(node => { if ( node.kind !== ts.SyntaxKind.EndOfFileToken && node.kind !== ts.SyntaxKind.JsxAttributes ) { expect(node).toBe( maps.esTreeNodeToTSNodeMap.get( - maps.tsNodeToESTreeNodeMap.get(node), + maps.tsNodeToESTreeNodeMap.get(node as any), ), ); } @@ -178,8 +178,8 @@ describe('convert', () => { const program = instance.convertProgram(); const maps = instance.getASTMaps(); - function checkMaps(child: any): void { - child.forEachChild((node: any) => { + function checkMaps(child: ts.SourceFile | ts.Node): void { + child.forEachChild(node => { if (node.kind !== ts.SyntaxKind.EndOfFileToken) { expect(ast).toBe( maps.esTreeNodeToTSNodeMap.get(maps.tsNodeToESTreeNodeMap.get(ast)), diff --git a/packages/typescript-estree/tests/lib/parse.ts b/packages/typescript-estree/tests/lib/parse.ts index 9c049ae882d5..2504a2fe3320 100644 --- a/packages/typescript-estree/tests/lib/parse.ts +++ b/packages/typescript-estree/tests/lib/parse.ts @@ -6,7 +6,7 @@ import { TSESTreeOptions } from '../../src/parser-options'; import * as sharedParserUtils from '../../src/create-program/shared'; import { createSnapshotTestBlock } from '../../tools/test-utils'; -const FIXTURES_DIR = './tests/fixtures/simpleProject'; +const FIXTURES_DIR = join(__dirname, '../fixtures/simpleProject'); describe('parse()', () => { describe('basic functionality', () => { @@ -176,11 +176,15 @@ describe('parse()', () => { ); }); - it('should not preserve node maps by default for parseAndGenerateServices(), unless `project` is set', () => { + it('should preserve node maps by default for parseAndGenerateServices()', () => { const noOptionSet = parser.parseAndGenerateServices(code, baseConfig); - expect(noOptionSet.services.esTreeNodeToTSNodeMap).toBeUndefined(); - expect(noOptionSet.services.tsNodeToESTreeNodeMap).toBeUndefined(); + expect(noOptionSet.services.esTreeNodeToTSNodeMap).toEqual( + expect.any(WeakMap), + ); + expect(noOptionSet.services.tsNodeToESTreeNodeMap).toEqual( + expect.any(WeakMap), + ); const withProjectNoOptionSet = parser.parseAndGenerateServices( code, @@ -195,55 +199,56 @@ describe('parse()', () => { ); }); - it('should preserve node maps for parseAndGenerateServices() when option is `true`, regardless of `project` config', () => { - const optionSetToTrue = parser.parseAndGenerateServices(code, { - ...baseConfig, - preserveNodeMaps: true, - }); - - expect(optionSetToTrue.services.esTreeNodeToTSNodeMap).toEqual( - expect.any(WeakMap), - ); - expect(optionSetToTrue.services.tsNodeToESTreeNodeMap).toEqual( - expect.any(WeakMap), - ); + function checkNodeMaps(setting: boolean): void { + it('without project', () => { + const parseResult = parser.parseAndGenerateServices(code, { + ...baseConfig, + preserveNodeMaps: setting, + }); - const withProjectOptionSetToTrue = parser.parseAndGenerateServices(code, { - ...projectConfig, - preserveNodeMaps: true, + expect(parseResult.services.esTreeNodeToTSNodeMap).toBeDefined(); + expect(parseResult.services.tsNodeToESTreeNodeMap).toBeDefined(); + expect( + parseResult.services.esTreeNodeToTSNodeMap.has( + parseResult.ast.body[0], + ), + ).toBe(setting); + expect( + parseResult.services.tsNodeToESTreeNodeMap.has( + parseResult.services.program.getSourceFile('estree.ts'), + ), + ).toBe(setting); }); - expect(withProjectOptionSetToTrue.services.esTreeNodeToTSNodeMap).toEqual( - expect.any(WeakMap), - ); - expect(withProjectOptionSetToTrue.services.tsNodeToESTreeNodeMap).toEqual( - expect.any(WeakMap), - ); - }); + it('with project', () => { + const parseResult = parser.parseAndGenerateServices(code, { + ...projectConfig, + preserveNodeMaps: setting, + }); - it('should not preserve node maps for parseAndGenerateServices() when option is `false`, regardless of `project` config', () => { - const optionSetToFalse = parser.parseAndGenerateServices(code, { - ...baseConfig, - preserveNodeMaps: false, + expect(parseResult.services.esTreeNodeToTSNodeMap).toBeDefined(); + expect(parseResult.services.tsNodeToESTreeNodeMap).toBeDefined(); + expect( + parseResult.services.esTreeNodeToTSNodeMap.has( + parseResult.ast.body[0], + ), + ).toBe(setting); + expect( + parseResult.services.tsNodeToESTreeNodeMap.has( + parseResult.services.program.getSourceFile( + join(FIXTURES_DIR, 'file.ts'), + ), + ), + ).toBe(setting); }); + } - expect(optionSetToFalse.services.esTreeNodeToTSNodeMap).toBeUndefined(); - expect(optionSetToFalse.services.tsNodeToESTreeNodeMap).toBeUndefined(); - - const withProjectOptionSetToFalse = parser.parseAndGenerateServices( - code, - { - ...projectConfig, - preserveNodeMaps: false, - }, - ); + describe('should preserve node maps for parseAndGenerateServices() when option is `true`, regardless of `project` config', () => { + checkNodeMaps(true); + }); - expect( - withProjectOptionSetToFalse.services.esTreeNodeToTSNodeMap, - ).toBeUndefined(); - expect( - withProjectOptionSetToFalse.services.tsNodeToESTreeNodeMap, - ).toBeUndefined(); + describe('should not preserve node maps for parseAndGenerateServices() when option is `false`, regardless of `project` config', () => { + checkNodeMaps(false); }); }); @@ -274,7 +279,9 @@ describe('parse()', () => { it(`should parse ${ext} file - ${ jsxContent ? 'with' : 'without' } JSX content - parserOptions.jsx = ${jsxSetting}`, () => { - let result; + let result: + | parser.ParseAndGenerateServicesResult + | undefined; const exp = expect(() => { result = parser.parseAndGenerateServices(code, { ...config, @@ -289,7 +296,16 @@ describe('parse()', () => { } if (!shouldThrow) { - expect(result).toMatchSnapshot(); + expect(result?.services.program).toBeDefined(); + expect(result?.ast).toBeDefined(); + expect({ + ...result, + services: { + ...result?.services, + // Reduce noise in snapshot + program: {}, + }, + }).toMatchSnapshot(); } }); }; diff --git a/packages/typescript-estree/tests/lib/semanticInfo.ts b/packages/typescript-estree/tests/lib/semanticInfo.ts index ba617b57744e..ee9f4c9150dc 100644 --- a/packages/typescript-estree/tests/lib/semanticInfo.ts +++ b/packages/typescript-estree/tests/lib/semanticInfo.ts @@ -151,7 +151,7 @@ describe('semanticInfo', () => { expect(parseResult).toHaveProperty('services.esTreeNodeToTSNodeMap'); const binaryExpression = (parseResult.ast .body[0] as TSESTree.VariableDeclaration).declarations[0].init!; - const tsBinaryExpression = parseResult.services.esTreeNodeToTSNodeMap!.get( + const tsBinaryExpression = parseResult.services.esTreeNodeToTSNodeMap.get( binaryExpression, ); expect(tsBinaryExpression.kind).toEqual(ts.SyntaxKind.BinaryExpression); @@ -159,7 +159,7 @@ describe('semanticInfo', () => { const computedPropertyString = ((parseResult.ast .body[1] as TSESTree.ClassDeclaration).body .body[0] as TSESTree.ClassProperty).key; - const tsComputedPropertyString = parseResult.services.esTreeNodeToTSNodeMap!.get( + const tsComputedPropertyString = parseResult.services.esTreeNodeToTSNodeMap.get( computedPropertyString, ); expect(tsComputedPropertyString.kind).toEqual(ts.SyntaxKind.StringLiteral); @@ -174,7 +174,7 @@ describe('semanticInfo', () => { // get type checker expect(parseResult).toHaveProperty('services.program.getTypeChecker'); - const checker = parseResult.services.program!.getTypeChecker(); + const checker = parseResult.services.program.getTypeChecker(); // get array node (ast shape validated by snapshot) // node is defined in other file than the parsed one @@ -185,14 +185,14 @@ describe('semanticInfo', () => { expect(arrayBoundName.name).toBe('arr'); expect(parseResult).toHaveProperty('services.esTreeNodeToTSNodeMap'); - const tsArrayBoundName = parseResult.services.esTreeNodeToTSNodeMap!.get( + const tsArrayBoundName = parseResult.services.esTreeNodeToTSNodeMap.get( arrayBoundName, ); expect(tsArrayBoundName).toBeDefined(); checkNumberArrayType(checker, tsArrayBoundName); expect( - parseResult.services.tsNodeToESTreeNodeMap!.get(tsArrayBoundName), + parseResult.services.tsNodeToESTreeNodeMap.get(tsArrayBoundName), ).toBe(arrayBoundName); }); @@ -206,19 +206,19 @@ describe('semanticInfo', () => { }, ); - expect(parseResult.services.program).toBeUndefined(); + expect(parseResult.services.program).toBeDefined(); // get bound name const boundName = (parseResult.ast.body[0] as TSESTree.VariableDeclaration) .declarations[0].id as TSESTree.Identifier; expect(boundName.name).toBe('x'); - const tsBoundName = parseResult.services.esTreeNodeToTSNodeMap!.get( + const tsBoundName = parseResult.services.esTreeNodeToTSNodeMap.get( boundName, ); expect(tsBoundName).toBeDefined(); - expect(parseResult.services.tsNodeToESTreeNodeMap!.get(tsBoundName)).toBe( + expect(parseResult.services.tsNodeToESTreeNodeMap.get(tsBoundName)).toBe( boundName, ); }); @@ -229,7 +229,7 @@ describe('semanticInfo', () => { { ...createOptions(''), project: undefined }, ); - expect(parseResult.services.program).toBeUndefined(); + expect(parseResult.services.program).toBeDefined(); }); it(`non-existent file should throw error when project provided`, () => { @@ -286,7 +286,7 @@ function testIsolatedFile( ): void { // get type checker expect(parseResult).toHaveProperty('services.program.getTypeChecker'); - const checker = parseResult.services.program!.getTypeChecker(); + const checker = parseResult.services.program.getTypeChecker(); // get number node (ast shape validated by snapshot) const declaration = (parseResult.ast.body[0] as TSESTree.VariableDeclaration) @@ -296,7 +296,7 @@ function testIsolatedFile( expect(parseResult).toHaveProperty('services.esTreeNodeToTSNodeMap'); // get corresponding TS node - const tsArrayMember = parseResult.services.esTreeNodeToTSNodeMap!.get( + const tsArrayMember = parseResult.services.esTreeNodeToTSNodeMap.get( arrayMember, ); expect(tsArrayMember).toBeDefined(); @@ -312,19 +312,17 @@ function testIsolatedFile( // make sure it maps back to original ESTree node expect(parseResult).toHaveProperty('services.tsNodeToESTreeNodeMap'); - expect(parseResult.services.tsNodeToESTreeNodeMap!.get(tsArrayMember)).toBe( + expect(parseResult.services.tsNodeToESTreeNodeMap.get(tsArrayMember)).toBe( arrayMember, ); // get bound name const boundName = declaration.id as TSESTree.Identifier; expect(boundName.name).toBe('x'); - const tsBoundName = parseResult.services.esTreeNodeToTSNodeMap!.get( - boundName, - ); + const tsBoundName = parseResult.services.esTreeNodeToTSNodeMap.get(boundName); expect(tsBoundName).toBeDefined(); checkNumberArrayType(checker, tsBoundName); - expect(parseResult.services.tsNodeToESTreeNodeMap!.get(tsBoundName)).toBe( + expect(parseResult.services.tsNodeToESTreeNodeMap.get(tsBoundName)).toBe( boundName, ); } From b6c3b7b84b8d199fa75a46432febd4a364a63217 Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Sat, 9 May 2020 17:45:08 -0700 Subject: [PATCH 11/33] feat: drop support for node v8 (#1997) --- .github/workflows/ci.yml | 2 +- package.json | 2 +- packages/eslint-plugin-tslint/package.json | 2 +- packages/eslint-plugin/package.json | 2 +- packages/experimental-utils/package.json | 2 +- packages/parser/package.json | 2 +- packages/typescript-estree/package.json | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 62502349d9fa..8fcbc40561c0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -140,7 +140,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [8.x, 10.x] + node-version: [10.x, 14.x] steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.node-version }} diff --git a/package.json b/package.json index 14c09a7d3f64..164fe95a34c0 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ ] }, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^10.12.0 || >=12.0.0" }, "devDependencies": { "@commitlint/cli": "^8.3.5", diff --git a/packages/eslint-plugin-tslint/package.json b/packages/eslint-plugin-tslint/package.json index 16d0949f2f48..d56f9232de09 100644 --- a/packages/eslint-plugin-tslint/package.json +++ b/packages/eslint-plugin-tslint/package.json @@ -11,7 +11,7 @@ "tslint" ], "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^10.12.0 || >=12.0.0" }, "repository": { "type": "git", diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index ea80890eef0a..7cb77b22ab70 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -9,7 +9,7 @@ "typescript" ], "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^10.12.0 || >=12.0.0" }, "files": [ "dist", diff --git a/packages/experimental-utils/package.json b/packages/experimental-utils/package.json index c6b35d0f1cc5..b05dda94129e 100644 --- a/packages/experimental-utils/package.json +++ b/packages/experimental-utils/package.json @@ -8,7 +8,7 @@ "estree" ], "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^10.12.0 || >=12.0.0" }, "files": [ "dist", diff --git a/packages/parser/package.json b/packages/parser/package.json index c28df64833cb..630a0a61d14f 100644 --- a/packages/parser/package.json +++ b/packages/parser/package.json @@ -10,7 +10,7 @@ "LICENSE" ], "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^10.12.0 || >=12.0.0" }, "repository": { "type": "git", diff --git a/packages/typescript-estree/package.json b/packages/typescript-estree/package.json index 5568f20ff8f2..14e3b4d6cacd 100644 --- a/packages/typescript-estree/package.json +++ b/packages/typescript-estree/package.json @@ -10,7 +10,7 @@ "LICENSE" ], "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^10.12.0 || >=12.0.0" }, "repository": { "type": "git", From 0e0010f82952f9beeeb84136eea00cc5eecc9db6 Mon Sep 17 00:00:00 2001 From: Armano Date: Sun, 10 May 2020 06:00:26 +0200 Subject: [PATCH 12/33] feat(typescript-estree): align optional fields (#1429) --- .../lib/__snapshots__/typescript.ts.snap | 731 ++++ ...class-with-optional-computed-method.src.ts | 17 + packages/typescript-estree/src/convert.ts | 7 +- .../src/ts-estree/ts-estree.ts | 2 + .../tests/ast-alignment/fixtures-to-test.ts | 14 +- .../tests/ast-alignment/utils.ts | 18 + .../semantic-diagnostics-enabled.ts.snap | 2 + .../lib/__snapshots__/typescript.ts.snap | 3858 +++++++++++++++-- 8 files changed, 4239 insertions(+), 410 deletions(-) create mode 100644 packages/shared-fixtures/fixtures/typescript/basics/class-with-optional-computed-method.src.ts diff --git a/packages/parser/tests/lib/__snapshots__/typescript.ts.snap b/packages/parser/tests/lib/__snapshots__/typescript.ts.snap index 97450c6c6014..dc8b9db9a835 100644 --- a/packages/parser/tests/lib/__snapshots__/typescript.ts.snap +++ b/packages/parser/tests/lib/__snapshots__/typescript.ts.snap @@ -8149,6 +8149,737 @@ Object { } `; +exports[`typescript fixtures/basics/class-with-optional-computed-method.src 1`] = ` +Object { + "$id": 25, + "block": Object { + "range": Array [ + 0, + 282, + ], + "type": "Program", + }, + "childScopes": Array [ + Object { + "$id": 24, + "block": Object { + "range": Array [ + 0, + 282, + ], + "type": "Program", + }, + "childScopes": Array [ + Object { + "$id": 23, + "block": Object { + "range": Array [ + 111, + 281, + ], + "type": "ClassDeclaration", + }, + "childScopes": Array [ + Object { + "$id": 14, + "block": Object { + "range": Array [ + 153, + 158, + ], + "type": "FunctionExpression", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [], + "throughReferences": Array [], + "type": "function", + "upperScope": Object { + "$ref": 23, + }, + "variableMap": Object { + "arguments": Object { + "$ref": 13, + }, + }, + "variableScope": Object { + "$ref": 14, + }, + "variables": Array [ + Object { + "$id": 13, + "defs": Array [], + "eslintUsed": undefined, + "identifiers": Array [], + "name": "arguments", + "references": Array [], + "scope": Object { + "$ref": 14, + }, + }, + ], + }, + Object { + "$id": 16, + "block": Object { + "range": Array [ + 176, + 181, + ], + "type": "FunctionExpression", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [], + "throughReferences": Array [], + "type": "function", + "upperScope": Object { + "$ref": 23, + }, + "variableMap": Object { + "arguments": Object { + "$ref": 15, + }, + }, + "variableScope": Object { + "$ref": 16, + }, + "variables": Array [ + Object { + "$id": 15, + "defs": Array [], + "eslintUsed": undefined, + "identifiers": Array [], + "name": "arguments", + "references": Array [], + "scope": Object { + "$ref": 16, + }, + }, + ], + }, + Object { + "$id": 18, + "block": Object { + "range": Array [ + 217, + 222, + ], + "type": "FunctionExpression", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [], + "throughReferences": Array [], + "type": "function", + "upperScope": Object { + "$ref": 23, + }, + "variableMap": Object { + "arguments": Object { + "$ref": 17, + }, + }, + "variableScope": Object { + "$ref": 18, + }, + "variables": Array [ + Object { + "$id": 17, + "defs": Array [], + "eslintUsed": undefined, + "identifiers": Array [], + "name": "arguments", + "references": Array [], + "scope": Object { + "$ref": 18, + }, + }, + ], + }, + Object { + "$id": 20, + "block": Object { + "range": Array [ + 239, + 244, + ], + "type": "FunctionExpression", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [], + "throughReferences": Array [], + "type": "function", + "upperScope": Object { + "$ref": 23, + }, + "variableMap": Object { + "arguments": Object { + "$ref": 19, + }, + }, + "variableScope": Object { + "$ref": 20, + }, + "variables": Array [ + Object { + "$id": 19, + "defs": Array [], + "eslintUsed": undefined, + "identifiers": Array [], + "name": "arguments", + "references": Array [], + "scope": Object { + "$ref": 20, + }, + }, + ], + }, + Object { + "$id": 22, + "block": Object { + "range": Array [ + 274, + 279, + ], + "type": "FunctionExpression", + }, + "childScopes": Array [], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [], + "throughReferences": Array [], + "type": "function", + "upperScope": Object { + "$ref": 23, + }, + "variableMap": Object { + "arguments": Object { + "$ref": 21, + }, + }, + "variableScope": Object { + "$ref": 22, + }, + "variables": Array [ + Object { + "$id": 21, + "defs": Array [], + "eslintUsed": undefined, + "identifiers": Array [], + "name": "arguments", + "references": Array [], + "scope": Object { + "$ref": 22, + }, + }, + ], + }, + ], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [ + Object { + "$id": 8, + "from": Object { + "$ref": 23, + }, + "identifier": Object { + "name": "computed1", + "range": Array [ + 124, + 133, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": undefined, + }, + Object { + "$id": 9, + "from": Object { + "$ref": 23, + }, + "identifier": Object { + "name": "computed2", + "range": Array [ + 142, + 151, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 1, + }, + "writeExpr": undefined, + }, + Object { + "$id": 10, + "from": Object { + "$ref": 23, + }, + "identifier": Object { + "name": "obj", + "range": Array [ + 227, + 230, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 2, + }, + "writeExpr": undefined, + }, + Object { + "$id": 11, + "from": Object { + "$ref": 23, + }, + "identifier": Object { + "name": "obj", + "range": Array [ + 249, + 252, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": Object { + "$ref": 2, + }, + "writeExpr": undefined, + }, + Object { + "$id": 12, + "from": Object { + "$ref": 23, + }, + "identifier": Object { + "name": "f", + "range": Array [ + 269, + 270, + ], + "type": "Identifier", + }, + "kind": "r", + "resolved": null, + "writeExpr": undefined, + }, + ], + "throughReferences": Array [ + Object { + "$ref": 8, + }, + Object { + "$ref": 9, + }, + Object { + "$ref": 10, + }, + Object { + "$ref": 11, + }, + Object { + "$ref": 12, + }, + ], + "type": "class", + "upperScope": Object { + "$ref": 24, + }, + "variableMap": Object { + "X": Object { + "$ref": 7, + }, + }, + "variableScope": Object { + "$ref": 24, + }, + "variables": Array [ + Object { + "$id": 7, + "defs": Array [ + Object { + "name": Object { + "name": "X", + "range": Array [ + 117, + 118, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 111, + 281, + ], + "type": "ClassDeclaration", + }, + "parent": undefined, + "type": "ClassName", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "X", + "range": Array [ + 117, + 118, + ], + "type": "Identifier", + }, + ], + "name": "X", + "references": Array [], + "scope": Object { + "$ref": 23, + }, + }, + ], + }, + ], + "functionExpressionScope": false, + "isStrict": true, + "references": Array [ + Object { + "$id": 4, + "from": Object { + "$ref": 24, + }, + "identifier": Object { + "name": "computed1", + "range": Array [ + 6, + 15, + ], + "type": "Identifier", + }, + "kind": "w", + "resolved": Object { + "$ref": 0, + }, + "writeExpr": Object { + "range": Array [ + 18, + 24, + ], + "type": "Literal", + }, + }, + Object { + "$id": 5, + "from": Object { + "$ref": 24, + }, + "identifier": Object { + "name": "computed2", + "range": Array [ + 32, + 41, + ], + "type": "Identifier", + }, + "kind": "w", + "resolved": Object { + "$ref": 1, + }, + "writeExpr": Object { + "range": Array [ + 44, + 50, + ], + "type": "Literal", + }, + }, + Object { + "$id": 6, + "from": Object { + "$ref": 24, + }, + "identifier": Object { + "name": "obj", + "range": Array [ + 58, + 61, + ], + "type": "Identifier", + }, + "kind": "w", + "resolved": Object { + "$ref": 2, + }, + "writeExpr": Object { + "range": Array [ + 64, + 109, + ], + "type": "ObjectExpression", + }, + }, + ], + "throughReferences": Array [ + Object { + "$ref": 12, + }, + ], + "type": "module", + "upperScope": Object { + "$ref": 25, + }, + "variableMap": Object { + "X": Object { + "$ref": 3, + }, + "computed1": Object { + "$ref": 0, + }, + "computed2": Object { + "$ref": 1, + }, + "obj": Object { + "$ref": 2, + }, + }, + "variableScope": Object { + "$ref": 24, + }, + "variables": Array [ + Object { + "$id": 0, + "defs": Array [ + Object { + "name": Object { + "name": "computed1", + "range": Array [ + 6, + 15, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 6, + 24, + ], + "type": "VariableDeclarator", + }, + "parent": Object { + "range": Array [ + 0, + 25, + ], + "type": "VariableDeclaration", + }, + "type": "Variable", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "computed1", + "range": Array [ + 6, + 15, + ], + "type": "Identifier", + }, + ], + "name": "computed1", + "references": Array [ + Object { + "$ref": 4, + }, + Object { + "$ref": 8, + }, + ], + "scope": Object { + "$ref": 24, + }, + }, + Object { + "$id": 1, + "defs": Array [ + Object { + "name": Object { + "name": "computed2", + "range": Array [ + 32, + 41, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 32, + 50, + ], + "type": "VariableDeclarator", + }, + "parent": Object { + "range": Array [ + 26, + 51, + ], + "type": "VariableDeclaration", + }, + "type": "Variable", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "computed2", + "range": Array [ + 32, + 41, + ], + "type": "Identifier", + }, + ], + "name": "computed2", + "references": Array [ + Object { + "$ref": 5, + }, + Object { + "$ref": 9, + }, + ], + "scope": Object { + "$ref": 24, + }, + }, + Object { + "$id": 2, + "defs": Array [ + Object { + "name": Object { + "name": "obj", + "range": Array [ + 58, + 61, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 58, + 109, + ], + "type": "VariableDeclarator", + }, + "parent": Object { + "range": Array [ + 52, + 110, + ], + "type": "VariableDeclaration", + }, + "type": "Variable", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "obj", + "range": Array [ + 58, + 61, + ], + "type": "Identifier", + }, + ], + "name": "obj", + "references": Array [ + Object { + "$ref": 6, + }, + Object { + "$ref": 10, + }, + Object { + "$ref": 11, + }, + ], + "scope": Object { + "$ref": 24, + }, + }, + Object { + "$id": 3, + "defs": Array [ + Object { + "name": Object { + "name": "X", + "range": Array [ + 117, + 118, + ], + "type": "Identifier", + }, + "node": Object { + "range": Array [ + 111, + 281, + ], + "type": "ClassDeclaration", + }, + "parent": null, + "type": "ClassName", + }, + ], + "eslintUsed": undefined, + "identifiers": Array [ + Object { + "name": "X", + "range": Array [ + 117, + 118, + ], + "type": "Identifier", + }, + ], + "name": "X", + "references": Array [], + "scope": Object { + "$ref": 24, + }, + }, + ], + }, + ], + "functionExpressionScope": false, + "isStrict": false, + "references": Array [], + "throughReferences": Array [ + Object { + "$ref": 12, + }, + ], + "type": "global", + "upperScope": null, + "variableMap": Object {}, + "variableScope": Object { + "$ref": 25, + }, + "variables": Array [], +} +`; + exports[`typescript fixtures/basics/class-with-optional-computed-property.src 1`] = ` Object { "$id": 5, diff --git a/packages/shared-fixtures/fixtures/typescript/basics/class-with-optional-computed-method.src.ts b/packages/shared-fixtures/fixtures/typescript/basics/class-with-optional-computed-method.src.ts new file mode 100644 index 000000000000..947cb550c2ce --- /dev/null +++ b/packages/shared-fixtures/fixtures/typescript/basics/class-with-optional-computed-method.src.ts @@ -0,0 +1,17 @@ +const computed1 = "buzz"; +const computed2 = "bazz"; +const obj = { + member: "member", + member2: "member2", +}; +class X { + [computed1]?(); + [computed2]?() {}; + [1]?(); + [2]?() {}; + ["literal1"]?(); + ["literal2"]?() {}; + [obj.member]?() {}; + [obj.member2]?(); + [f()]?() {} +} diff --git a/packages/typescript-estree/src/convert.ts b/packages/typescript-estree/src/convert.ts index f6770453581a..dc4a1a0091a9 100644 --- a/packages/typescript-estree/src/convert.ts +++ b/packages/typescript-estree/src/convert.ts @@ -1084,11 +1084,8 @@ export class Converter { } } - if ( - result.key.type === AST_NODE_TYPES.Identifier && - node.questionToken - ) { - result.key.optional = true; + if (node.questionToken) { + result.optional = true; } if (node.kind === SyntaxKind.GetAccessor) { diff --git a/packages/typescript-estree/src/ts-estree/ts-estree.ts b/packages/typescript-estree/src/ts-estree/ts-estree.ts index 1bfb323e3d76..bb7944b4baef 100644 --- a/packages/typescript-estree/src/ts-estree/ts-estree.ts +++ b/packages/typescript-estree/src/ts-estree/ts-estree.ts @@ -656,6 +656,7 @@ interface MethodDefinitionBase extends BaseNode { computed: boolean; static: boolean; kind: 'method' | 'get' | 'set' | 'constructor'; + optional?: boolean; decorators?: Decorator[]; accessibility?: Accessibility; typeParameters?: TSTypeParameterDeclaration; @@ -682,6 +683,7 @@ interface PropertyBase extends BaseNode { computed: boolean; method: boolean; shorthand: boolean; + optional?: boolean; kind: 'init' | 'get' | 'set'; } diff --git a/packages/typescript-estree/tests/ast-alignment/fixtures-to-test.ts b/packages/typescript-estree/tests/ast-alignment/fixtures-to-test.ts index 5254ba0d6c71..e454fe6fb6d6 100644 --- a/packages/typescript-estree/tests/ast-alignment/fixtures-to-test.ts +++ b/packages/typescript-estree/tests/ast-alignment/fixtures-to-test.ts @@ -362,14 +362,6 @@ tester.addFixturePatternConfig('typescript/babylon-convergence', { tester.addFixturePatternConfig('typescript/basics', { fileType: 'ts', ignore: [ - /** - * Babel and ts-estree reports optional field on different nodes - * TODO: investigate - */ - 'class-with-optional-methods', - 'abstract-class-with-abstract-method', - 'abstract-class-with-optional-method', - 'declare-class-with-optional-method', /** * Babel parses it as TSQualifiedName * ts parses it as MemberExpression @@ -399,7 +391,11 @@ tester.addFixturePatternConfig('typescript/basics', { * SyntaxError: 'abstract' modifier can only appear on a class, method, or property declaration. */ 'abstract-class-with-abstract-constructor', - // babel hard fails on computed string enum members, but TS doesn't + /** + * [BABEL ERRORED, BUT TS-ESTREE DID NOT] + * babel hard fails on computed string enum members, but TS doesn't + * TODO: report this to babel + */ 'export-named-enum-computed-string', /** * Babel: TSTypePredicate includes `:` statement in range diff --git a/packages/typescript-estree/tests/ast-alignment/utils.ts b/packages/typescript-estree/tests/ast-alignment/utils.ts index 5bb824705d38..9cdedb452eba 100644 --- a/packages/typescript-estree/tests/ast-alignment/utils.ts +++ b/packages/typescript-estree/tests/ast-alignment/utils.ts @@ -151,6 +151,16 @@ export function preprocessBabylonAST(ast: BabelTypes.File): any { }; } }, + MethodDefinition(node) { + /** + * Babel: MethodDefinition + abstract: true + * ts-estree: TSAbstractClassProperty + */ + if (node.abstract) { + node.type = AST_NODE_TYPES.TSAbstractMethodDefinition; + delete node.abstract; + } + }, ClassProperty(node) { /** * Babel: ClassProperty + abstract: true @@ -198,6 +208,14 @@ export function preprocessBabylonAST(ast: BabelTypes.File): any { node.range[0] = node.typeParameters.range[0]; node.loc.start = Object.assign({}, node.typeParameters.loc.start); } + + /** + * ts-estree: if there's no body, it becomes a TSEmptyBodyFunctionExpression + */ + if (!node.body) { + node.type = AST_NODE_TYPES.TSEmptyBodyFunctionExpression; + node.body = null; + } }, /** * Template strings seem to also be affected by the difference in opinion between different parsers in diff --git a/packages/typescript-estree/tests/lib/__snapshots__/semantic-diagnostics-enabled.ts.snap b/packages/typescript-estree/tests/lib/__snapshots__/semantic-diagnostics-enabled.ts.snap index 124cc7cde046..2cff4d0b441b 100644 --- a/packages/typescript-estree/tests/lib/__snapshots__/semantic-diagnostics-enabled.ts.snap +++ b/packages/typescript-estree/tests/lib/__snapshots__/semantic-diagnostics-enabled.ts.snap @@ -1781,6 +1781,8 @@ exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" e exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" enabled fixtures/typescript/basics/class-with-mixin-reference.src 1`] = `"TEST OUTPUT: No semantic or syntactic issues found"`; +exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" enabled fixtures/typescript/basics/class-with-optional-computed-method.src 1`] = `"TEST OUTPUT: No semantic or syntactic issues found"`; + exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" enabled fixtures/typescript/basics/class-with-optional-computed-property.src 1`] = `"TEST OUTPUT: No semantic or syntactic issues found"`; exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" enabled fixtures/typescript/basics/class-with-optional-methods.src 1`] = `"TEST OUTPUT: No semantic or syntactic issues found"`; diff --git a/packages/typescript-estree/tests/lib/__snapshots__/typescript.ts.snap b/packages/typescript-estree/tests/lib/__snapshots__/typescript.ts.snap index e71820fc060e..7a554e8aa898 100644 --- a/packages/typescript-estree/tests/lib/__snapshots__/typescript.ts.snap +++ b/packages/typescript-estree/tests/lib/__snapshots__/typescript.ts.snap @@ -3901,7 +3901,6 @@ Object { }, }, "name": "createSocket", - "optional": true, "range": Array [ 43, 55, @@ -3919,6 +3918,7 @@ Object { "line": 2, }, }, + "optional": true, "range": Array [ 43, 76, @@ -23788,144 +23788,70 @@ Object { } `; -exports[`typescript fixtures/basics/class-with-optional-computed-property.src 1`] = ` +exports[`typescript fixtures/basics/class-with-optional-computed-method.src 1`] = ` Object { "body": Array [ Object { - "body": Object { - "body": Array [ - Object { - "accessibility": "private", - "computed": true, - "declare": false, - "key": Object { - "loc": Object { - "end": Object { - "column": 18, - "line": 2, - }, - "start": Object { - "column": 13, - "line": 2, - }, - }, - "range": Array [ - 23, - 28, - ], - "raw": "'foo'", - "type": "Literal", - "value": "foo", - }, + "declarations": Array [ + Object { + "id": Object { "loc": Object { "end": Object { - "column": 33, - "line": 2, + "column": 15, + "line": 1, }, "start": Object { - "column": 4, - "line": 2, + "column": 6, + "line": 1, }, }, - "optional": true, + "name": "computed1", "range": Array [ - 14, - 43, + 6, + 15, ], - "static": false, - "type": "ClassProperty", - "value": Object { - "loc": Object { - "end": Object { - "column": 32, - "line": 2, - }, - "start": Object { - "column": 23, - "line": 2, - }, + "type": "Identifier", + }, + "init": Object { + "loc": Object { + "end": Object { + "column": 24, + "line": 1, + }, + "start": Object { + "column": 18, + "line": 1, }, - "name": "undefined", - "range": Array [ - 33, - 42, - ], - "type": "Identifier", }, + "range": Array [ + 18, + 24, + ], + "raw": "\\"buzz\\"", + "type": "Literal", + "value": "buzz", }, - ], - "loc": Object { - "end": Object { - "column": 1, - "line": 3, - }, - "start": Object { - "column": 8, - "line": 1, - }, - }, - "range": Array [ - 8, - 45, - ], - "type": "ClassBody", - }, - "id": Object { - "loc": Object { - "end": Object { - "column": 7, - "line": 1, - }, - "start": Object { - "column": 6, - "line": 1, + "loc": Object { + "end": Object { + "column": 24, + "line": 1, + }, + "start": Object { + "column": 6, + "line": 1, + }, }, + "range": Array [ + 6, + 24, + ], + "type": "VariableDeclarator", }, - "name": "X", - "range": Array [ - 6, - 7, - ], - "type": "Identifier", - }, - "loc": Object { - "end": Object { - "column": 1, - "line": 3, - }, - "start": Object { - "column": 0, - "line": 1, - }, - }, - "range": Array [ - 0, - 45, ], - "superClass": null, - "type": "ClassDeclaration", - }, - ], - "loc": Object { - "end": Object { - "column": 0, - "line": 4, - }, - "start": Object { - "column": 0, - "line": 1, - }, - }, - "range": Array [ - 0, - 46, - ], - "sourceType": "script", - "tokens": Array [ - Object { + "kind": "const", "loc": Object { "end": Object { - "column": 5, + "column": 25, "line": 1, }, "start": Object { @@ -23935,314 +23861,3454 @@ Object { }, "range": Array [ 0, - 5, - ], - "type": "Keyword", - "value": "class", - }, - Object { - "loc": Object { - "end": Object { - "column": 7, - "line": 1, - }, - "start": Object { - "column": 6, - "line": 1, - }, - }, - "range": Array [ - 6, - 7, - ], - "type": "Identifier", - "value": "X", - }, - Object { - "loc": Object { - "end": Object { - "column": 9, - "line": 1, - }, - "start": Object { - "column": 8, - "line": 1, - }, - }, - "range": Array [ - 8, - 9, - ], - "type": "Punctuator", - "value": "{", - }, - Object { - "loc": Object { - "end": Object { - "column": 11, - "line": 2, - }, - "start": Object { - "column": 4, - "line": 2, - }, - }, - "range": Array [ - 14, - 21, - ], - "type": "Keyword", - "value": "private", - }, - Object { - "loc": Object { - "end": Object { - "column": 13, - "line": 2, - }, - "start": Object { - "column": 12, - "line": 2, - }, - }, - "range": Array [ - 22, - 23, - ], - "type": "Punctuator", - "value": "[", - }, - Object { - "loc": Object { - "end": Object { - "column": 18, - "line": 2, - }, - "start": Object { - "column": 13, - "line": 2, - }, - }, - "range": Array [ - 23, - 28, - ], - "type": "String", - "value": "'foo'", - }, - Object { - "loc": Object { - "end": Object { - "column": 19, - "line": 2, - }, - "start": Object { - "column": 18, - "line": 2, - }, - }, - "range": Array [ - 28, - 29, - ], - "type": "Punctuator", - "value": "]", - }, - Object { - "loc": Object { - "end": Object { - "column": 20, - "line": 2, - }, - "start": Object { - "column": 19, - "line": 2, - }, - }, - "range": Array [ - 29, - 30, - ], - "type": "Punctuator", - "value": "?", - }, - Object { - "loc": Object { - "end": Object { - "column": 22, - "line": 2, - }, - "start": Object { - "column": 21, - "line": 2, - }, - }, - "range": Array [ - 31, - 32, + 25, ], - "type": "Punctuator", - "value": "=", + "type": "VariableDeclaration", }, Object { - "loc": Object { - "end": Object { - "column": 32, - "line": 2, - }, - "start": Object { - "column": 23, - "line": 2, + "declarations": Array [ + Object { + "id": Object { + "loc": Object { + "end": Object { + "column": 15, + "line": 2, + }, + "start": Object { + "column": 6, + "line": 2, + }, + }, + "name": "computed2", + "range": Array [ + 32, + 41, + ], + "type": "Identifier", + }, + "init": Object { + "loc": Object { + "end": Object { + "column": 24, + "line": 2, + }, + "start": Object { + "column": 18, + "line": 2, + }, + }, + "range": Array [ + 44, + 50, + ], + "raw": "\\"bazz\\"", + "type": "Literal", + "value": "bazz", + }, + "loc": Object { + "end": Object { + "column": 24, + "line": 2, + }, + "start": Object { + "column": 6, + "line": 2, + }, + }, + "range": Array [ + 32, + 50, + ], + "type": "VariableDeclarator", }, - }, - "range": Array [ - 33, - 42, ], - "type": "Identifier", - "value": "undefined", - }, - Object { + "kind": "const", "loc": Object { "end": Object { - "column": 33, - "line": 2, - }, - "start": Object { - "column": 32, + "column": 25, "line": 2, }, - }, - "range": Array [ - 42, - 43, - ], - "type": "Punctuator", - "value": ";", - }, - Object { - "loc": Object { - "end": Object { - "column": 1, - "line": 3, - }, "start": Object { "column": 0, - "line": 3, + "line": 2, }, }, "range": Array [ - 44, - 45, + 26, + 51, ], - "type": "Punctuator", - "value": "}", + "type": "VariableDeclaration", }, - ], - "type": "Program", -} -`; - -exports[`typescript fixtures/basics/class-with-optional-methods.src 1`] = ` -Object { - "body": Array [ Object { - "body": Object { - "body": Array [ - Object { - "computed": false, - "key": Object { - "loc": Object { - "end": Object { - "column": 5, - "line": 2, - }, - "start": Object { - "column": 2, - "line": 2, - }, - }, - "name": "foo", - "optional": true, - "range": Array [ - 14, - 17, - ], - "type": "Identifier", - }, - "kind": "method", + "declarations": Array [ + Object { + "id": Object { "loc": Object { "end": Object { "column": 9, - "line": 2, + "line": 3, }, "start": Object { - "column": 2, - "line": 2, + "column": 6, + "line": 3, }, }, + "name": "obj", "range": Array [ - 14, - 21, + 58, + 61, ], - "static": false, - "type": "MethodDefinition", - "value": Object { - "async": false, - "body": null, - "expression": false, - "generator": false, - "id": null, - "loc": Object { - "end": Object { - "column": 9, - "line": 2, - }, - "start": Object { - "column": 6, - "line": 2, - }, - }, - "params": Array [], - "range": Array [ - 18, - 21, - ], - "type": "TSEmptyBodyFunctionExpression", - }, + "type": "Identifier", }, - Object { - "computed": false, - "key": Object { - "loc": Object { - "end": Object { - "column": 5, - "line": 3, - }, - "start": Object { - "column": 2, - "line": 3, - }, - }, - "name": "bar", - "optional": true, - "range": Array [ - 24, - 27, - ], - "type": "Identifier", - }, - "kind": "method", + "init": Object { "loc": Object { "end": Object { - "column": 17, - "line": 3, + "column": 1, + "line": 6, }, "start": Object { - "column": 2, + "column": 12, "line": 3, }, }, + "properties": Array [ + Object { + "computed": false, + "key": Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 4, + }, + "start": Object { + "column": 2, + "line": 4, + }, + }, + "name": "member", + "range": Array [ + 68, + 74, + ], + "type": "Identifier", + }, + "kind": "init", + "loc": Object { + "end": Object { + "column": 18, + "line": 4, + }, + "start": Object { + "column": 2, + "line": 4, + }, + }, + "method": false, + "range": Array [ + 68, + 84, + ], + "shorthand": false, + "type": "Property", + "value": Object { + "loc": Object { + "end": Object { + "column": 18, + "line": 4, + }, + "start": Object { + "column": 10, + "line": 4, + }, + }, + "range": Array [ + 76, + 84, + ], + "raw": "\\"member\\"", + "type": "Literal", + "value": "member", + }, + }, + Object { + "computed": false, + "key": Object { + "loc": Object { + "end": Object { + "column": 9, + "line": 5, + }, + "start": Object { + "column": 2, + "line": 5, + }, + }, + "name": "member2", + "range": Array [ + 88, + 95, + ], + "type": "Identifier", + }, + "kind": "init", + "loc": Object { + "end": Object { + "column": 20, + "line": 5, + }, + "start": Object { + "column": 2, + "line": 5, + }, + }, + "method": false, + "range": Array [ + 88, + 106, + ], + "shorthand": false, + "type": "Property", + "value": Object { + "loc": Object { + "end": Object { + "column": 20, + "line": 5, + }, + "start": Object { + "column": 11, + "line": 5, + }, + }, + "range": Array [ + 97, + 106, + ], + "raw": "\\"member2\\"", + "type": "Literal", + "value": "member2", + }, + }, + ], + "range": Array [ + 64, + 109, + ], + "type": "ObjectExpression", + }, + "loc": Object { + "end": Object { + "column": 1, + "line": 6, + }, + "start": Object { + "column": 6, + "line": 3, + }, + }, + "range": Array [ + 58, + 109, + ], + "type": "VariableDeclarator", + }, + ], + "kind": "const", + "loc": Object { + "end": Object { + "column": 2, + "line": 6, + }, + "start": Object { + "column": 0, + "line": 3, + }, + }, + "range": Array [ + 52, + 110, + ], + "type": "VariableDeclaration", + }, + Object { + "body": Object { + "body": Array [ + Object { + "computed": true, + "key": Object { + "loc": Object { + "end": Object { + "column": 12, + "line": 8, + }, + "start": Object { + "column": 3, + "line": 8, + }, + }, + "name": "computed1", + "range": Array [ + 124, + 133, + ], + "type": "Identifier", + }, + "kind": "method", + "loc": Object { + "end": Object { + "column": 17, + "line": 8, + }, + "start": Object { + "column": 2, + "line": 8, + }, + }, + "optional": true, + "range": Array [ + 123, + 138, + ], + "static": false, + "type": "MethodDefinition", + "value": Object { + "async": false, + "body": null, + "expression": false, + "generator": false, + "id": null, + "loc": Object { + "end": Object { + "column": 17, + "line": 8, + }, + "start": Object { + "column": 14, + "line": 8, + }, + }, + "params": Array [], + "range": Array [ + 135, + 138, + ], + "type": "TSEmptyBodyFunctionExpression", + }, + }, + Object { + "computed": true, + "key": Object { + "loc": Object { + "end": Object { + "column": 12, + "line": 9, + }, + "start": Object { + "column": 3, + "line": 9, + }, + }, + "name": "computed2", + "range": Array [ + 142, + 151, + ], + "type": "Identifier", + }, + "kind": "method", + "loc": Object { + "end": Object { + "column": 19, + "line": 9, + }, + "start": Object { + "column": 2, + "line": 9, + }, + }, + "optional": true, + "range": Array [ + 141, + 158, + ], + "static": false, + "type": "MethodDefinition", + "value": Object { + "async": false, + "body": Object { + "body": Array [], + "loc": Object { + "end": Object { + "column": 19, + "line": 9, + }, + "start": Object { + "column": 17, + "line": 9, + }, + }, + "range": Array [ + 156, + 158, + ], + "type": "BlockStatement", + }, + "expression": false, + "generator": false, + "id": null, + "loc": Object { + "end": Object { + "column": 19, + "line": 9, + }, + "start": Object { + "column": 14, + "line": 9, + }, + }, + "params": Array [], + "range": Array [ + 153, + 158, + ], + "type": "FunctionExpression", + }, + }, + Object { + "computed": true, + "key": Object { + "loc": Object { + "end": Object { + "column": 4, + "line": 10, + }, + "start": Object { + "column": 3, + "line": 10, + }, + }, + "range": Array [ + 163, + 164, + ], + "raw": "1", + "type": "Literal", + "value": 1, + }, + "kind": "method", + "loc": Object { + "end": Object { + "column": 9, + "line": 10, + }, + "start": Object { + "column": 2, + "line": 10, + }, + }, + "optional": true, + "range": Array [ + 162, + 169, + ], + "static": false, + "type": "MethodDefinition", + "value": Object { + "async": false, + "body": null, + "expression": false, + "generator": false, + "id": null, + "loc": Object { + "end": Object { + "column": 9, + "line": 10, + }, + "start": Object { + "column": 6, + "line": 10, + }, + }, + "params": Array [], + "range": Array [ + 166, + 169, + ], + "type": "TSEmptyBodyFunctionExpression", + }, + }, + Object { + "computed": true, + "key": Object { + "loc": Object { + "end": Object { + "column": 4, + "line": 11, + }, + "start": Object { + "column": 3, + "line": 11, + }, + }, + "range": Array [ + 173, + 174, + ], + "raw": "2", + "type": "Literal", + "value": 2, + }, + "kind": "method", + "loc": Object { + "end": Object { + "column": 11, + "line": 11, + }, + "start": Object { + "column": 2, + "line": 11, + }, + }, + "optional": true, + "range": Array [ + 172, + 181, + ], + "static": false, + "type": "MethodDefinition", + "value": Object { + "async": false, + "body": Object { + "body": Array [], + "loc": Object { + "end": Object { + "column": 11, + "line": 11, + }, + "start": Object { + "column": 9, + "line": 11, + }, + }, + "range": Array [ + 179, + 181, + ], + "type": "BlockStatement", + }, + "expression": false, + "generator": false, + "id": null, + "loc": Object { + "end": Object { + "column": 11, + "line": 11, + }, + "start": Object { + "column": 6, + "line": 11, + }, + }, + "params": Array [], + "range": Array [ + 176, + 181, + ], + "type": "FunctionExpression", + }, + }, + Object { + "computed": true, + "key": Object { + "loc": Object { + "end": Object { + "column": 13, + "line": 12, + }, + "start": Object { + "column": 3, + "line": 12, + }, + }, + "range": Array [ + 186, + 196, + ], + "raw": "\\"literal1\\"", + "type": "Literal", + "value": "literal1", + }, + "kind": "method", + "loc": Object { + "end": Object { + "column": 18, + "line": 12, + }, + "start": Object { + "column": 2, + "line": 12, + }, + }, + "optional": true, + "range": Array [ + 185, + 201, + ], + "static": false, + "type": "MethodDefinition", + "value": Object { + "async": false, + "body": null, + "expression": false, + "generator": false, + "id": null, + "loc": Object { + "end": Object { + "column": 18, + "line": 12, + }, + "start": Object { + "column": 15, + "line": 12, + }, + }, + "params": Array [], + "range": Array [ + 198, + 201, + ], + "type": "TSEmptyBodyFunctionExpression", + }, + }, + Object { + "computed": true, + "key": Object { + "loc": Object { + "end": Object { + "column": 13, + "line": 13, + }, + "start": Object { + "column": 3, + "line": 13, + }, + }, + "range": Array [ + 205, + 215, + ], + "raw": "\\"literal2\\"", + "type": "Literal", + "value": "literal2", + }, + "kind": "method", + "loc": Object { + "end": Object { + "column": 20, + "line": 13, + }, + "start": Object { + "column": 2, + "line": 13, + }, + }, + "optional": true, + "range": Array [ + 204, + 222, + ], + "static": false, + "type": "MethodDefinition", + "value": Object { + "async": false, + "body": Object { + "body": Array [], + "loc": Object { + "end": Object { + "column": 20, + "line": 13, + }, + "start": Object { + "column": 18, + "line": 13, + }, + }, + "range": Array [ + 220, + 222, + ], + "type": "BlockStatement", + }, + "expression": false, + "generator": false, + "id": null, + "loc": Object { + "end": Object { + "column": 20, + "line": 13, + }, + "start": Object { + "column": 15, + "line": 13, + }, + }, + "params": Array [], + "range": Array [ + 217, + 222, + ], + "type": "FunctionExpression", + }, + }, + Object { + "computed": true, + "key": Object { + "computed": false, + "loc": Object { + "end": Object { + "column": 13, + "line": 14, + }, + "start": Object { + "column": 3, + "line": 14, + }, + }, + "object": Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 14, + }, + "start": Object { + "column": 3, + "line": 14, + }, + }, + "name": "obj", + "range": Array [ + 227, + 230, + ], + "type": "Identifier", + }, + "optional": false, + "property": Object { + "loc": Object { + "end": Object { + "column": 13, + "line": 14, + }, + "start": Object { + "column": 7, + "line": 14, + }, + }, + "name": "member", + "range": Array [ + 231, + 237, + ], + "type": "Identifier", + }, + "range": Array [ + 227, + 237, + ], + "type": "MemberExpression", + }, + "kind": "method", + "loc": Object { + "end": Object { + "column": 20, + "line": 14, + }, + "start": Object { + "column": 2, + "line": 14, + }, + }, + "optional": true, + "range": Array [ + 226, + 244, + ], + "static": false, + "type": "MethodDefinition", + "value": Object { + "async": false, + "body": Object { + "body": Array [], + "loc": Object { + "end": Object { + "column": 20, + "line": 14, + }, + "start": Object { + "column": 18, + "line": 14, + }, + }, + "range": Array [ + 242, + 244, + ], + "type": "BlockStatement", + }, + "expression": false, + "generator": false, + "id": null, + "loc": Object { + "end": Object { + "column": 20, + "line": 14, + }, + "start": Object { + "column": 15, + "line": 14, + }, + }, + "params": Array [], + "range": Array [ + 239, + 244, + ], + "type": "FunctionExpression", + }, + }, + Object { + "computed": true, + "key": Object { + "computed": false, + "loc": Object { + "end": Object { + "column": 14, + "line": 15, + }, + "start": Object { + "column": 3, + "line": 15, + }, + }, + "object": Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 15, + }, + "start": Object { + "column": 3, + "line": 15, + }, + }, + "name": "obj", + "range": Array [ + 249, + 252, + ], + "type": "Identifier", + }, + "optional": false, + "property": Object { + "loc": Object { + "end": Object { + "column": 14, + "line": 15, + }, + "start": Object { + "column": 7, + "line": 15, + }, + }, + "name": "member2", + "range": Array [ + 253, + 260, + ], + "type": "Identifier", + }, + "range": Array [ + 249, + 260, + ], + "type": "MemberExpression", + }, + "kind": "method", + "loc": Object { + "end": Object { + "column": 19, + "line": 15, + }, + "start": Object { + "column": 2, + "line": 15, + }, + }, + "optional": true, + "range": Array [ + 248, + 265, + ], + "static": false, + "type": "MethodDefinition", + "value": Object { + "async": false, + "body": null, + "expression": false, + "generator": false, + "id": null, + "loc": Object { + "end": Object { + "column": 19, + "line": 15, + }, + "start": Object { + "column": 16, + "line": 15, + }, + }, + "params": Array [], + "range": Array [ + 262, + 265, + ], + "type": "TSEmptyBodyFunctionExpression", + }, + }, + Object { + "computed": true, + "key": Object { + "arguments": Array [], + "callee": Object { + "loc": Object { + "end": Object { + "column": 4, + "line": 16, + }, + "start": Object { + "column": 3, + "line": 16, + }, + }, + "name": "f", + "range": Array [ + 269, + 270, + ], + "type": "Identifier", + }, + "loc": Object { + "end": Object { + "column": 6, + "line": 16, + }, + "start": Object { + "column": 3, + "line": 16, + }, + }, + "optional": false, + "range": Array [ + 269, + 272, + ], + "type": "CallExpression", + }, + "kind": "method", + "loc": Object { + "end": Object { + "column": 13, + "line": 16, + }, + "start": Object { + "column": 2, + "line": 16, + }, + }, + "optional": true, + "range": Array [ + 268, + 279, + ], + "static": false, + "type": "MethodDefinition", + "value": Object { + "async": false, + "body": Object { + "body": Array [], + "loc": Object { + "end": Object { + "column": 13, + "line": 16, + }, + "start": Object { + "column": 11, + "line": 16, + }, + }, + "range": Array [ + 277, + 279, + ], + "type": "BlockStatement", + }, + "expression": false, + "generator": false, + "id": null, + "loc": Object { + "end": Object { + "column": 13, + "line": 16, + }, + "start": Object { + "column": 8, + "line": 16, + }, + }, + "params": Array [], + "range": Array [ + 274, + 279, + ], + "type": "FunctionExpression", + }, + }, + ], + "loc": Object { + "end": Object { + "column": 1, + "line": 17, + }, + "start": Object { + "column": 8, + "line": 7, + }, + }, + "range": Array [ + 119, + 281, + ], + "type": "ClassBody", + }, + "id": Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 7, + }, + "start": Object { + "column": 6, + "line": 7, + }, + }, + "name": "X", + "range": Array [ + 117, + 118, + ], + "type": "Identifier", + }, + "loc": Object { + "end": Object { + "column": 1, + "line": 17, + }, + "start": Object { + "column": 0, + "line": 7, + }, + }, + "range": Array [ + 111, + 281, + ], + "superClass": null, + "type": "ClassDeclaration", + }, + ], + "loc": Object { + "end": Object { + "column": 0, + "line": 18, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "range": Array [ + 0, + 282, + ], + "sourceType": "script", + "tokens": Array [ + Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 1, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "range": Array [ + 0, + 5, + ], + "type": "Keyword", + "value": "const", + }, + Object { + "loc": Object { + "end": Object { + "column": 15, + "line": 1, + }, + "start": Object { + "column": 6, + "line": 1, + }, + }, + "range": Array [ + 6, + 15, + ], + "type": "Identifier", + "value": "computed1", + }, + Object { + "loc": Object { + "end": Object { + "column": 17, + "line": 1, + }, + "start": Object { + "column": 16, + "line": 1, + }, + }, + "range": Array [ + 16, + 17, + ], + "type": "Punctuator", + "value": "=", + }, + Object { + "loc": Object { + "end": Object { + "column": 24, + "line": 1, + }, + "start": Object { + "column": 18, + "line": 1, + }, + }, + "range": Array [ + 18, + 24, + ], + "type": "String", + "value": "\\"buzz\\"", + }, + Object { + "loc": Object { + "end": Object { + "column": 25, + "line": 1, + }, + "start": Object { + "column": 24, + "line": 1, + }, + }, + "range": Array [ + 24, + 25, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 2, + }, + "start": Object { + "column": 0, + "line": 2, + }, + }, + "range": Array [ + 26, + 31, + ], + "type": "Keyword", + "value": "const", + }, + Object { + "loc": Object { + "end": Object { + "column": 15, + "line": 2, + }, + "start": Object { + "column": 6, + "line": 2, + }, + }, + "range": Array [ + 32, + 41, + ], + "type": "Identifier", + "value": "computed2", + }, + Object { + "loc": Object { + "end": Object { + "column": 17, + "line": 2, + }, + "start": Object { + "column": 16, + "line": 2, + }, + }, + "range": Array [ + 42, + 43, + ], + "type": "Punctuator", + "value": "=", + }, + Object { + "loc": Object { + "end": Object { + "column": 24, + "line": 2, + }, + "start": Object { + "column": 18, + "line": 2, + }, + }, + "range": Array [ + 44, + 50, + ], + "type": "String", + "value": "\\"bazz\\"", + }, + Object { + "loc": Object { + "end": Object { + "column": 25, + "line": 2, + }, + "start": Object { + "column": 24, + "line": 2, + }, + }, + "range": Array [ + 50, + 51, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 3, + }, + "start": Object { + "column": 0, + "line": 3, + }, + }, + "range": Array [ + 52, + 57, + ], + "type": "Keyword", + "value": "const", + }, + Object { + "loc": Object { + "end": Object { + "column": 9, + "line": 3, + }, + "start": Object { + "column": 6, + "line": 3, + }, + }, + "range": Array [ + 58, + 61, + ], + "type": "Identifier", + "value": "obj", + }, + Object { + "loc": Object { + "end": Object { + "column": 11, + "line": 3, + }, + "start": Object { + "column": 10, + "line": 3, + }, + }, + "range": Array [ + 62, + 63, + ], + "type": "Punctuator", + "value": "=", + }, + Object { + "loc": Object { + "end": Object { + "column": 13, + "line": 3, + }, + "start": Object { + "column": 12, + "line": 3, + }, + }, + "range": Array [ + 64, + 65, + ], + "type": "Punctuator", + "value": "{", + }, + Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 4, + }, + "start": Object { + "column": 2, + "line": 4, + }, + }, + "range": Array [ + 68, + 74, + ], + "type": "Identifier", + "value": "member", + }, + Object { + "loc": Object { + "end": Object { + "column": 9, + "line": 4, + }, + "start": Object { + "column": 8, + "line": 4, + }, + }, + "range": Array [ + 74, + 75, + ], + "type": "Punctuator", + "value": ":", + }, + Object { + "loc": Object { + "end": Object { + "column": 18, + "line": 4, + }, + "start": Object { + "column": 10, + "line": 4, + }, + }, + "range": Array [ + 76, + 84, + ], + "type": "String", + "value": "\\"member\\"", + }, + Object { + "loc": Object { + "end": Object { + "column": 19, + "line": 4, + }, + "start": Object { + "column": 18, + "line": 4, + }, + }, + "range": Array [ + 84, + 85, + ], + "type": "Punctuator", + "value": ",", + }, + Object { + "loc": Object { + "end": Object { + "column": 9, + "line": 5, + }, + "start": Object { + "column": 2, + "line": 5, + }, + }, + "range": Array [ + 88, + 95, + ], + "type": "Identifier", + "value": "member2", + }, + Object { + "loc": Object { + "end": Object { + "column": 10, + "line": 5, + }, + "start": Object { + "column": 9, + "line": 5, + }, + }, + "range": Array [ + 95, + 96, + ], + "type": "Punctuator", + "value": ":", + }, + Object { + "loc": Object { + "end": Object { + "column": 20, + "line": 5, + }, + "start": Object { + "column": 11, + "line": 5, + }, + }, + "range": Array [ + 97, + 106, + ], + "type": "String", + "value": "\\"member2\\"", + }, + Object { + "loc": Object { + "end": Object { + "column": 21, + "line": 5, + }, + "start": Object { + "column": 20, + "line": 5, + }, + }, + "range": Array [ + 106, + 107, + ], + "type": "Punctuator", + "value": ",", + }, + Object { + "loc": Object { + "end": Object { + "column": 1, + "line": 6, + }, + "start": Object { + "column": 0, + "line": 6, + }, + }, + "range": Array [ + 108, + 109, + ], + "type": "Punctuator", + "value": "}", + }, + Object { + "loc": Object { + "end": Object { + "column": 2, + "line": 6, + }, + "start": Object { + "column": 1, + "line": 6, + }, + }, + "range": Array [ + 109, + 110, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 7, + }, + "start": Object { + "column": 0, + "line": 7, + }, + }, + "range": Array [ + 111, + 116, + ], + "type": "Keyword", + "value": "class", + }, + Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 7, + }, + "start": Object { + "column": 6, + "line": 7, + }, + }, + "range": Array [ + 117, + 118, + ], + "type": "Identifier", + "value": "X", + }, + Object { + "loc": Object { + "end": Object { + "column": 9, + "line": 7, + }, + "start": Object { + "column": 8, + "line": 7, + }, + }, + "range": Array [ + 119, + 120, + ], + "type": "Punctuator", + "value": "{", + }, + Object { + "loc": Object { + "end": Object { + "column": 3, + "line": 8, + }, + "start": Object { + "column": 2, + "line": 8, + }, + }, + "range": Array [ + 123, + 124, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 12, + "line": 8, + }, + "start": Object { + "column": 3, + "line": 8, + }, + }, + "range": Array [ + 124, + 133, + ], + "type": "Identifier", + "value": "computed1", + }, + Object { + "loc": Object { + "end": Object { + "column": 13, + "line": 8, + }, + "start": Object { + "column": 12, + "line": 8, + }, + }, + "range": Array [ + 133, + 134, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 14, + "line": 8, + }, + "start": Object { + "column": 13, + "line": 8, + }, + }, + "range": Array [ + 134, + 135, + ], + "type": "Punctuator", + "value": "?", + }, + Object { + "loc": Object { + "end": Object { + "column": 15, + "line": 8, + }, + "start": Object { + "column": 14, + "line": 8, + }, + }, + "range": Array [ + 135, + 136, + ], + "type": "Punctuator", + "value": "(", + }, + Object { + "loc": Object { + "end": Object { + "column": 16, + "line": 8, + }, + "start": Object { + "column": 15, + "line": 8, + }, + }, + "range": Array [ + 136, + 137, + ], + "type": "Punctuator", + "value": ")", + }, + Object { + "loc": Object { + "end": Object { + "column": 17, + "line": 8, + }, + "start": Object { + "column": 16, + "line": 8, + }, + }, + "range": Array [ + 137, + 138, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 3, + "line": 9, + }, + "start": Object { + "column": 2, + "line": 9, + }, + }, + "range": Array [ + 141, + 142, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 12, + "line": 9, + }, + "start": Object { + "column": 3, + "line": 9, + }, + }, + "range": Array [ + 142, + 151, + ], + "type": "Identifier", + "value": "computed2", + }, + Object { + "loc": Object { + "end": Object { + "column": 13, + "line": 9, + }, + "start": Object { + "column": 12, + "line": 9, + }, + }, + "range": Array [ + 151, + 152, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 14, + "line": 9, + }, + "start": Object { + "column": 13, + "line": 9, + }, + }, + "range": Array [ + 152, + 153, + ], + "type": "Punctuator", + "value": "?", + }, + Object { + "loc": Object { + "end": Object { + "column": 15, + "line": 9, + }, + "start": Object { + "column": 14, + "line": 9, + }, + }, + "range": Array [ + 153, + 154, + ], + "type": "Punctuator", + "value": "(", + }, + Object { + "loc": Object { + "end": Object { + "column": 16, + "line": 9, + }, + "start": Object { + "column": 15, + "line": 9, + }, + }, + "range": Array [ + 154, + 155, + ], + "type": "Punctuator", + "value": ")", + }, + Object { + "loc": Object { + "end": Object { + "column": 18, + "line": 9, + }, + "start": Object { + "column": 17, + "line": 9, + }, + }, + "range": Array [ + 156, + 157, + ], + "type": "Punctuator", + "value": "{", + }, + Object { + "loc": Object { + "end": Object { + "column": 19, + "line": 9, + }, + "start": Object { + "column": 18, + "line": 9, + }, + }, + "range": Array [ + 157, + 158, + ], + "type": "Punctuator", + "value": "}", + }, + Object { + "loc": Object { + "end": Object { + "column": 20, + "line": 9, + }, + "start": Object { + "column": 19, + "line": 9, + }, + }, + "range": Array [ + 158, + 159, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 3, + "line": 10, + }, + "start": Object { + "column": 2, + "line": 10, + }, + }, + "range": Array [ + 162, + 163, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 4, + "line": 10, + }, + "start": Object { + "column": 3, + "line": 10, + }, + }, + "range": Array [ + 163, + 164, + ], + "type": "Numeric", + "value": "1", + }, + Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 10, + }, + "start": Object { + "column": 4, + "line": 10, + }, + }, + "range": Array [ + 164, + 165, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 10, + }, + "start": Object { + "column": 5, + "line": 10, + }, + }, + "range": Array [ + 165, + 166, + ], + "type": "Punctuator", + "value": "?", + }, + Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 10, + }, + "start": Object { + "column": 6, + "line": 10, + }, + }, + "range": Array [ + 166, + 167, + ], + "type": "Punctuator", + "value": "(", + }, + Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 10, + }, + "start": Object { + "column": 7, + "line": 10, + }, + }, + "range": Array [ + 167, + 168, + ], + "type": "Punctuator", + "value": ")", + }, + Object { + "loc": Object { + "end": Object { + "column": 9, + "line": 10, + }, + "start": Object { + "column": 8, + "line": 10, + }, + }, + "range": Array [ + 168, + 169, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 3, + "line": 11, + }, + "start": Object { + "column": 2, + "line": 11, + }, + }, + "range": Array [ + 172, + 173, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 4, + "line": 11, + }, + "start": Object { + "column": 3, + "line": 11, + }, + }, + "range": Array [ + 173, + 174, + ], + "type": "Numeric", + "value": "2", + }, + Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 11, + }, + "start": Object { + "column": 4, + "line": 11, + }, + }, + "range": Array [ + 174, + 175, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 11, + }, + "start": Object { + "column": 5, + "line": 11, + }, + }, + "range": Array [ + 175, + 176, + ], + "type": "Punctuator", + "value": "?", + }, + Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 11, + }, + "start": Object { + "column": 6, + "line": 11, + }, + }, + "range": Array [ + 176, + 177, + ], + "type": "Punctuator", + "value": "(", + }, + Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 11, + }, + "start": Object { + "column": 7, + "line": 11, + }, + }, + "range": Array [ + 177, + 178, + ], + "type": "Punctuator", + "value": ")", + }, + Object { + "loc": Object { + "end": Object { + "column": 10, + "line": 11, + }, + "start": Object { + "column": 9, + "line": 11, + }, + }, + "range": Array [ + 179, + 180, + ], + "type": "Punctuator", + "value": "{", + }, + Object { + "loc": Object { + "end": Object { + "column": 11, + "line": 11, + }, + "start": Object { + "column": 10, + "line": 11, + }, + }, + "range": Array [ + 180, + 181, + ], + "type": "Punctuator", + "value": "}", + }, + Object { + "loc": Object { + "end": Object { + "column": 12, + "line": 11, + }, + "start": Object { + "column": 11, + "line": 11, + }, + }, + "range": Array [ + 181, + 182, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 3, + "line": 12, + }, + "start": Object { + "column": 2, + "line": 12, + }, + }, + "range": Array [ + 185, + 186, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 13, + "line": 12, + }, + "start": Object { + "column": 3, + "line": 12, + }, + }, + "range": Array [ + 186, + 196, + ], + "type": "String", + "value": "\\"literal1\\"", + }, + Object { + "loc": Object { + "end": Object { + "column": 14, + "line": 12, + }, + "start": Object { + "column": 13, + "line": 12, + }, + }, + "range": Array [ + 196, + 197, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 15, + "line": 12, + }, + "start": Object { + "column": 14, + "line": 12, + }, + }, + "range": Array [ + 197, + 198, + ], + "type": "Punctuator", + "value": "?", + }, + Object { + "loc": Object { + "end": Object { + "column": 16, + "line": 12, + }, + "start": Object { + "column": 15, + "line": 12, + }, + }, + "range": Array [ + 198, + 199, + ], + "type": "Punctuator", + "value": "(", + }, + Object { + "loc": Object { + "end": Object { + "column": 17, + "line": 12, + }, + "start": Object { + "column": 16, + "line": 12, + }, + }, + "range": Array [ + 199, + 200, + ], + "type": "Punctuator", + "value": ")", + }, + Object { + "loc": Object { + "end": Object { + "column": 18, + "line": 12, + }, + "start": Object { + "column": 17, + "line": 12, + }, + }, + "range": Array [ + 200, + 201, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 3, + "line": 13, + }, + "start": Object { + "column": 2, + "line": 13, + }, + }, + "range": Array [ + 204, + 205, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 13, + "line": 13, + }, + "start": Object { + "column": 3, + "line": 13, + }, + }, + "range": Array [ + 205, + 215, + ], + "type": "String", + "value": "\\"literal2\\"", + }, + Object { + "loc": Object { + "end": Object { + "column": 14, + "line": 13, + }, + "start": Object { + "column": 13, + "line": 13, + }, + }, + "range": Array [ + 215, + 216, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 15, + "line": 13, + }, + "start": Object { + "column": 14, + "line": 13, + }, + }, + "range": Array [ + 216, + 217, + ], + "type": "Punctuator", + "value": "?", + }, + Object { + "loc": Object { + "end": Object { + "column": 16, + "line": 13, + }, + "start": Object { + "column": 15, + "line": 13, + }, + }, + "range": Array [ + 217, + 218, + ], + "type": "Punctuator", + "value": "(", + }, + Object { + "loc": Object { + "end": Object { + "column": 17, + "line": 13, + }, + "start": Object { + "column": 16, + "line": 13, + }, + }, + "range": Array [ + 218, + 219, + ], + "type": "Punctuator", + "value": ")", + }, + Object { + "loc": Object { + "end": Object { + "column": 19, + "line": 13, + }, + "start": Object { + "column": 18, + "line": 13, + }, + }, + "range": Array [ + 220, + 221, + ], + "type": "Punctuator", + "value": "{", + }, + Object { + "loc": Object { + "end": Object { + "column": 20, + "line": 13, + }, + "start": Object { + "column": 19, + "line": 13, + }, + }, + "range": Array [ + 221, + 222, + ], + "type": "Punctuator", + "value": "}", + }, + Object { + "loc": Object { + "end": Object { + "column": 21, + "line": 13, + }, + "start": Object { + "column": 20, + "line": 13, + }, + }, + "range": Array [ + 222, + 223, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 3, + "line": 14, + }, + "start": Object { + "column": 2, + "line": 14, + }, + }, + "range": Array [ + 226, + 227, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 14, + }, + "start": Object { + "column": 3, + "line": 14, + }, + }, + "range": Array [ + 227, + 230, + ], + "type": "Identifier", + "value": "obj", + }, + Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 14, + }, + "start": Object { + "column": 6, + "line": 14, + }, + }, + "range": Array [ + 230, + 231, + ], + "type": "Punctuator", + "value": ".", + }, + Object { + "loc": Object { + "end": Object { + "column": 13, + "line": 14, + }, + "start": Object { + "column": 7, + "line": 14, + }, + }, + "range": Array [ + 231, + 237, + ], + "type": "Identifier", + "value": "member", + }, + Object { + "loc": Object { + "end": Object { + "column": 14, + "line": 14, + }, + "start": Object { + "column": 13, + "line": 14, + }, + }, + "range": Array [ + 237, + 238, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 15, + "line": 14, + }, + "start": Object { + "column": 14, + "line": 14, + }, + }, + "range": Array [ + 238, + 239, + ], + "type": "Punctuator", + "value": "?", + }, + Object { + "loc": Object { + "end": Object { + "column": 16, + "line": 14, + }, + "start": Object { + "column": 15, + "line": 14, + }, + }, + "range": Array [ + 239, + 240, + ], + "type": "Punctuator", + "value": "(", + }, + Object { + "loc": Object { + "end": Object { + "column": 17, + "line": 14, + }, + "start": Object { + "column": 16, + "line": 14, + }, + }, + "range": Array [ + 240, + 241, + ], + "type": "Punctuator", + "value": ")", + }, + Object { + "loc": Object { + "end": Object { + "column": 19, + "line": 14, + }, + "start": Object { + "column": 18, + "line": 14, + }, + }, + "range": Array [ + 242, + 243, + ], + "type": "Punctuator", + "value": "{", + }, + Object { + "loc": Object { + "end": Object { + "column": 20, + "line": 14, + }, + "start": Object { + "column": 19, + "line": 14, + }, + }, + "range": Array [ + 243, + 244, + ], + "type": "Punctuator", + "value": "}", + }, + Object { + "loc": Object { + "end": Object { + "column": 21, + "line": 14, + }, + "start": Object { + "column": 20, + "line": 14, + }, + }, + "range": Array [ + 244, + 245, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 3, + "line": 15, + }, + "start": Object { + "column": 2, + "line": 15, + }, + }, + "range": Array [ + 248, + 249, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 15, + }, + "start": Object { + "column": 3, + "line": 15, + }, + }, + "range": Array [ + 249, + 252, + ], + "type": "Identifier", + "value": "obj", + }, + Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 15, + }, + "start": Object { + "column": 6, + "line": 15, + }, + }, + "range": Array [ + 252, + 253, + ], + "type": "Punctuator", + "value": ".", + }, + Object { + "loc": Object { + "end": Object { + "column": 14, + "line": 15, + }, + "start": Object { + "column": 7, + "line": 15, + }, + }, + "range": Array [ + 253, + 260, + ], + "type": "Identifier", + "value": "member2", + }, + Object { + "loc": Object { + "end": Object { + "column": 15, + "line": 15, + }, + "start": Object { + "column": 14, + "line": 15, + }, + }, + "range": Array [ + 260, + 261, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 16, + "line": 15, + }, + "start": Object { + "column": 15, + "line": 15, + }, + }, + "range": Array [ + 261, + 262, + ], + "type": "Punctuator", + "value": "?", + }, + Object { + "loc": Object { + "end": Object { + "column": 17, + "line": 15, + }, + "start": Object { + "column": 16, + "line": 15, + }, + }, + "range": Array [ + 262, + 263, + ], + "type": "Punctuator", + "value": "(", + }, + Object { + "loc": Object { + "end": Object { + "column": 18, + "line": 15, + }, + "start": Object { + "column": 17, + "line": 15, + }, + }, + "range": Array [ + 263, + 264, + ], + "type": "Punctuator", + "value": ")", + }, + Object { + "loc": Object { + "end": Object { + "column": 19, + "line": 15, + }, + "start": Object { + "column": 18, + "line": 15, + }, + }, + "range": Array [ + 264, + 265, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 3, + "line": 16, + }, + "start": Object { + "column": 2, + "line": 16, + }, + }, + "range": Array [ + 268, + 269, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 4, + "line": 16, + }, + "start": Object { + "column": 3, + "line": 16, + }, + }, + "range": Array [ + 269, + 270, + ], + "type": "Identifier", + "value": "f", + }, + Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 16, + }, + "start": Object { + "column": 4, + "line": 16, + }, + }, + "range": Array [ + 270, + 271, + ], + "type": "Punctuator", + "value": "(", + }, + Object { + "loc": Object { + "end": Object { + "column": 6, + "line": 16, + }, + "start": Object { + "column": 5, + "line": 16, + }, + }, + "range": Array [ + 271, + 272, + ], + "type": "Punctuator", + "value": ")", + }, + Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 16, + }, + "start": Object { + "column": 6, + "line": 16, + }, + }, + "range": Array [ + 272, + 273, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 8, + "line": 16, + }, + "start": Object { + "column": 7, + "line": 16, + }, + }, + "range": Array [ + 273, + 274, + ], + "type": "Punctuator", + "value": "?", + }, + Object { + "loc": Object { + "end": Object { + "column": 9, + "line": 16, + }, + "start": Object { + "column": 8, + "line": 16, + }, + }, + "range": Array [ + 274, + 275, + ], + "type": "Punctuator", + "value": "(", + }, + Object { + "loc": Object { + "end": Object { + "column": 10, + "line": 16, + }, + "start": Object { + "column": 9, + "line": 16, + }, + }, + "range": Array [ + 275, + 276, + ], + "type": "Punctuator", + "value": ")", + }, + Object { + "loc": Object { + "end": Object { + "column": 12, + "line": 16, + }, + "start": Object { + "column": 11, + "line": 16, + }, + }, + "range": Array [ + 277, + 278, + ], + "type": "Punctuator", + "value": "{", + }, + Object { + "loc": Object { + "end": Object { + "column": 13, + "line": 16, + }, + "start": Object { + "column": 12, + "line": 16, + }, + }, + "range": Array [ + 278, + 279, + ], + "type": "Punctuator", + "value": "}", + }, + Object { + "loc": Object { + "end": Object { + "column": 1, + "line": 17, + }, + "start": Object { + "column": 0, + "line": 17, + }, + }, + "range": Array [ + 280, + 281, + ], + "type": "Punctuator", + "value": "}", + }, + ], + "type": "Program", +} +`; + +exports[`typescript fixtures/basics/class-with-optional-computed-property.src 1`] = ` +Object { + "body": Array [ + Object { + "body": Object { + "body": Array [ + Object { + "accessibility": "private", + "computed": true, + "declare": false, + "key": Object { + "loc": Object { + "end": Object { + "column": 18, + "line": 2, + }, + "start": Object { + "column": 13, + "line": 2, + }, + }, + "range": Array [ + 23, + 28, + ], + "raw": "'foo'", + "type": "Literal", + "value": "foo", + }, + "loc": Object { + "end": Object { + "column": 33, + "line": 2, + }, + "start": Object { + "column": 4, + "line": 2, + }, + }, + "optional": true, + "range": Array [ + 14, + 43, + ], + "static": false, + "type": "ClassProperty", + "value": Object { + "loc": Object { + "end": Object { + "column": 32, + "line": 2, + }, + "start": Object { + "column": 23, + "line": 2, + }, + }, + "name": "undefined", + "range": Array [ + 33, + 42, + ], + "type": "Identifier", + }, + }, + ], + "loc": Object { + "end": Object { + "column": 1, + "line": 3, + }, + "start": Object { + "column": 8, + "line": 1, + }, + }, + "range": Array [ + 8, + 45, + ], + "type": "ClassBody", + }, + "id": Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 1, + }, + "start": Object { + "column": 6, + "line": 1, + }, + }, + "name": "X", + "range": Array [ + 6, + 7, + ], + "type": "Identifier", + }, + "loc": Object { + "end": Object { + "column": 1, + "line": 3, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "range": Array [ + 0, + 45, + ], + "superClass": null, + "type": "ClassDeclaration", + }, + ], + "loc": Object { + "end": Object { + "column": 0, + "line": 4, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "range": Array [ + 0, + 46, + ], + "sourceType": "script", + "tokens": Array [ + Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 1, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "range": Array [ + 0, + 5, + ], + "type": "Keyword", + "value": "class", + }, + Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 1, + }, + "start": Object { + "column": 6, + "line": 1, + }, + }, + "range": Array [ + 6, + 7, + ], + "type": "Identifier", + "value": "X", + }, + Object { + "loc": Object { + "end": Object { + "column": 9, + "line": 1, + }, + "start": Object { + "column": 8, + "line": 1, + }, + }, + "range": Array [ + 8, + 9, + ], + "type": "Punctuator", + "value": "{", + }, + Object { + "loc": Object { + "end": Object { + "column": 11, + "line": 2, + }, + "start": Object { + "column": 4, + "line": 2, + }, + }, + "range": Array [ + 14, + 21, + ], + "type": "Keyword", + "value": "private", + }, + Object { + "loc": Object { + "end": Object { + "column": 13, + "line": 2, + }, + "start": Object { + "column": 12, + "line": 2, + }, + }, + "range": Array [ + 22, + 23, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 18, + "line": 2, + }, + "start": Object { + "column": 13, + "line": 2, + }, + }, + "range": Array [ + 23, + 28, + ], + "type": "String", + "value": "'foo'", + }, + Object { + "loc": Object { + "end": Object { + "column": 19, + "line": 2, + }, + "start": Object { + "column": 18, + "line": 2, + }, + }, + "range": Array [ + 28, + 29, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 20, + "line": 2, + }, + "start": Object { + "column": 19, + "line": 2, + }, + }, + "range": Array [ + 29, + 30, + ], + "type": "Punctuator", + "value": "?", + }, + Object { + "loc": Object { + "end": Object { + "column": 22, + "line": 2, + }, + "start": Object { + "column": 21, + "line": 2, + }, + }, + "range": Array [ + 31, + 32, + ], + "type": "Punctuator", + "value": "=", + }, + Object { + "loc": Object { + "end": Object { + "column": 32, + "line": 2, + }, + "start": Object { + "column": 23, + "line": 2, + }, + }, + "range": Array [ + 33, + 42, + ], + "type": "Identifier", + "value": "undefined", + }, + Object { + "loc": Object { + "end": Object { + "column": 33, + "line": 2, + }, + "start": Object { + "column": 32, + "line": 2, + }, + }, + "range": Array [ + 42, + 43, + ], + "type": "Punctuator", + "value": ";", + }, + Object { + "loc": Object { + "end": Object { + "column": 1, + "line": 3, + }, + "start": Object { + "column": 0, + "line": 3, + }, + }, + "range": Array [ + 44, + 45, + ], + "type": "Punctuator", + "value": "}", + }, + ], + "type": "Program", +} +`; + +exports[`typescript fixtures/basics/class-with-optional-methods.src 1`] = ` +Object { + "body": Array [ + Object { + "body": Object { + "body": Array [ + Object { + "computed": false, + "key": Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 2, + }, + "start": Object { + "column": 2, + "line": 2, + }, + }, + "name": "foo", + "range": Array [ + 14, + 17, + ], + "type": "Identifier", + }, + "kind": "method", + "loc": Object { + "end": Object { + "column": 9, + "line": 2, + }, + "start": Object { + "column": 2, + "line": 2, + }, + }, + "optional": true, + "range": Array [ + 14, + 21, + ], + "static": false, + "type": "MethodDefinition", + "value": Object { + "async": false, + "body": null, + "expression": false, + "generator": false, + "id": null, + "loc": Object { + "end": Object { + "column": 9, + "line": 2, + }, + "start": Object { + "column": 6, + "line": 2, + }, + }, + "params": Array [], + "range": Array [ + 18, + 21, + ], + "type": "TSEmptyBodyFunctionExpression", + }, + }, + Object { + "computed": false, + "key": Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 3, + }, + "start": Object { + "column": 2, + "line": 3, + }, + }, + "name": "bar", + "range": Array [ + 24, + 27, + ], + "type": "Identifier", + }, + "kind": "method", + "loc": Object { + "end": Object { + "column": 17, + "line": 3, + }, + "start": Object { + "column": 2, + "line": 3, + }, + }, + "optional": true, "range": Array [ 24, 39, @@ -24322,7 +27388,6 @@ Object { }, }, "name": "baz", - "optional": true, "range": Array [ 50, 53, @@ -24340,6 +27405,7 @@ Object { "line": 4, }, }, + "optional": true, "range": Array [ 42, 65, @@ -38182,7 +41248,6 @@ Object { }, }, "name": "bar", - "optional": true, "range": Array [ 24, 27, @@ -38200,6 +41265,7 @@ Object { "line": 2, }, }, + "optional": true, "range": Array [ 24, 36, From aff5b62044f9b93f2087a1d261e9be3f8d6fd54d Mon Sep 17 00:00:00 2001 From: Armano Date: Sun, 10 May 2020 19:18:12 +0200 Subject: [PATCH 13/33] feat(typescript-estree): align nodes with estree 2020 (#1389) --- .../src/rules/class-literal-property-style.ts | 5 +- .../src/rules/no-inferrable-types.ts | 3 +- .../src/rules/prefer-optional-chain.ts | 2 - .../lib/__snapshots__/javascript.ts.snap | 2 + .../error-dynamic-import-params.src.js | 1 + packages/typescript-estree/src/convert.ts | 31 +++++-- .../src/ts-estree/ast-node-types.ts | 2 +- .../src/ts-estree/estree-to-ts-node-types.ts | 5 +- .../src/ts-estree/ts-estree.ts | 15 +++- .../typescript-estree/src/visitor-keys.ts | 3 +- .../tests/ast-alignment/fixtures-to-test.ts | 29 +------ .../lib/__snapshots__/javascript.ts.snap | 82 ++++++++----------- .../semantic-diagnostics-enabled.ts.snap | 9 ++ 13 files changed, 95 insertions(+), 94 deletions(-) create mode 100644 packages/shared-fixtures/fixtures/javascript/experimentalDynamicImport/error-dynamic-import-params.src.js diff --git a/packages/eslint-plugin/src/rules/class-literal-property-style.ts b/packages/eslint-plugin/src/rules/class-literal-property-style.ts index a4500cdfdbf8..0a257427ec10 100644 --- a/packages/eslint-plugin/src/rules/class-literal-property-style.ts +++ b/packages/eslint-plugin/src/rules/class-literal-property-style.ts @@ -23,10 +23,7 @@ const printNodeModifiers = ( const isSupportedLiteral = ( node: TSESTree.Node, ): node is TSESTree.LiteralExpression => { - if ( - node.type === AST_NODE_TYPES.Literal || - node.type === AST_NODE_TYPES.BigIntLiteral - ) { + if (node.type === AST_NODE_TYPES.Literal) { return true; } diff --git a/packages/eslint-plugin/src/rules/no-inferrable-types.ts b/packages/eslint-plugin/src/rules/no-inferrable-types.ts index 898a3294fd7a..2b84414dfcd7 100644 --- a/packages/eslint-plugin/src/rules/no-inferrable-types.ts +++ b/packages/eslint-plugin/src/rules/no-inferrable-types.ts @@ -118,7 +118,8 @@ export default util.createRule({ return ( isFunctionCall(unwrappedInit, 'BigInt') || - unwrappedInit.type === AST_NODE_TYPES.BigIntLiteral + (unwrappedInit.type === AST_NODE_TYPES.Literal && + 'bigint' in unwrappedInit) ); } diff --git a/packages/eslint-plugin/src/rules/prefer-optional-chain.ts b/packages/eslint-plugin/src/rules/prefer-optional-chain.ts index 6adc3f1d9c89..0d5176b6f107 100644 --- a/packages/eslint-plugin/src/rules/prefer-optional-chain.ts +++ b/packages/eslint-plugin/src/rules/prefer-optional-chain.ts @@ -306,7 +306,6 @@ export default util.createRule({ break; case AST_NODE_TYPES.Literal: - case AST_NODE_TYPES.BigIntLiteral: case AST_NODE_TYPES.TemplateLiteral: propertyText = sourceCode.getText(node.property); break; @@ -353,7 +352,6 @@ const ALLOWED_MEMBER_OBJECT_TYPES: ReadonlySet = new Set([ AST_NODE_TYPES.ThisExpression, ]); const ALLOWED_COMPUTED_PROP_TYPES: ReadonlySet = new Set([ - AST_NODE_TYPES.BigIntLiteral, AST_NODE_TYPES.Identifier, AST_NODE_TYPES.Literal, AST_NODE_TYPES.MemberExpression, diff --git a/packages/parser/tests/lib/__snapshots__/javascript.ts.snap b/packages/parser/tests/lib/__snapshots__/javascript.ts.snap index 495f3b26b053..654b09e21ab6 100644 --- a/packages/parser/tests/lib/__snapshots__/javascript.ts.snap +++ b/packages/parser/tests/lib/__snapshots__/javascript.ts.snap @@ -35993,6 +35993,8 @@ Object { } `; +exports[`javascript fixtures/experimentalDynamicImport/error-dynamic-import-params.src 1`] = `"Dynamic import must have one specifier as an argument."`; + exports[`javascript fixtures/experimentalObjectRestSpread/arg-spread.src 1`] = ` Object { "$id": 6, diff --git a/packages/shared-fixtures/fixtures/javascript/experimentalDynamicImport/error-dynamic-import-params.src.js b/packages/shared-fixtures/fixtures/javascript/experimentalDynamicImport/error-dynamic-import-params.src.js new file mode 100644 index 000000000000..c5d6277887f3 --- /dev/null +++ b/packages/shared-fixtures/fixtures/javascript/experimentalDynamicImport/error-dynamic-import-params.src.js @@ -0,0 +1 @@ +import('foo', '') diff --git a/packages/typescript-estree/src/convert.ts b/packages/typescript-estree/src/convert.ts index dc4a1a0091a9..c2ce21755af7 100644 --- a/packages/typescript-estree/src/convert.ts +++ b/packages/typescript-estree/src/convert.ts @@ -1808,6 +1808,20 @@ export class Converter { } case SyntaxKind.CallExpression: { + if (node.expression.kind === SyntaxKind.ImportKeyword) { + if (node.arguments.length !== 1) { + throw createError( + this.ast, + node.arguments.pos, + 'Dynamic import must have one specifier as an argument.', + ); + } + return this.createNode(node, { + type: AST_NODE_TYPES.ImportExpression, + source: this.convertChild(node.arguments[0]), + }); + } + const callee = this.convertChild(node.expression); const args = node.arguments.map(el => this.convertChild(el)); let result; @@ -1915,14 +1929,17 @@ export class Converter { } case SyntaxKind.BigIntLiteral: { - const result = this.createNode(node, { - type: AST_NODE_TYPES.BigIntLiteral, - raw: '', - value: '', + const range = getRange(node, this.ast); + const rawValue = this.ast.text.slice(range[0], range[1]); + const bigint = rawValue.slice(0, -1); // remove suffix `n` + const value = typeof BigInt !== 'undefined' ? BigInt(bigint) : null; + return this.createNode(node, { + type: AST_NODE_TYPES.Literal, + raw: rawValue, + value: value, + bigint: value === null ? bigint : String(value), + range, }); - result.raw = this.ast.text.slice(result.range[0], result.range[1]); - result.value = result.raw.slice(0, -1); // remove suffix `n` - return result; } case SyntaxKind.RegularExpressionLiteral: { diff --git a/packages/typescript-estree/src/ts-estree/ast-node-types.ts b/packages/typescript-estree/src/ts-estree/ast-node-types.ts index 13f2485819f0..d630398ec719 100644 --- a/packages/typescript-estree/src/ts-estree/ast-node-types.ts +++ b/packages/typescript-estree/src/ts-estree/ast-node-types.ts @@ -5,7 +5,6 @@ export enum AST_NODE_TYPES { AssignmentExpression = 'AssignmentExpression', AssignmentPattern = 'AssignmentPattern', AwaitExpression = 'AwaitExpression', - BigIntLiteral = 'BigIntLiteral', BinaryExpression = 'BinaryExpression', BlockStatement = 'BlockStatement', BreakStatement = 'BreakStatement', @@ -36,6 +35,7 @@ export enum AST_NODE_TYPES { Import = 'Import', ImportDeclaration = 'ImportDeclaration', ImportDefaultSpecifier = 'ImportDefaultSpecifier', + ImportExpression = 'ImportExpression', ImportNamespaceSpecifier = 'ImportNamespaceSpecifier', ImportSpecifier = 'ImportSpecifier', JSXAttribute = 'JSXAttribute', diff --git a/packages/typescript-estree/src/ts-estree/estree-to-ts-node-types.ts b/packages/typescript-estree/src/ts-estree/estree-to-ts-node-types.ts index bb00046c3349..5585c2902842 100644 --- a/packages/typescript-estree/src/ts-estree/estree-to-ts-node-types.ts +++ b/packages/typescript-estree/src/ts-estree/estree-to-ts-node-types.ts @@ -16,7 +16,6 @@ export interface EstreeToTsNodeTypes { | ts.BinaryExpression | ts.ParameterDeclaration; [AST_NODE_TYPES.AwaitExpression]: ts.AwaitExpression; - [AST_NODE_TYPES.BigIntLiteral]: ts.BigIntLiteral; [AST_NODE_TYPES.BinaryExpression]: ts.BinaryExpression; [AST_NODE_TYPES.BlockStatement]: ts.Block; [AST_NODE_TYPES.BreakStatement]: ts.BreakStatement; @@ -73,6 +72,7 @@ export interface EstreeToTsNodeTypes { [AST_NODE_TYPES.Import]: ts.ImportExpression; [AST_NODE_TYPES.ImportDeclaration]: ts.ImportDeclaration; [AST_NODE_TYPES.ImportDefaultSpecifier]: ts.ImportClause; + [AST_NODE_TYPES.ImportExpression]: ts.CallExpression; [AST_NODE_TYPES.ImportNamespaceSpecifier]: ts.NamespaceImport; [AST_NODE_TYPES.ImportSpecifier]: ts.ImportSpecifier; [AST_NODE_TYPES.JSXAttribute]: ts.JsxAttribute; @@ -98,7 +98,8 @@ export interface EstreeToTsNodeTypes { | ts.RegularExpressionLiteral | ts.JsxText | ts.NullLiteral - | ts.BooleanLiteral; + | ts.BooleanLiteral + | ts.BigIntLiteral; [AST_NODE_TYPES.LogicalExpression]: ts.BinaryExpression; [AST_NODE_TYPES.MemberExpression]: | ts.PropertyAccessExpression diff --git a/packages/typescript-estree/src/ts-estree/ts-estree.ts b/packages/typescript-estree/src/ts-estree/ts-estree.ts index bb7944b4baef..bd0b40636194 100644 --- a/packages/typescript-estree/src/ts-estree/ts-estree.ts +++ b/packages/typescript-estree/src/ts-estree/ts-estree.ts @@ -175,6 +175,7 @@ export type Node = | Import | ImportDeclaration | ImportDefaultSpecifier + | ImportExpression | ImportNamespaceSpecifier | ImportSpecifier | JSXAttribute @@ -395,12 +396,13 @@ export type LeftHandSideExpression = | TSAsExpression | ArrowFunctionExpression; export type Literal = + | BigIntLiteral | BooleanLiteral | NumberLiteral | NullLiteral | RegExpLiteral | StringLiteral; -export type LiteralExpression = BigIntLiteral | Literal | TemplateLiteral; +export type LiteralExpression = Literal | TemplateLiteral; export type MemberExpression = | MemberExpressionComputedName | MemberExpressionNonComputedName; @@ -624,7 +626,7 @@ interface FunctionSignatureBase extends BaseNode { interface LiteralBase extends BaseNode { raw: string; - value: boolean | number | RegExp | string | null; + value: string | boolean | null | number | RegExp | bigint; regex?: { pattern: string; flags: string; @@ -784,7 +786,9 @@ export interface AwaitExpression extends BaseNode { } export interface BigIntLiteral extends LiteralBase { - type: AST_NODE_TYPES.BigIntLiteral; + type: AST_NODE_TYPES.Literal; + value: bigint | null; + bigint: string; } export interface BinaryExpression extends BinaryExpressionBase { @@ -968,6 +972,11 @@ export interface ImportDefaultSpecifier extends BaseNode { local: Identifier; } +export interface ImportExpression extends BaseNode { + type: AST_NODE_TYPES.ImportExpression; + source: Expression; +} + export interface ImportNamespaceSpecifier extends BaseNode { type: AST_NODE_TYPES.ImportNamespaceSpecifier; local: Identifier; diff --git a/packages/typescript-estree/src/visitor-keys.ts b/packages/typescript-estree/src/visitor-keys.ts index a3622fc4713f..bba4a2f378b1 100644 --- a/packages/typescript-estree/src/visitor-keys.ts +++ b/packages/typescript-estree/src/visitor-keys.ts @@ -3,6 +3,8 @@ import * as eslintVisitorKeys from 'eslint-visitor-keys'; export const visitorKeys = eslintVisitorKeys.unionWith({ // Additional estree nodes. Import: [], + // ES2020 + ImportExpression: ['source'], // Additional Properties. ArrayPattern: ['decorators', 'elements', 'typeAnnotation'], ArrowFunctionExpression: ['typeParameters', 'params', 'returnType', 'body'], @@ -40,7 +42,6 @@ export const visitorKeys = eslintVisitorKeys.unionWith({ JSXSpreadChild: ['expression'], // Additional Nodes. - BigIntLiteral: [], ClassProperty: ['decorators', 'key', 'typeAnnotation', 'value'], Decorator: ['expression'], OptionalCallExpression: ['callee', 'typeParameters', 'arguments'], diff --git a/packages/typescript-estree/tests/ast-alignment/fixtures-to-test.ts b/packages/typescript-estree/tests/ast-alignment/fixtures-to-test.ts index e454fe6fb6d6..eb247042a8f2 100644 --- a/packages/typescript-estree/tests/ast-alignment/fixtures-to-test.ts +++ b/packages/typescript-estree/tests/ast-alignment/fixtures-to-test.ts @@ -37,8 +37,8 @@ class FixturesTester { * Utility to generate a FixturePatternConfig object containing the glob pattern for specific subsections of the fixtures/ directory, * including the capability to ignore specific nested patterns. * - * @param {string} fixturesSubPath the sub-path within the fixtures/ directory - * @param {CreateFixturePatternConfig?} config an optional configuration object with optional sub-paths to ignore and/or parse with sourceType: module + * @param fixturesSubPath the sub-path within the fixtures/ directory + * @param config an optional configuration object with optional sub-paths to ignore and/or parse with sourceType: module */ public addFixturePatternConfig( fixturesSubPath: string, @@ -186,19 +186,7 @@ tester.addFixturePatternConfig('javascript/function', { ], }); -tester.addFixturePatternConfig('javascript/bigIntLiterals', { - ignore: [ - /** - * new BigIntLiteral type - * @see https://github.com/estree/estree/blob/master/es2020.md#bigintliteral - * @see https://github.com/typescript-eslint/typescript-eslint/pull/1389 - */ - 'binary', - 'decimal', - 'hex', - 'octal', - ], -}); +tester.addFixturePatternConfig('javascript/bigIntLiterals'); tester.addFixturePatternConfig('javascript/binaryLiterals'); tester.addFixturePatternConfig('javascript/blockBindings'); @@ -229,16 +217,7 @@ tester.addFixturePatternConfig('javascript/destructuring-and-forOf'); tester.addFixturePatternConfig('javascript/destructuring-and-spread'); tester.addFixturePatternConfig('javascript/experimentalAsyncIteration'); -tester.addFixturePatternConfig('javascript/experimentalDynamicImport', { - ignore: [ - /** - * new ImportExpression type - * @see https://github.com/estree/estree/blob/master/es2020.md#importexpression - * @see https://github.com/typescript-eslint/typescript-eslint/pull/1389 - */ - 'dynamic-import', - ], -}); +tester.addFixturePatternConfig('javascript/experimentalDynamicImport'); tester.addFixturePatternConfig('javascript/exponentiationOperators'); tester.addFixturePatternConfig('javascript/experimentalOptionalCatchBinding'); diff --git a/packages/typescript-estree/tests/lib/__snapshots__/javascript.ts.snap b/packages/typescript-estree/tests/lib/__snapshots__/javascript.ts.snap index b2814f8b4ba5..1ae708c8a404 100644 --- a/packages/typescript-estree/tests/lib/__snapshots__/javascript.ts.snap +++ b/packages/typescript-estree/tests/lib/__snapshots__/javascript.ts.snap @@ -16491,6 +16491,7 @@ Object { "body": Array [ Object { "expression": Object { + "bigint": "1", "loc": Object { "end": Object { "column": 4, @@ -16506,8 +16507,8 @@ Object { 4, ], "raw": "0b1n", - "type": "BigIntLiteral", - "value": "0b1", + "type": "Literal", + "value": 1n, }, "loc": Object { "end": Object { @@ -16588,6 +16589,7 @@ Object { "body": Array [ Object { "expression": Object { + "bigint": "1", "loc": Object { "end": Object { "column": 2, @@ -16603,8 +16605,8 @@ Object { 2, ], "raw": "1n", - "type": "BigIntLiteral", - "value": "1", + "type": "Literal", + "value": 1n, }, "loc": Object { "end": Object { @@ -16685,6 +16687,7 @@ Object { "body": Array [ Object { "expression": Object { + "bigint": "1", "loc": Object { "end": Object { "column": 4, @@ -16700,8 +16703,8 @@ Object { 4, ], "raw": "0x1n", - "type": "BigIntLiteral", - "value": "0x1", + "type": "Literal", + "value": 1n, }, "loc": Object { "end": Object { @@ -16782,6 +16785,7 @@ Object { "body": Array [ Object { "expression": Object { + "bigint": "1", "loc": Object { "end": Object { "column": 4, @@ -16797,8 +16801,8 @@ Object { 4, ], "raw": "0o1n", - "type": "BigIntLiteral", - "value": "0o1", + "type": "Literal", + "value": 1n, }, "loc": Object { "end": Object { @@ -80423,44 +80427,6 @@ Object { }, }, "object": Object { - "arguments": Array [ - Object { - "loc": Object { - "end": Object { - "column": 12, - "line": 1, - }, - "start": Object { - "column": 7, - "line": 1, - }, - }, - "range": Array [ - 7, - 12, - ], - "raw": "'foo'", - "type": "Literal", - "value": "foo", - }, - ], - "callee": Object { - "loc": Object { - "end": Object { - "column": 6, - "line": 1, - }, - "start": Object { - "column": 0, - "line": 1, - }, - }, - "range": Array [ - 0, - 6, - ], - "type": "Import", - }, "loc": Object { "end": Object { "column": 13, @@ -80471,12 +80437,30 @@ Object { "line": 1, }, }, - "optional": false, "range": Array [ 0, 13, ], - "type": "CallExpression", + "source": Object { + "loc": Object { + "end": Object { + "column": 12, + "line": 1, + }, + "start": Object { + "column": 7, + "line": 1, + }, + }, + "range": Array [ + 7, + 12, + ], + "raw": "'foo'", + "type": "Literal", + "value": "foo", + }, + "type": "ImportExpression", }, "optional": false, "property": Object { @@ -80738,6 +80722,8 @@ Object { } `; +exports[`javascript fixtures/experimentalDynamicImport/error-dynamic-import-params.src 1`] = `"Dynamic import must have one specifier as an argument."`; + exports[`javascript fixtures/experimentalObjectRestSpread/arg-spread.src 1`] = ` Object { "body": Array [ diff --git a/packages/typescript-estree/tests/lib/__snapshots__/semantic-diagnostics-enabled.ts.snap b/packages/typescript-estree/tests/lib/__snapshots__/semantic-diagnostics-enabled.ts.snap index 2cff4d0b441b..bdc9a9a52dc3 100644 --- a/packages/typescript-estree/tests/lib/__snapshots__/semantic-diagnostics-enabled.ts.snap +++ b/packages/typescript-estree/tests/lib/__snapshots__/semantic-diagnostics-enabled.ts.snap @@ -585,6 +585,15 @@ exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" e exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" enabled fixtures/javascript/experimentalDynamicImport/dynamic-import.src 1`] = `"TEST OUTPUT: No semantic or syntactic issues found"`; +exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" enabled fixtures/javascript/experimentalDynamicImport/error-dynamic-import-params.src 1`] = ` +Object { + "column": 7, + "index": 7, + "lineNumber": 1, + "message": "Dynamic import must have one specifier as an argument.", +} +`; + exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" enabled fixtures/javascript/experimentalObjectRestSpread/arg-spread.src 1`] = `"TEST OUTPUT: No semantic or syntactic issues found"`; exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" enabled fixtures/javascript/experimentalObjectRestSpread/destructuring-assign-mirror.src 1`] = `"TEST OUTPUT: No semantic or syntactic issues found"`; From 8a4a396ec55bf3a1d4d949e3c0b44ab93746a0ec Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Sun, 10 May 2020 10:29:29 -0700 Subject: [PATCH 14/33] chore: setup automatic RC releases for v3 branch (#2000) --- .github/workflows/ci.yml | 109 +++++++++++++++++++++++++++++++-------- package.json | 27 +++++----- 2 files changed, 101 insertions(+), 35 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8fcbc40561c0..60e6627de93b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,11 +38,15 @@ jobs: restore-keys: | ${{ runner.os }}-yarn- - # This also runs a build as part of the postinstall bootstrap - - name: Install dependencies and build + - name: Install dependencies run: | - yarn --ignore-engines --frozen-lockfile - yarn check-clean-workspace-after-install + yarn --ignore-engines --frozen-lockfile --ignore-scripts + yarn lerna:init + yarn check:clean-workspace-after-install + + - name: Build + run: | + yarn build # Note that this command *also* type checks tests/tools, # whereas the build only checks src files @@ -84,14 +88,18 @@ jobs: restore-keys: | ${{ runner.os }}-yarn- - # This also runs a build as part of the postinstall bootstrap - - name: Install dependencies and build + - name: Install dependencies + run: | + yarn --ignore-engines --frozen-lockfile --ignore-scripts + yarn lerna:init + yarn check:clean-workspace-after-install + + - name: Build run: | - yarn --ignore-engines --frozen-lockfile - yarn check-clean-workspace-after-install + yarn build - name: Check code formatting - run: yarn format-check + run: yarn check:format - name: Lint code run: yarn lint @@ -124,14 +132,18 @@ jobs: restore-keys: | ${{ runner.os }}-yarn- - # This also runs a build as part of the postinstall bootstrap - - name: Install dependencies and build + - name: Install dependencies + run: | + yarn --ignore-engines --frozen-lockfile --ignore-scripts + yarn lerna:init + yarn check:clean-workspace-after-install + + - name: Build run: | - yarn --ignore-engines --frozen-lockfile - yarn check-clean-workspace-after-install + yarn build - name: Run integrations tests - run: yarn integration-tests + run: yarn test:integration env: CI: true @@ -160,11 +172,15 @@ jobs: restore-keys: | ${{ runner.os }}-yarn- - # This also runs a build as part of the postinstall bootstrap - - name: Install dependencies and build + - name: Install dependencies run: | - yarn --ignore-engines --frozen-lockfile - yarn check-clean-workspace-after-install + yarn --ignore-engines --frozen-lockfile --ignore-scripts + yarn lerna:init + yarn check:clean-workspace-after-install + + - name: Build + run: | + yarn build - name: Run unit tests # the internal plugin is only run locally, so it doesn't have to support older versions @@ -201,13 +217,62 @@ jobs: restore-keys: | ${{ runner.os }}-yarn- - # This also runs a build as part of the postinstall bootstrap - - name: Install dependencies and build + - name: Install dependencies run: | - yarn --ignore-engines --frozen-lockfile - yarn check-clean-workspace-after-install + yarn --ignore-engines --frozen-lockfile --ignore-scripts + yarn lerna:init + yarn check:clean-workspace-after-install + + - name: Build + run: | + yarn build - name: Publish all packages to npm run: npx lerna publish --loglevel=verbose --canary --exact --force-publish --yes env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + # TODO - delete this before merging v3 into master + publish_v3_prerelease_version: + name: Publish the latest code as a v3 prerelease version + runs-on: ubuntu-latest + needs: [primary_code_validation_and_tests, unit_tests_on_other_node_versions, linting_and_style, integration_tests] + if: github.ref == 'refs/heads/v3' + steps: + - uses: actions/checkout@v2 + # Fetch all history for all tags and branches in this job because lerna needs it + - run: | + git fetch --prune --unshallow + + - name: Use Node.js ${{ env.PRIMARY_NODE_VERSION }} + uses: actions/setup-node@v1 + with: + node-version: ${{ env.PRIMARY_NODE_VERSION }} + registry-url: https://registry.npmjs.org/ + + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "::set-output name=dir::$(yarn cache dir)" + + - uses: actions/cache@v1 + id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - name: Install dependencies + run: | + yarn --ignore-engines --frozen-lockfile --ignore-scripts + yarn lerna:init + yarn check:clean-workspace-after-install + + - name: Build + run: | + yarn build + + - name: Publish all packages to npm + run: npx lerna publish --loglevel=verbose --canary --exact --force-publish --yes --dist-tag rc-v3 + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/package.json b/package.json index 164fe95a34c0..41ba35916588 100644 --- a/package.json +++ b/package.json @@ -18,25 +18,26 @@ }, "scripts": { "build": "lerna run build", - "clean": "lerna clean && lerna run clean", - "cz": "git-cz", - "check:docs": "lerna run check:docs", + "check:clean-workspace-after-install": "git diff --quiet --exit-code", "check:configs": "lerna run check:configs", + "check:docs": "lerna run check:docs", + "check:format": "prettier --list-different \"./**/*.{ts,js,json,md}\"", "check:spelling": "cspell --config=.cspell.json \"**/*.{md,ts,js}\"", - "generate-contributors": "yarn ts-node --transpile-only ./tools/generate-contributors.ts && yarn all-contributors generate", + "clean": "lerna clean && lerna run clean", + "cz": "git-cz", "format": "prettier --write \"./**/*.{ts,js,json,md}\"", - "format-check": "prettier --list-different \"./**/*.{ts,js,json,md}\"", - "integration-tests": "./tests/integration/run-all-tests.sh", - "kill-integration-test-containers": "docker-compose -f tests/integration/docker-compose.yml down -v --rmi local", - "lint": "eslint . --ext .js,.ts", - "lint-fix": "eslint . --ext .js,.ts --fix", - "lint:markdown": "markdownlint '**/*.md' --config=.markdownlint.json --ignore-path=.markdownlintignore", + "generate:contributors": "yarn ts-node --transpile-only ./tools/generate-contributors.ts && yarn all-contributors generate", + "lerna:init": "lerna bootstrap --ignore-scripts && lerna link --force-local", + "lint:fix": "eslint . --ext .js,.ts --fix", "lint:markdown:fix": "lint:markdown --fix", + "lint:markdown": "markdownlint '**/*.md' --config=.markdownlint.json --ignore-path=.markdownlintignore", + "lint": "eslint . --ext .js,.ts", + "postinstall": "yarn lerna-init && yarn build", "pre-commit": "yarn lint-staged", - "pre-push": "yarn format-check", - "postinstall": "lerna bootstrap -- --ignore-engines && yarn build && lerna link", - "check-clean-workspace-after-install": "git diff --quiet --exit-code", + "pre-push": "yarn check:format", "test": "lerna run test --concurrency 1", + "test:integration": "./tests/integration/run-all-tests.sh", + "test:kill-integration-containers": "docker-compose -f tests/integration/docker-compose.yml down -v --rmi local", "typecheck": "lerna run typecheck" }, "config": { From 02afc316b17870060ee52f9f2b36c8d510055f2f Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Sun, 10 May 2020 10:46:04 -0700 Subject: [PATCH 15/33] chore: trigger actions on commits into v3 --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 60e6627de93b..28993958cef9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,6 +4,8 @@ on: push: branches: - master + # TODO - delete this before merging v3 into master + - v3 pull_request: branches: - '**' From cd1448240dca11762fcb9c10e18bb6541a840485 Mon Sep 17 00:00:00 2001 From: Nikita Stefaniak Date: Sun, 10 May 2020 21:11:01 +0200 Subject: [PATCH 16/33] feat(eslint-plugin): [strict-boolean-expression] rework options (#1631) --- .../docs/rules/strict-boolean-expressions.md | 123 +- .../src/rules/strict-boolean-expressions.ts | 189 ++- .../rules/strict-boolean-expressions.test.ts | 1398 +++-------------- 3 files changed, 421 insertions(+), 1289 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/strict-boolean-expressions.md b/packages/eslint-plugin/docs/rules/strict-boolean-expressions.md index cec621588ef2..07284154a311 100644 --- a/packages/eslint-plugin/docs/rules/strict-boolean-expressions.md +++ b/packages/eslint-plugin/docs/rules/strict-boolean-expressions.md @@ -1,67 +1,122 @@ # Restricts the types allowed in boolean expressions (`strict-boolean-expressions`) -Requires that any boolean expression is limited to true booleans rather than -casting another primitive to a boolean at runtime. +Forbids usage of non-boolean types in expressions where a boolean is expected. +`boolean` and `never` types are always allowed. +Additional types which are considered safe in a boolean context can be configured via options. -It is useful to be explicit, for example, if you were trying to check if a -number was defined. Doing `if (number)` would evaluate to `false` if `number` -was defined and `0`. This rule forces these expressions to be explicit and to -strictly use booleans. +The following nodes are considered boolean expressions and their type is checked: -The following nodes are checked: - -- Arguments to the `!`, `&&`, and `||` operators -- The condition in a conditional expression `(cond ? x : y)` +- Argument to the logical negation operator (`!arg`). +- The condition in a conditional expression (`cond ? x : y`). - Conditions for `if`, `for`, `while`, and `do-while` statements. +- Operands of logical binary operators (`lhs || rhs` and `lhs && rhs`). + - Right-hand side operand is ignored when it's not a descendant of another boolean expression. + This is to allow usage of boolean operators for their short-circuiting behavior. + +## Examples Examples of **incorrect** code for this rule: ```ts -const number = 0; -if (number) { - return; +// nullable numbers are considered unsafe by default +let num: number | undefined = 0; +if (num) { + console.log('num is defined'); +} + +// nullable strings are considered unsafe by default +let str: string | null = null; +if (!str) { + console.log('str is empty'); } -let foo = bar || 'foobar'; +// nullable booleans are considered unsafe by default +function foo(bool?: boolean) { + if (bool) { + bar(); + } +} -let undefinedItem; -let foo = undefinedItem ? 'foo' : 'bar'; +// `any`, unconstrained generics and unions of more than one primitive type are disallowed +const foo = (arg: T) => (arg ? 1 : 0); -let str = 'foo'; -while (str) { - break; +// always-truthy and always-falsy types are disallowed +let obj = {}; +while (obj) { + obj = getObj(); } ``` Examples of **correct** code for this rule: -```ts -const number = 0; -if (typeof number !== 'undefined') { - return; +```tsx +// Using logical operators for their side effects is allowed +const Component = () => { + const entry = map.get('foo') || {}; + return entry &&

Name: {entry.name}

; +}; + +// nullable values should be checked explicitly against null or undefined +let num: number | undefined = 0; +if (num != null) { + console.log('num is defined'); } -let foo = typeof bar !== 'undefined' ? bar : 'foobar'; - -let undefinedItem; -let foo = typeof undefinedItem !== 'undefined' ? 'foo' : 'bar'; +let str: string | null = null; +if (str != null && !str) { + console.log('str is empty'); +} -let str = 'foo'; -while (typeof str !== 'undefined') { - break; +function foo(bool?: boolean) { + if (bool ?? false) { + bar(); + } } + +// `any` types should be cast to boolean explicitly +const foo = (arg: any) => (Boolean(arg) ? 1 : 0); ``` ## Options Options may be provided as an object with: -- `allowNullable` to allow `undefined` and `null` in addition to `boolean` as a type of all boolean expressions. (`false` by default). -- `allowSafe` to allow non-falsy types (i.e. non string / number / boolean) in addition to `boolean` as a type of all boolean expressions. (`false` by default). -- `ignoreRhs` to skip the check on the right hand side of expressions like `a && b` or `a || b` - allows these operators to be used for their short-circuiting behavior. (`false` by default). +- `allowString` (`true` by default) - + Allows `string` in a boolean context. + This is safe because strings have only one falsy value (`""`). + Set this to `false` if you prefer the explicit `str != ""` or `str.length > 0` style. + +- `allowNumber` (`true` by default) - + Allows `number` in a boolean context. + This is safe because numbers have only two falsy values (`0` and `NaN`). + Set this to `false` if you prefer the explicit `num != 0` and `!Number.isNaN(num)` style. + +- `allowNullableObject` (`true` by default) - + Allows `object | function | symbol | null | undefined` in a boolean context. + This is safe because objects, functions and symbols don't have falsy values. + Set this to `false` if you prefer the explicit `obj != null` style. + +- `allowNullableBoolean` (`false` by default) - + Allows `boolean | null | undefined` in a boolean context. + This is unsafe because nullable booleans can be either `false` or nullish. + Set this to `false` if you want to enforce explicit `bool ?? false` or `bool ?? true` style. + Set this to `true` if you don't mind implicitly treating false the same as a nullish value. + +- `allowNullableString` (`false` by default) - + Allows `string | null | undefined` in a boolean context. + This is unsafe because nullable strings can be either an empty string or nullish. + Set this to `true` if you don't mind implicitly treating an empty string the same as a nullish value. + +- `allowNullableNumber` (`false` by default) - + Allows `number | null | undefined` in a boolean context. + This is unsafe because nullable numbers can be either a falsy number or nullish. + Set this to `true` if you don't mind implicitly treating zero or NaN the same as a nullish value. + +- `allowAny` (`false` by default) - + Allows `any` in a boolean context. ## Related To - TSLint: [strict-boolean-expressions](https://palantir.github.io/tslint/rules/strict-boolean-expressions) -- [no-unnecessary-condition](./no-unnecessary-condition.md) - essentially a less opinionated alternative to this rule. `strict-boolean-expressions` enforces a specific code style, while `no-unnecessary-condition` is about correctness. +- [no-unnecessary-condition](./no-unnecessary-condition.md) - Similar rule which reports always-truthy and always-falsy values in conditions diff --git a/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts b/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts index 265bc05a41f8..df2b59e12ec8 100644 --- a/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts +++ b/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts @@ -6,15 +6,19 @@ import * as ts from 'typescript'; import * as tsutils from 'tsutils'; import * as util from '../util'; -type Options = [ +export type Options = [ { - ignoreRhs?: boolean; - allowNullable?: boolean; - allowSafe?: boolean; + allowString?: boolean; + allowNumber?: boolean; + allowNullableObject?: boolean; + allowNullableBoolean?: boolean; + allowNullableString?: boolean; + allowNullableNumber?: boolean; + allowAny?: boolean; }, ]; -type MessageId = +export type MessageId = | 'conditionErrorOther' | 'conditionErrorAny' | 'conditionErrorNullish' @@ -40,15 +44,13 @@ export default util.createRule({ { type: 'object', properties: { - ignoreRhs: { - type: 'boolean', - }, - allowNullable: { - type: 'boolean', - }, - allowSafe: { - type: 'boolean', - }, + allowString: { type: 'boolean' }, + allowNumber: { type: 'boolean' }, + allowNullableObject: { type: 'boolean' }, + allowNullableBoolean: { type: 'boolean' }, + allowNullableString: { type: 'boolean' }, + allowNullableNumber: { type: 'boolean' }, + allowAny: { type: 'boolean' }, }, additionalProperties: false, }, @@ -88,9 +90,9 @@ export default util.createRule({ }, defaultOptions: [ { - ignoreRhs: false, - allowNullable: false, - allowSafe: false, + allowString: true, + allowNumber: true, + allowNullableObject: true, }, ], create(context, [options]) { @@ -109,14 +111,14 @@ export default util.createRule({ 'UnaryExpression[operator="!"]': checkUnaryLogicalExpression, }; - type ExpressionWithTest = + type TestExpression = | TSESTree.ConditionalExpression | TSESTree.DoWhileStatement | TSESTree.ForStatement | TSESTree.IfStatement | TSESTree.WhileStatement; - function checkTestExpression(node: ExpressionWithTest): void { + function checkTestExpression(node: TestExpression): void { if (node.test == null) { return; } @@ -128,52 +130,35 @@ export default util.createRule({ } /** - * This function analyzes the type of a boolean expression node and checks if it is allowed. - * It can recurse when checking nested logical operators, so that only the outermost expressions are reported. + * This function analyzes the type of a node and checks if it is allowed in a boolean context. + * It can recurse when checking nested logical operators, so that only the outermost operands are reported. + * The right operand of a logical expression is ignored unless it's a part of a test expression (if/while/ternary/etc). * @param node The AST node to check. - * @param isRoot Whether it is the root of a logical expression and there was no recursion yet. - * @returns `true` if there was an error reported. + * @param isTestExpr Whether the node is a descendant of a test expression. */ - function checkNode(node: TSESTree.Node, isRoot = false): boolean { + function checkNode(node: TSESTree.Node, isTestExpr = false): void { // prevent checking the same node multiple times if (checkedNodes.has(node)) { - return false; + return; } checkedNodes.add(node); - // for logical operator, we also check its operands + // for logical operator, we check its operands if ( node.type === AST_NODE_TYPES.LogicalExpression && node.operator !== '??' ) { - let hasError = false; - if (checkNode(node.left)) { - hasError = true; - } - if (!options.ignoreRhs) { - if (checkNode(node.right)) { - hasError = true; - } - } - // if this logical operator is not the root of a logical expression - // we only check its operands and return - if (!isRoot) { - return hasError; - } - // if this is the root of a logical expression - // we want to check its resulting type too - else { - // ...unless there already was an error, we exit so we don't double-report - if (hasError) { - return true; - } + checkNode(node.left, isTestExpr); + + // we ignore the right operand when not in a context of a test expression + if (isTestExpr) { + checkNode(node.right, isTestExpr); } + return; } const tsNode = service.esTreeNodeToTSNodeMap.get(node); const type = util.getConstrainedTypeAtLocation(checker, tsNode); - let messageId: MessageId | undefined; - const types = inspectVariantTypes(tsutils.unionTypeParts(type)); const is = (...wantedTypes: readonly VariantType[]): boolean => @@ -183,79 +168,87 @@ export default util.createRule({ // boolean if (is('boolean')) { // boolean is always okay - return false; + return; } + // never if (is('never')) { // never is always okay - return false; + return; } + // nullish - else if (is('nullish')) { + if (is('nullish')) { // condition is always false - messageId = 'conditionErrorNullish'; + context.report({ node, messageId: 'conditionErrorNullish' }); + return; } + // nullable boolean - else if (is('nullish', 'boolean')) { - if (!options.allowNullable) { - messageId = 'conditionErrorNullableBoolean'; + if (is('nullish', 'boolean')) { + if (!options.allowNullableBoolean) { + context.report({ node, messageId: 'conditionErrorNullableBoolean' }); } + return; } + // string - else if (is('string')) { - messageId = 'conditionErrorString'; + if (is('string')) { + if (!options.allowString) { + context.report({ node, messageId: 'conditionErrorString' }); + } + return; } + // nullable string - else if (is('nullish', 'string')) { - messageId = 'conditionErrorNullableString'; + if (is('nullish', 'string')) { + if (!options.allowNullableString) { + context.report({ node, messageId: 'conditionErrorNullableString' }); + } + return; } + // number - else if (is('number')) { - messageId = 'conditionErrorNumber'; + if (is('number')) { + if (!options.allowNumber) { + context.report({ node, messageId: 'conditionErrorNumber' }); + } + return; } + // nullable number - else if (is('nullish', 'number')) { - messageId = 'conditionErrorNullableNumber'; + if (is('nullish', 'number')) { + if (!options.allowNullableNumber) { + context.report({ node, messageId: 'conditionErrorNullableNumber' }); + } + return; } + // object - else if (is('object')) { + if (is('object')) { // condition is always true - if (!options.allowSafe) { - messageId = 'conditionErrorObject'; - } + context.report({ node, messageId: 'conditionErrorObject' }); + return; } + // nullable object - else if (is('nullish', 'object')) { - if (!options.allowSafe || !options.allowNullable) { - messageId = 'conditionErrorNullableObject'; - } - } - // boolean/object - else if (is('boolean', 'object')) { - if (!options.allowSafe) { - messageId = 'conditionErrorOther'; - } - } - // nullable boolean/object - else if (is('nullish', 'boolean', 'object')) { - if (!options.allowSafe || !options.allowNullable) { - messageId = 'conditionErrorOther'; + if (is('nullish', 'object')) { + if (!options.allowNullableObject) { + context.report({ node, messageId: 'conditionErrorNullableObject' }); } + return; } + // any - else if (is('any')) { - messageId = 'conditionErrorAny'; - } - // other - else { - messageId = 'conditionErrorOther'; + if (is('any')) { + if (!options.allowAny) { + context.report({ node, messageId: 'conditionErrorAny' }); + } + return; } - if (messageId != null) { - context.report({ node, messageId }); - return true; - } - return false; + // other + context.report({ node, messageId: 'conditionErrorOther' }); } /** The types we care about */ @@ -300,7 +293,12 @@ export default util.createRule({ } if ( - types.some(type => tsutils.isTypeFlagSet(type, ts.TypeFlags.NumberLike)) + types.some(type => + tsutils.isTypeFlagSet( + type, + ts.TypeFlags.NumberLike | ts.TypeFlags.BigIntLike, + ), + ) ) { variantTypes.add('number'); } @@ -316,6 +314,7 @@ export default util.createRule({ ts.TypeFlags.BooleanLike | ts.TypeFlags.StringLike | ts.TypeFlags.NumberLike | + ts.TypeFlags.BigIntLike | ts.TypeFlags.Any | ts.TypeFlags.Unknown | ts.TypeFlags.Never, diff --git a/packages/eslint-plugin/tests/rules/strict-boolean-expressions.test.ts b/packages/eslint-plugin/tests/rules/strict-boolean-expressions.test.ts index daa619b84eeb..f72739fb0047 100644 --- a/packages/eslint-plugin/tests/rules/strict-boolean-expressions.test.ts +++ b/packages/eslint-plugin/tests/rules/strict-boolean-expressions.test.ts @@ -1,1239 +1,317 @@ -import rule from '../../src/rules/strict-boolean-expressions'; +import rule, { + Options, + MessageId, +} from '../../src/rules/strict-boolean-expressions'; import { - RuleTester, - getFixturesRootDir, batchedSingleLineTests, + getFixturesRootDir, + RuleTester, noFormat, } from '../RuleTester'; -const rootPath = getFixturesRootDir(); - const ruleTester = new RuleTester({ parser: '@typescript-eslint/parser', parserOptions: { - tsconfigRootDir: rootPath, + tsconfigRootDir: getFixturesRootDir(), project: './tsconfig.json', }, }); ruleTester.run('strict-boolean-expressions', rule, { valid: [ - ` - let val = true; - let bool = !val; - let bool2 = true || val; - let bool3 = true && val; - `, - ` - let a = 0; - let u1 = typeof a; - let u2 = -a; - let u3 = ~a; - `, - ` - const bool1 = true; - const bool2 = false; - if (true) { - return; - } - - if (bool1) { - return; - } - - if (bool1 && bool2) { - return; - } + // boolean in boolean context + ...batchedSingleLineTests({ + code: noFormat` + true ? "a" : "b"; + if (false) {} + while (true) {} + for (; false;) {} + !true; + false || 123; + true && "foo"; + !(false || true); + true && false ? true : false; + false && true || false; + false && true || []; + (false && 1) || (true && 2); + declare const x: boolean; if (x) {} + (x: boolean) => !x; + (x: T) => x ? 1 : 0; + declare const x: never; if (x) {} + `, + }), - if (bool1 || bool2) { - return; - } + // string in boolean context + ...batchedSingleLineTests({ + code: noFormat` + if ("") {} + while ("x") {} + for (; "";) {} + "" && "1" || x; + declare const x: string; if (x) {} + (x: string) => !x; + (x: T) => x ? 1 : 0; + `, + }), - if ((bool1 && bool2) || bool1 || bool2) { - return; - } - `, - ` - const bool1 = true; - const bool2 = false; - const res1 = true ? true : false; - const res2 = bool1 && bool2 ? true : false; - const res3 = bool1 || bool2 ? true : false; - const res4 = (bool1 && bool2) || bool1 || bool2 ? true : false; - `, - ` - for (let i = 0; true; i++) { - break; - } - `, - ` - const bool = true; - for (let i = 0; bool; i++) { - break; - } - `, - ` - const bool1 = true; - const bool2 = false; - for (let i = 0; bool1 && bool2; i++) { - break; - } - `, - ` - const bool1 = true; - const bool2 = false; - for (let i = 0; bool1 || bool2; i++) { - break; - } - `, - ` - const bool1 = true; - const bool2 = false; - for (let i = 0; (bool1 && bool2) || bool1 || bool2; i++) { - break; - } - `, - ` - while (true) { - break; - } - `, - ` - const bool = true; - while (bool) { - break; - } - `, - ` - const bool1 = true; - const bool2 = false; - while (bool1 && bool2) { - break; - } - `, - ` - const bool1 = true; - const bool2 = false; - while (bool1 || bool2) { - break; - } - `, - ` - const bool1 = true; - const bool2 = false; - while ((bool1 && bool2) || bool1 || bool2) { - break; - } - `, - ` - do { - break; - } while (true); - `, - ` - const bool = true; - do { - break; - } while (bool); - `, - ` - const bool1 = true; - const bool2 = false; - do { - break; - } while (bool1 && bool2); - `, - ` - const bool1 = true; - const bool2 = false; - do { - break; - } while (bool1 || bool2); - `, - ` - const bool1 = true; - const bool2 = false; - do { - break; - } while ((bool1 && bool2) || bool1 || bool2); - `, - ` - function foo(arg: T) { - return !arg; - } - `, - { - options: [{ ignoreRhs: true }], - code: ` - const obj = { x: 1 }; - const bool = false; - const boolOrObj = bool || obj; - const boolAndObj = bool && obj; + // number in boolean context + ...batchedSingleLineTests({ + code: noFormat` + if (0) {} + while (1n) {} + for (; Infinity;) {} + 0 / 0 && 1 + 2 || x; + declare const x: number; if (x) {} + (x: bigint) => !x; + (x: T) => x ? 1 : 0; `, - }, - ...batchedSingleLineTests({ - options: [{ allowNullable: true }], - code: ` - const f1 = (x?: boolean) => (x ? 1 : 0); - const f2 = (x: boolean | null) => (x ? 1 : 0); - const f3 = (x?: true | null) => (x ? 1 : 0); - const f4 = (x?: false) => (x ? 1 : 0); + }), + + // nullable object in boolean context + ...batchedSingleLineTests({ + code: noFormat` + declare const x: null | object; if (x) {} + (x?: { a: any }) => !x; + (x: T) => x ? 1 : 0; `, }), - ` - declare const x: string | null; - y = x ?? 'foo'; - `, - ...batchedSingleLineTests({ - options: [{ allowSafe: true }], - code: ` - const f1 = (x: boolean | { a: string }) => (x ? 1 : 0); - const f2 = (x: true | { a: string }) => (x ? 1 : 0); - const f3 = (x: { a: string } | false) => (x ? 1 : 0); + + // nullable boolean in boolean context + ...batchedSingleLineTests({ + options: [{ allowNullableBoolean: true }], + code: noFormat` + declare const x: boolean | null; if (x) {} + (x?: boolean) => !x; + (x: T) => x ? 1 : 0; `, }), - ...batchedSingleLineTests({ - options: [{ allowNullable: true, allowSafe: true }], - code: ` - const f1 = (x?: boolean | { a?: 1 }) => (x ? 1 : 0); - const f2 = (x: { a?: 1 } | { b?: 'a' } | null) => (x ? 1 : 0); - const f3 = (x?: { a?: 1 } | { b?: 'a' } | null) => (x ? 1 : 0); - const f4 = (x?: { b?: 'a' } | true) => (x ? 1 : 0); - const f5 = (g?: (x: number) => number) => (g ? g(1) : 0); + + // nullable string in boolean context + ...batchedSingleLineTests({ + options: [{ allowNullableString: true }], + code: noFormat` + declare const x: string | null; if (x) {} + (x?: string) => !x; + (x: T) => x ? 1 : 0; `, }), - ...batchedSingleLineTests({ - options: [{ allowNullable: true, allowSafe: true, ignoreRhs: true }], - code: ` - const f1 = (x?: { a: null }) => x && x.foo && x.foo.bar; - const f2 = (g?: (x: number) => number) => g && g(1); + + // nullable number in boolean context + ...batchedSingleLineTests({ + options: [{ allowNullableNumber: true }], + code: noFormat` + declare const x: number | null; if (x) {} + (x?: number) => !x; + (x: T) => x ? 1 : 0; `, }), - ` - declare let x: never; - if (x) { - } - `, - ...batchedSingleLineTests({ + + // any in boolean context + ...batchedSingleLineTests({ + options: [{ allowAny: true }], code: noFormat` - function f1(x: never) { return !x; } - function f2(x: never) { return x ? 1 : 0; } - function f3(x: never, y: never) { return x && y; } - function f5(x: never | boolean) { if (!x) { } } + declare const x: any; if (x) {} + (x) => !x; + (x: T) => x ? 1 : 0; `, }), ], invalid: [ - { - code: ` - let val = 'foo'; - let bool = !val; - `, - errors: [ - { - messageId: 'conditionErrorString', - line: 3, - column: 21, - }, - ], - }, - { - code: ` - let val; - let bool = !val; - `, - errors: [ - { - messageId: 'conditionErrorNullish', - line: 3, - column: 21, - }, - ], - }, - { - code: ` - let val = 1; - let bool = true && val; - `, - errors: [ - { - messageId: 'conditionErrorNumber', - line: 3, - column: 28, - }, - ], - }, - { - code: ` - let val; - let bool = true && val; - `, - errors: [ - { - messageId: 'conditionErrorNullish', - line: 3, - column: 28, - }, - ], - }, - { - code: ` - let val = 1; - let bool = true || val; - `, - errors: [ - { - messageId: 'conditionErrorNumber', - line: 3, - column: 28, - }, - ], - }, - { - code: ` - let val; - let bool = true || val; - `, - errors: [ - { - messageId: 'conditionErrorAny', - line: 3, - column: 28, - }, - ], - }, - { - code: ` - let num = 1; - let str = 'foo'; - let val = null; - let bool = true && (val || num || str); - `, - errors: [ - { - messageId: 'conditionErrorNullish', - line: 5, - column: 29, - }, - { - messageId: 'conditionErrorNumber', - line: 5, - column: 36, - }, - { - messageId: 'conditionErrorString', - line: 5, - column: 43, - }, - ], - }, - { - code: ` - if (1) { - return; - } - `, - errors: [ - { - messageId: 'conditionErrorNumber', - line: 2, - column: 13, - }, - ], - }, - { - code: ` - if (undefined) { - return; - } - `, - errors: [ - { - messageId: 'conditionErrorNullish', - line: 2, - column: 13, - }, - ], - }, - { - code: ` - let item = 'foo'; - if (item) { - return; - } - `, - errors: [ - { - messageId: 'conditionErrorString', - line: 3, - column: 13, - }, - ], - }, - { - code: ` - let item; - if (item) { - return; - } - `, - errors: [ - { - messageId: 'conditionErrorNullish', - line: 3, - column: 13, - }, - ], - }, - { - code: ` - let item1 = true; - let item2 = 1; - if (item1 && item2) { - return; - } - `, - errors: [ - { - messageId: 'conditionErrorNumber', - line: 4, - column: 22, - }, - ], - }, - { - code: ` - let item1 = 1; - let item2 = true; - if (item1 && item2) { - return; - } - `, - errors: [ - { - messageId: 'conditionErrorNumber', - line: 4, - column: 13, - }, - ], - }, - { - code: ` - let item1; - let item2 = true; - if (item1 && item2) { - return; - } - `, - errors: [ - { - messageId: 'conditionErrorNullish', - line: 4, - column: 13, - }, - ], - }, - { - code: ` - let item1 = true; - let item2 = 1; - if (item1 || item2) { - return; - } - `, - errors: [ - { - messageId: 'conditionErrorNumber', - line: 4, - column: 22, - }, - ], - }, - { - code: ` - let item1 = 1; - let item2 = true; - if (item1 || item2) { - return; - } - `, - errors: [ - { - messageId: 'conditionErrorNumber', - line: 4, - column: 13, - }, - ], - }, - { - code: ` - let item1; - let item2 = true; - if (item1 || item2) { - return; - } - `, - errors: [ - { - messageId: 'conditionErrorNullish', - line: 4, - column: 13, - }, - ], - }, - { - code: ` - const bool = 'foo' ? true : false; - `, - errors: [ - { - messageId: 'conditionErrorString', - line: 2, - column: 22, - }, - ], - }, - { - code: ` - const bool = undefined ? true : false; - `, - errors: [ - { - messageId: 'conditionErrorNullish', - line: 2, - column: 22, - }, - ], - }, - { - code: ` - let item = 1; - const bool = item ? true : false; - `, - errors: [ - { - messageId: 'conditionErrorNumber', - line: 3, - column: 22, - }, - ], - }, - { - code: ` - let item; - const bool = item ? true : false; - `, - errors: [ - { - messageId: 'conditionErrorNullish', - line: 3, - column: 22, - }, - ], - }, - { - code: ` - let item1 = 1; - let item2 = false; - const bool = item1 && item2 ? true : false; - `, - errors: [ - { - messageId: 'conditionErrorNumber', - line: 4, - column: 22, - }, - ], - }, - { - code: ` - let item1 = true; - let item2 = 1; - const bool = item1 && item2 ? true : false; - `, - errors: [ - { - messageId: 'conditionErrorNumber', - line: 4, - column: 31, - }, - ], - }, - { - code: ` - let item1 = true; - let item2; - const bool = item1 && item2 ? true : false; - `, - errors: [ - { - messageId: 'conditionErrorNullish', - line: 4, - column: 31, - }, - ], - }, - { - code: ` - let item1 = 1; - let item2 = false; - const bool = item1 || item2 ? true : false; - `, - errors: [ - { - messageId: 'conditionErrorNumber', - line: 4, - column: 22, - }, - ], - }, - { - code: ` - let item1 = true; - let item2 = 1; - const bool = item1 || item2 ? true : false; - `, - errors: [ - { - messageId: 'conditionErrorNumber', - line: 4, - column: 31, - }, - ], - }, - { - code: ` - let item1 = true; - let item2; - const bool = item1 || item2 ? true : false; - `, - errors: [ - { - messageId: 'conditionErrorNullish', - line: 4, - column: 31, - }, - ], - }, - { - code: ` - for (let i = 0; 1; i++) { - return; - } - `, - errors: [ - { - messageId: 'conditionErrorNumber', - line: 2, - column: 25, - }, + // non-boolean in RHS of test expression + ...batchedSingleLineTests({ + options: [ + { allowString: false, allowNumber: false, allowNullableObject: false }, ], - }, - { - code: ` - for (let i = 0; undefined; i++) { - return; - } - `, - errors: [ - { - messageId: 'conditionErrorNullish', - line: 2, - column: 25, - }, - ], - }, - { - code: ` - let bool = 1; - for (let i = 0; bool; i++) { - return; - } - `, - errors: [ - { - messageId: 'conditionErrorNumber', - line: 3, - column: 25, - }, - ], - }, - { - code: ` - let bool; - for (let i = 0; bool; i++) { - return; - } - `, - errors: [ - { - messageId: 'conditionErrorNullish', - line: 3, - column: 25, - }, - ], - }, - { - code: ` - let bool1 = 'foo'; - let bool2 = true; - for (let i = 0; bool1 && bool2; i++) { - return; - } - `, - errors: [ - { - messageId: 'conditionErrorString', - line: 4, - column: 25, - }, - ], - }, - { - code: ` - let bool1; - let bool2 = true; - for (let i = 0; bool1 && bool2; i++) { - return; - } - `, - errors: [ - { - messageId: 'conditionErrorNullish', - line: 4, - column: 25, - }, - ], - }, - { - code: ` - let bool1 = 1; - let bool2 = true; - for (let i = 0; bool1 || bool2; i++) { - return; - } - `, - errors: [ - { - messageId: 'conditionErrorNumber', - line: 4, - column: 25, - }, - ], - }, - { - code: ` - let bool1; - let bool2 = true; - for (let i = 0; bool1 || bool2; i++) { - return; - } - `, - errors: [ - { - messageId: 'conditionErrorNullish', - line: 4, - column: 25, - }, - ], - }, - { - code: ` - while (1) { - return; - } - `, - errors: [ - { - messageId: 'conditionErrorNumber', - line: 2, - column: 16, - }, - ], - }, - { - code: ` - while (undefined) { - return; - } - `, - errors: [ - { - messageId: 'conditionErrorNullish', - line: 2, - column: 16, - }, - ], - }, - { - code: ` - let bool = 1; - while (bool) { - return; - } - `, - errors: [ - { - messageId: 'conditionErrorNumber', - line: 3, - column: 16, - }, - ], - }, - { - code: ` - let bool; - while (bool) { - return; - } - `, - errors: [ - { - messageId: 'conditionErrorNullish', - line: 3, - column: 16, - }, - ], - }, - { - code: ` - let bool1 = 1; - let bool2 = true; - while (bool1 && bool2) { - return; - } - `, - errors: [ - { - messageId: 'conditionErrorNumber', - line: 4, - column: 16, - }, - ], - }, - { - code: ` - let bool1; - let bool2 = true; - while (bool1 && bool2) { - return; - } + code: noFormat` + if (true && 1) {} + while (false || "a") {} + (x: object) => true || false || x ? true : false; `, errors: [ - { - messageId: 'conditionErrorNullish', - line: 4, - column: 16, - }, + { messageId: 'conditionErrorNumber', line: 2, column: 13 }, + { messageId: 'conditionErrorString', line: 3, column: 25 }, + { messageId: 'conditionErrorObject', line: 4, column: 41 }, ], - }, + }), + + // check if all and only the outermost operands are checked { - code: ` - let bool1 = 1; - let bool2 = true; - while (bool1 || bool2) { - return; - } - `, - errors: [ - { - messageId: 'conditionErrorNumber', - line: 4, - column: 16, - }, + options: [ + { allowString: false, allowNumber: false, allowNullableObject: false }, ], - }, - { code: ` - let bool1; - let bool2 = true; - while (bool1 || bool2) { - return; + if (('' && {}) || (0 && void 0)) { } `, errors: [ - { - messageId: 'conditionErrorNullish', - line: 4, - column: 16, - }, - ], - }, - { - code: ` - do { - return; - } while ('foo'); - `, - errors: [ - { - messageId: 'conditionErrorString', - line: 4, - column: 18, - }, + { messageId: 'conditionErrorString', line: 2, column: 14 }, + { messageId: 'conditionErrorObject', line: 2, column: 20 }, + { messageId: 'conditionErrorNumber', line: 2, column: 28 }, + { messageId: 'conditionErrorNullish', line: 2, column: 33 }, ], }, - { - code: ` - do { - return; - } while (undefined); - `, - errors: [ - { - messageId: 'conditionErrorNullish', - line: 4, - column: 18, - }, - ], - }, - { - code: ` - let bool = 1; - do { - return; - } while (bool); - `, - errors: [ - { - messageId: 'conditionErrorNumber', - line: 5, - column: 18, - }, - ], - }, - { - code: ` - let bool; - do { - return; - } while (bool); - `, - errors: [ - { - messageId: 'conditionErrorAny', - line: 5, - column: 18, - }, - ], - }, - { - code: ` - let bool1 = 1; - let bool2 = true; - do { - return; - } while (bool1 && bool2); - `, - errors: [ - { - messageId: 'conditionErrorNumber', - line: 6, - column: 18, - }, - ], - }, - { - code: ` - let bool1; - let bool2 = true; - do { - return; - } while (bool1 && bool2); + + // nullish in boolean context + ...batchedSingleLineTests({ + code: noFormat` + null || {}; + undefined && []; + declare const x: null; if (x) {} + (x: undefined) => !x; + (x: T) => x ? 1 : 0; `, errors: [ - { - messageId: 'conditionErrorAny', - line: 6, - column: 18, - }, + { messageId: 'conditionErrorNullish', line: 2, column: 1 }, + { messageId: 'conditionErrorNullish', line: 3, column: 9 }, + { messageId: 'conditionErrorNullish', line: 4, column: 36 }, + { messageId: 'conditionErrorNullish', line: 5, column: 28 }, + { messageId: 'conditionErrorNullish', line: 6, column: 47 }, ], - }, - { - code: ` - let bool1 = 1; - let bool2 = true; - do { - return; - } while (bool1 || bool2); + }), + + // object in boolean context + ...batchedSingleLineTests({ + code: noFormat` + [] || 1; + ({}) && "a"; + declare const x: symbol; if (x) {} + (x: () => void) => !x; + (x: T) => x ? 1 : 0; `, errors: [ - { - messageId: 'conditionErrorNumber', - line: 6, - column: 18, - }, + { messageId: 'conditionErrorObject', line: 2, column: 1 }, + { messageId: 'conditionErrorObject', line: 3, column: 10 }, + { messageId: 'conditionErrorObject', line: 4, column: 38 }, + { messageId: 'conditionErrorObject', line: 5, column: 29 }, + { messageId: 'conditionErrorObject', line: 6, column: 37 }, ], - }, - { - code: ` - let bool1; - let bool2 = true; - do { - return; - } while (bool1 || bool2); + }), + + // string in boolean context + ...batchedSingleLineTests({ + options: [{ allowString: false }], + code: noFormat` + while ("") {} + for (; "foo";) {} + declare const x: string; if (x) {} + (x: string) => !x; + (x: T) => x ? 1 : 0; `, errors: [ - { - messageId: 'conditionErrorAny', - line: 6, - column: 18, - }, + { messageId: 'conditionErrorString', line: 2, column: 8 }, + { messageId: 'conditionErrorString', line: 3, column: 16 }, + { messageId: 'conditionErrorString', line: 4, column: 38 }, + { messageId: 'conditionErrorString', line: 5, column: 25 }, + { messageId: 'conditionErrorString', line: 6, column: 37 }, ], - }, - { - code: ` - function foo(arg: T) { - return !arg; - } + }), + + // number in boolean context + ...batchedSingleLineTests({ + options: [{ allowNumber: false }], + code: noFormat` + while (0n) {} + for (; 123;) {} + declare const x: number; if (x) {} + (x: bigint) => !x; + (x: T) => x ? 1 : 0; `, errors: [ - { - messageId: 'conditionErrorNumber', - line: 3, - column: 19, - }, - ], - }, - ...batchedSingleLineTests({ - errors: [ - { - messageId: 'conditionErrorNullableBoolean', - line: 2, - column: 48, - }, - { - messageId: 'conditionErrorNullableBoolean', - line: 3, - column: 38, - }, - { - messageId: 'conditionErrorOther', - line: 4, - column: 42, - }, + { messageId: 'conditionErrorNumber', line: 2, column: 8 }, + { messageId: 'conditionErrorNumber', line: 3, column: 16 }, + { messageId: 'conditionErrorNumber', line: 4, column: 38 }, + { messageId: 'conditionErrorNumber', line: 5, column: 25 }, + { messageId: 'conditionErrorNumber', line: 6, column: 37 }, ], - code: ` - const f1 = (x: boolean | null | undefined) => (x ? 1 : 0); - const f2 = (x?: boolean) => (x ? 1 : 0); - const f3 = (x: boolean | {}) => (x ? 1 : 0); - `, }), - { - options: [{ ignoreRhs: true }], - errors: [ - { - messageId: 'conditionErrorObject', - line: 4, - column: 27, - }, - { - messageId: 'conditionErrorObject', - line: 5, - column: 28, - }, - ], - code: ` - const obj = { x: 1 }; - const bool = false; - const objOrBool = obj || bool; - const objAndBool = obj && bool; + + // mixed `string | number` value in boolean context + ...batchedSingleLineTests({ + options: [{ allowString: true, allowNumber: true }], + code: noFormat` + declare const x: string | number; if (x) {} + (x: bigint | string) => !x; + (x: T) => x ? 1 : 0; `, - }, - { - options: [{ ignoreRhs: true }], errors: [ - { - messageId: 'conditionErrorOther', - line: 4, - column: 13, - }, - { - messageId: 'conditionErrorOther', - line: 6, - column: 13, - }, + { messageId: 'conditionErrorOther', line: 2, column: 39 }, + { messageId: 'conditionErrorOther', line: 3, column: 34 }, + { messageId: 'conditionErrorOther', line: 4, column: 55 }, ], - code: ` - const condition = () => false; - const obj = { x: 1 }; - if (condition() || obj) { - } - if (condition() && obj) { - } + }), + + // nullable boolean in boolean context + ...batchedSingleLineTests({ + options: [{ allowNullableBoolean: false }], + code: noFormat` + declare const x: boolean | null; if (x) {} + (x?: boolean) => !x; + (x: T) => x ? 1 : 0; `, - }, - { - options: [{ ignoreRhs: true }], errors: [ - { - messageId: 'conditionErrorOther', - line: 4, - column: 13, - }, - { - messageId: 'conditionErrorOther', - line: 6, - column: 13, - }, + { messageId: 'conditionErrorNullableBoolean', line: 2, column: 38 }, + { messageId: 'conditionErrorNullableBoolean', line: 3, column: 27 }, + { messageId: 'conditionErrorNullableBoolean', line: 4, column: 57 }, ], - code: ` - declare let condition: boolean; - const obj = { x: 1 }; - if (condition || obj) { - } - if (condition && obj) { - } + }), + + // nullable object in boolean context + ...batchedSingleLineTests({ + options: [{ allowNullableObject: false }], + code: noFormat` + declare const x: object | null; if (x) {} + (x?: { a: number }) => !x; + (x: T) => x ? 1 : 0; `, - }, - ...batchedSingleLineTests({ - options: [{ allowNullable: true }], errors: [ - { - messageId: 'conditionErrorNullish', - line: 2, - column: 38, - }, - { - messageId: 'conditionErrorNullableNumber', - line: 3, - column: 37, - }, - { - messageId: 'conditionErrorNullableString', - line: 4, - column: 37, - }, - { - messageId: 'conditionErrorOther', - line: 5, - column: 46, - }, + { messageId: 'conditionErrorNullableObject', line: 2, column: 37 }, + { messageId: 'conditionErrorNullableObject', line: 3, column: 33 }, + { messageId: 'conditionErrorNullableObject', line: 4, column: 52 }, ], - code: ` - const f1 = (x: null | undefined) => (x ? 1 : 0); - const f2 = (x?: number) => (x ? 1 : 0); - const f3 = (x?: string) => (x ? 1 : 0); - const f4 = (x?: string | number) => (x ? 1 : 0); - `, }), - { - errors: [ - { - messageId: 'conditionErrorOther', - line: 3, - column: 44, - }, - { - messageId: 'conditionErrorOther', - line: 4, - column: 45, - }, - ], - code: ` - type Type = { a: string }; - const f1 = (x: Type | boolean) => (x ? 1 : 0); - const f2 = (x?: Type | boolean) => (x ? 1 : 0); + + // nullable string in boolean context + ...batchedSingleLineTests({ + code: noFormat` + declare const x: string | null; if (x) {} + (x?: string) => !x; + (x: T) => x ? 1 : 0; `, - }, - ...batchedSingleLineTests({ - options: [{ allowSafe: true }], errors: [ - { - messageId: 'conditionErrorOther', - line: 2, - column: 37, - }, - { - messageId: 'conditionErrorOther', - line: 3, - column: 45, - }, - { - messageId: 'conditionErrorOther', - line: 4, - column: 45, - }, + { messageId: 'conditionErrorNullableString', line: 2, column: 37 }, + { messageId: 'conditionErrorNullableString', line: 3, column: 26 }, + { messageId: 'conditionErrorNullableString', line: 4, column: 56 }, ], - code: ` - const f1 = (x: object | string) => (x ? 1 : 0); - const f2 = (x: object | number) => (x ? 1 : 0); - const f3 = (x: number | string) => (x ? 1 : 0); - `, }), - { - options: [{ allowSafe: true }], - errors: [ - { - messageId: 'conditionErrorNumber', - line: 12, - column: 35, - }, - { - messageId: 'conditionErrorString', - line: 13, - column: 35, - }, - ], - code: ` - enum Enum1 { - A, - B, - C, - } - enum Enum2 { - A = 'A', - B = 'B', - C = 'C', - } - const f1 = (x: Enum1) => (x ? 1 : 0); - const f2 = (x: Enum2) => (x ? 1 : 0); + + // nullable number in boolean context + ...batchedSingleLineTests({ + code: noFormat` + declare const x: number | null; if (x) {} + (x?: number) => !x; + (x: T) => x ? 1 : 0; `, - }, - { - options: [{ allowNullable: true, allowSafe: true }], errors: [ - { - messageId: 'conditionErrorOther', - line: 3, - column: 44, - }, - { - messageId: 'conditionErrorOther', - line: 4, - column: 50, - }, + { messageId: 'conditionErrorNullableNumber', line: 2, column: 37 }, + { messageId: 'conditionErrorNullableNumber', line: 3, column: 26 }, + { messageId: 'conditionErrorNullableNumber', line: 4, column: 56 }, ], - code: ` - type Type = { a: string }; - const f1 = (x?: Type | string) => (x ? 1 : 0); - const f2 = (x: Type | number | null) => (x ? 1 : 0); + }), + + // any in boolean context + // TODO: when `T` is not `extends any` then the error is `conditionErrorObject` (says it's always truthy, which is false) + ...batchedSingleLineTests({ + code: noFormat` + if (x) {} + x => !x; + (x: T) => x ? 1 : 0; `, - }, - ...batchedSingleLineTests({ errors: [ - { - messageId: 'conditionErrorObject', - line: 2, - column: 32, - }, - { - messageId: 'conditionErrorNullableObject', - line: 3, - column: 41, - }, - { - messageId: 'conditionErrorNullableObject', - line: 4, - column: 48, - }, + { messageId: 'conditionErrorAny', line: 2, column: 5 }, + { messageId: 'conditionErrorAny', line: 3, column: 15 }, + { messageId: 'conditionErrorAny', line: 4, column: 34 }, ], - code: ` - const f1 = (x: { x: any }) => (x ? 1 : 0); - const f2 = (x?: { x: any }) => (x ? 1 : 0); - const f3 = (x?: { x: any } | null) => (x ? 1 : 0); - `, }), ], }); From 0126b4f56f9197d561e90b09962ccceb4f88bc41 Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Sun, 10 May 2020 12:14:50 -0700 Subject: [PATCH 17/33] feat(eslint-plugin): update recommended sets (#2001) --- .cspell.json | 1 + .eslintrc.js | 39 +++--- docs/getting-started/linting/README.md | 2 - packages/eslint-plugin/README.md | 42 +++--- packages/eslint-plugin/src/configs/all.json | 126 ------------------ packages/eslint-plugin/src/configs/all.ts | 126 ++++++++++++++++++ packages/eslint-plugin/src/configs/base.json | 5 - packages/eslint-plugin/src/configs/base.ts | 5 + .../src/configs/eslint-recommended.ts | 12 +- .../recommended-requiring-type-checking.json | 19 --- .../recommended-requiring-type-checking.ts | 21 +++ .../src/configs/recommended.json | 38 ------ .../eslint-plugin/src/configs/recommended.ts | 30 +++++ packages/eslint-plugin/src/index.ts | 8 +- .../eslint-plugin/src/rules/ban-ts-comment.ts | 2 +- .../eslint-plugin/src/rules/ban-ts-ignore.ts | 2 +- packages/eslint-plugin/src/rules/camelcase.ts | 2 +- .../src/rules/class-name-casing.ts | 2 +- .../src/rules/consistent-type-assertions.ts | 2 +- .../rules/explicit-function-return-type.ts | 2 +- .../rules/explicit-module-boundary-types.ts | 2 +- .../src/rules/interface-name-prefix.ts | 4 +- .../src/rules/member-delimiter-style.ts | 2 +- .../src/rules/naming-convention.ts | 5 - .../src/rules/no-extra-non-null-assertion.ts | 2 +- .../eslint-plugin/src/rules/no-extra-semi.ts | 2 +- .../src/rules/no-floating-promises.ts | 2 +- .../src/rules/no-implied-eval.ts | 2 +- .../no-non-null-asserted-optional-chain.ts | 2 +- .../src/rules/no-unsafe-assignment.ts | 2 +- .../eslint-plugin/src/rules/no-unsafe-call.ts | 2 +- .../src/rules/no-unsafe-member-access.ts | 2 +- .../src/rules/no-unsafe-return.ts | 2 +- .../src/rules/no-use-before-define.ts | 2 +- .../src/rules/prefer-as-const.ts | 2 +- .../src/rules/prefer-includes.ts | 2 +- .../rules/prefer-string-starts-ends-with.ts | 3 +- .../src/rules/restrict-plus-operands.ts | 2 +- .../rules/restrict-template-expressions.ts | 2 +- .../src/rules/type-annotation-spacing.ts | 2 +- .../tests/rules/naming-convention.test.ts | 1 - .../eslint-plugin/tools/generate-configs.ts | 39 ++---- tools/generate-contributors.ts | 2 +- 43 files changed, 277 insertions(+), 297 deletions(-) delete mode 100644 packages/eslint-plugin/src/configs/all.json create mode 100644 packages/eslint-plugin/src/configs/all.ts delete mode 100644 packages/eslint-plugin/src/configs/base.json create mode 100644 packages/eslint-plugin/src/configs/base.ts delete mode 100644 packages/eslint-plugin/src/configs/recommended-requiring-type-checking.json create mode 100644 packages/eslint-plugin/src/configs/recommended-requiring-type-checking.ts delete mode 100644 packages/eslint-plugin/src/configs/recommended.json create mode 100644 packages/eslint-plugin/src/configs/recommended.ts diff --git a/.cspell.json b/.cspell.json index 9df7d65a1b56..86a9b7af4f9c 100644 --- a/.cspell.json +++ b/.cspell.json @@ -80,6 +80,7 @@ "rulesets", "superset", "thenables", + "transpiles", "tsconfigs", "tsutils", "typedef", diff --git a/.eslintrc.js b/.eslintrc.js index 7760aa89ea10..4974d31f8c9b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -14,10 +14,14 @@ module.exports = { }, extends: [ 'eslint:recommended', - 'plugin:@typescript-eslint/eslint-recommended', 'plugin:@typescript-eslint/recommended', 'plugin:@typescript-eslint/recommended-requiring-type-checking', ], + parserOptions: { + sourceType: 'module', + project: ['./tsconfig.eslint.json', './packages/*/tsconfig.json'], + tsconfigRootDir: __dirname, + }, rules: { // // our plugin :D @@ -25,21 +29,28 @@ module.exports = { '@typescript-eslint/consistent-type-definitions': ['error', 'interface'], '@typescript-eslint/explicit-function-return-type': 'error', + '@typescript-eslint/explicit-module-boundary-types': 'off', + '@typescript-eslint/no-empty-function': [ + 'error', + { allow: ['arrowFunctions'] }, + ], '@typescript-eslint/no-explicit-any': 'error', '@typescript-eslint/no-non-null-assertion': 'off', - '@typescript-eslint/no-throw-literal': 'off', - '@typescript-eslint/no-use-before-define': 'off', '@typescript-eslint/no-var-requires': 'off', '@typescript-eslint/prefer-nullish-coalescing': 'error', '@typescript-eslint/prefer-optional-chain': 'error', '@typescript-eslint/unbound-method': 'off', - '@typescript-eslint/prefer-as-const': 'error', - 'no-empty-function': 'off', - '@typescript-eslint/no-empty-function': [ - 'error', - { allow: ['arrowFunctions'] }, - ], + // TODO - enable these new recommended rules + '@typescript-eslint/no-floating-promises': 'off', + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/no-unsafe-return': 'off', + '@typescript-eslint/restrict-plus-operands': 'off', + '@typescript-eslint/restrict-template-expressions': 'off', + // TODO - enable this + '@typescript-eslint/naming-convention': 'off', // // Internal repo rules @@ -53,8 +64,6 @@ module.exports = { // eslint base // - 'comma-dangle': ['error', 'always-multiline'], - 'constructor-super': 'off', curly: ['error', 'all'], 'no-mixed-operators': 'error', 'no-console': 'error', @@ -128,14 +137,6 @@ module.exports = { // Require modules with a single export to use a default export 'import/prefer-default-export': 'off', // we want everything to be named }, - parserOptions: { - sourceType: 'module', - ecmaFeatures: { - jsx: false, - }, - project: ['./tsconfig.eslint.json', './packages/*/tsconfig.json'], - tsconfigRootDir: __dirname, - }, overrides: [ // all test files { diff --git a/docs/getting-started/linting/README.md b/docs/getting-started/linting/README.md index 7936b96f2379..bb1fd058e89b 100644 --- a/docs/getting-started/linting/README.md +++ b/docs/getting-started/linting/README.md @@ -24,7 +24,6 @@ module.exports = { ], extends: [ 'eslint:recommended', - 'plugin:@typescript-eslint/eslint-recommended', 'plugin:@typescript-eslint/recommended', ], }; @@ -41,7 +40,6 @@ Explaining the important bits: - This allows you to use the rules within your codebase. - `extends: [ ... ]` tells ESLint that your config extends the given configurations. - `eslint:recommended` is ESLint's inbuilt "recommended" config - it turns on a small, sensible set of rules which lint for well-known best-practices. - - `plugin:@typescript-eslint/eslint-recommended` is a configuration we provide which disables a few of the recommended rules from the previous set that we know are already covered by TypeScript's typechecker. - `plugin:@typescript-eslint/recommended` is our "recommended" config - it's just like `eslint:recommended`, except it only turns on rules from our TypeScript-specific plugin. Further reading: diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md index c57d8d09cd62..fe165f2bc9fc 100644 --- a/packages/eslint-plugin/README.md +++ b/packages/eslint-plugin/README.md @@ -97,15 +97,15 @@ Pro Tip: For larger codebases you may want to consider splitting our linting int | [`@typescript-eslint/adjacent-overload-signatures`](./docs/rules/adjacent-overload-signatures.md) | Require that member overloads be consecutive | :heavy_check_mark: | | | | [`@typescript-eslint/array-type`](./docs/rules/array-type.md) | Requires using either `T[]` or `Array` for arrays | | :wrench: | | | [`@typescript-eslint/await-thenable`](./docs/rules/await-thenable.md) | Disallows awaiting a value that is not a Thenable | :heavy_check_mark: | | :thought_balloon: | -| [`@typescript-eslint/ban-ts-comment`](./docs/rules/ban-ts-comment.md) | Bans `// @ts-` comments from being used | | | | +| [`@typescript-eslint/ban-ts-comment`](./docs/rules/ban-ts-comment.md) | Bans `// @ts-` comments from being used | :heavy_check_mark: | | | | [`@typescript-eslint/ban-types`](./docs/rules/ban-types.md) | Bans specific types from being used | :heavy_check_mark: | :wrench: | | | [`@typescript-eslint/class-literal-property-style`](./docs/rules/class-literal-property-style.md) | Ensures that literals on classes are exposed in a consistent style | | :wrench: | | -| [`@typescript-eslint/consistent-type-assertions`](./docs/rules/consistent-type-assertions.md) | Enforces consistent usage of type assertions | :heavy_check_mark: | | | +| [`@typescript-eslint/consistent-type-assertions`](./docs/rules/consistent-type-assertions.md) | Enforces consistent usage of type assertions | | | | | [`@typescript-eslint/consistent-type-definitions`](./docs/rules/consistent-type-definitions.md) | Consistent with type definition either `interface` or `type` | | :wrench: | | -| [`@typescript-eslint/explicit-function-return-type`](./docs/rules/explicit-function-return-type.md) | Require explicit return types on functions and class methods | :heavy_check_mark: | | | +| [`@typescript-eslint/explicit-function-return-type`](./docs/rules/explicit-function-return-type.md) | Require explicit return types on functions and class methods | | | | | [`@typescript-eslint/explicit-member-accessibility`](./docs/rules/explicit-member-accessibility.md) | Require explicit accessibility modifiers on class properties and methods | | :wrench: | | -| [`@typescript-eslint/explicit-module-boundary-types`](./docs/rules/explicit-module-boundary-types.md) | Require explicit return and argument types on exported functions' and classes' public class methods | | | | -| [`@typescript-eslint/member-delimiter-style`](./docs/rules/member-delimiter-style.md) | Require a specific member delimiter style for interfaces and type literals | :heavy_check_mark: | :wrench: | | +| [`@typescript-eslint/explicit-module-boundary-types`](./docs/rules/explicit-module-boundary-types.md) | Require explicit return and argument types on exported functions' and classes' public class methods | :heavy_check_mark: | | | +| [`@typescript-eslint/member-delimiter-style`](./docs/rules/member-delimiter-style.md) | Require a specific member delimiter style for interfaces and type literals | | :wrench: | | | [`@typescript-eslint/member-ordering`](./docs/rules/member-ordering.md) | Require a consistent member declaration order | | | | | [`@typescript-eslint/method-signature-style`](./docs/rules/method-signature-style.md) | Enforces using a particular method signature syntax. | | :wrench: | | | [`@typescript-eslint/naming-convention`](./docs/rules/naming-convention.md) | Enforces naming conventions for everything across a codebase | | | :thought_balloon: | @@ -113,17 +113,17 @@ Pro Tip: For larger codebases you may want to consider splitting our linting int | [`@typescript-eslint/no-dynamic-delete`](./docs/rules/no-dynamic-delete.md) | Disallow the delete operator with computed key expressions | | :wrench: | | | [`@typescript-eslint/no-empty-interface`](./docs/rules/no-empty-interface.md) | Disallow the declaration of empty interfaces | :heavy_check_mark: | :wrench: | | | [`@typescript-eslint/no-explicit-any`](./docs/rules/no-explicit-any.md) | Disallow usage of the `any` type | :heavy_check_mark: | :wrench: | | -| [`@typescript-eslint/no-extra-non-null-assertion`](./docs/rules/no-extra-non-null-assertion.md) | Disallow extra non-null assertion | | :wrench: | | +| [`@typescript-eslint/no-extra-non-null-assertion`](./docs/rules/no-extra-non-null-assertion.md) | Disallow extra non-null assertion | :heavy_check_mark: | :wrench: | | | [`@typescript-eslint/no-extraneous-class`](./docs/rules/no-extraneous-class.md) | Forbids the use of classes as namespaces | | | | -| [`@typescript-eslint/no-floating-promises`](./docs/rules/no-floating-promises.md) | Requires Promise-like values to be handled appropriately | | | :thought_balloon: | +| [`@typescript-eslint/no-floating-promises`](./docs/rules/no-floating-promises.md) | Requires Promise-like values to be handled appropriately | :heavy_check_mark: | | :thought_balloon: | | [`@typescript-eslint/no-for-in-array`](./docs/rules/no-for-in-array.md) | Disallow iterating over an array with a for-in loop | :heavy_check_mark: | | :thought_balloon: | -| [`@typescript-eslint/no-implied-eval`](./docs/rules/no-implied-eval.md) | Disallow the use of `eval()`-like methods | | | :thought_balloon: | +| [`@typescript-eslint/no-implied-eval`](./docs/rules/no-implied-eval.md) | Disallow the use of `eval()`-like methods | :heavy_check_mark: | | :thought_balloon: | | [`@typescript-eslint/no-inferrable-types`](./docs/rules/no-inferrable-types.md) | Disallows explicit type declarations for variables or parameters initialized to a number, string, or boolean | :heavy_check_mark: | :wrench: | | | [`@typescript-eslint/no-invalid-void-type`](./docs/rules/no-invalid-void-type.md) | Disallows usage of `void` type outside of generic or return types | | | | | [`@typescript-eslint/no-misused-new`](./docs/rules/no-misused-new.md) | Enforce valid definition of `new` and `constructor` | :heavy_check_mark: | | | | [`@typescript-eslint/no-misused-promises`](./docs/rules/no-misused-promises.md) | Avoid using promises in places not designed to handle them | :heavy_check_mark: | | :thought_balloon: | | [`@typescript-eslint/no-namespace`](./docs/rules/no-namespace.md) | Disallow the use of custom TypeScript modules and namespaces | :heavy_check_mark: | | | -| [`@typescript-eslint/no-non-null-asserted-optional-chain`](./docs/rules/no-non-null-asserted-optional-chain.md) | Disallows using a non-null assertion after an optional chain expression | | | | +| [`@typescript-eslint/no-non-null-asserted-optional-chain`](./docs/rules/no-non-null-asserted-optional-chain.md) | Disallows using a non-null assertion after an optional chain expression | :heavy_check_mark: | | | | [`@typescript-eslint/no-non-null-assertion`](./docs/rules/no-non-null-assertion.md) | Disallows non-null assertions using the `!` postfix operator | :heavy_check_mark: | | | | [`@typescript-eslint/no-parameter-properties`](./docs/rules/no-parameter-properties.md) | Disallow the use of parameter properties in class constructors | | | | | [`@typescript-eslint/no-require-imports`](./docs/rules/no-require-imports.md) | Disallows invocation of `require()` | | | | @@ -135,16 +135,16 @@ Pro Tip: For larger codebases you may want to consider splitting our linting int | [`@typescript-eslint/no-unnecessary-qualifier`](./docs/rules/no-unnecessary-qualifier.md) | Warns when a namespace qualifier is unnecessary | | :wrench: | :thought_balloon: | | [`@typescript-eslint/no-unnecessary-type-arguments`](./docs/rules/no-unnecessary-type-arguments.md) | Enforces that type arguments will not be used if not required | | :wrench: | :thought_balloon: | | [`@typescript-eslint/no-unnecessary-type-assertion`](./docs/rules/no-unnecessary-type-assertion.md) | Warns if a type assertion does not change the type of an expression | :heavy_check_mark: | :wrench: | :thought_balloon: | -| [`@typescript-eslint/no-unsafe-assignment`](./docs/rules/no-unsafe-assignment.md) | Disallows assigning any to variables and properties | | | :thought_balloon: | -| [`@typescript-eslint/no-unsafe-call`](./docs/rules/no-unsafe-call.md) | Disallows calling an any type value | | | :thought_balloon: | -| [`@typescript-eslint/no-unsafe-member-access`](./docs/rules/no-unsafe-member-access.md) | Disallows member access on any typed variables | | | :thought_balloon: | -| [`@typescript-eslint/no-unsafe-return`](./docs/rules/no-unsafe-return.md) | Disallows returning any from a function | | | :thought_balloon: | +| [`@typescript-eslint/no-unsafe-assignment`](./docs/rules/no-unsafe-assignment.md) | Disallows assigning any to variables and properties | :heavy_check_mark: | | :thought_balloon: | +| [`@typescript-eslint/no-unsafe-call`](./docs/rules/no-unsafe-call.md) | Disallows calling an any type value | :heavy_check_mark: | | :thought_balloon: | +| [`@typescript-eslint/no-unsafe-member-access`](./docs/rules/no-unsafe-member-access.md) | Disallows member access on any typed variables | :heavy_check_mark: | | :thought_balloon: | +| [`@typescript-eslint/no-unsafe-return`](./docs/rules/no-unsafe-return.md) | Disallows returning any from a function | :heavy_check_mark: | | :thought_balloon: | | [`@typescript-eslint/no-unused-vars-experimental`](./docs/rules/no-unused-vars-experimental.md) | Disallow unused variables and arguments | | | | | [`@typescript-eslint/no-var-requires`](./docs/rules/no-var-requires.md) | Disallows the use of require statements except in import statements | :heavy_check_mark: | | | -| [`@typescript-eslint/prefer-as-const`](./docs/rules/prefer-as-const.md) | Prefer usage of `as const` over literal type | | :wrench: | | +| [`@typescript-eslint/prefer-as-const`](./docs/rules/prefer-as-const.md) | Prefer usage of `as const` over literal type | :heavy_check_mark: | :wrench: | | | [`@typescript-eslint/prefer-for-of`](./docs/rules/prefer-for-of.md) | Prefer a ‘for-of’ loop over a standard ‘for’ loop if the index is only used to access the array being iterated | | | | | [`@typescript-eslint/prefer-function-type`](./docs/rules/prefer-function-type.md) | Use function types instead of interfaces with call signatures | | :wrench: | | -| [`@typescript-eslint/prefer-includes`](./docs/rules/prefer-includes.md) | Enforce `includes` method over `indexOf` method | :heavy_check_mark: | :wrench: | :thought_balloon: | +| [`@typescript-eslint/prefer-includes`](./docs/rules/prefer-includes.md) | Enforce `includes` method over `indexOf` method | | :wrench: | :thought_balloon: | | [`@typescript-eslint/prefer-namespace-keyword`](./docs/rules/prefer-namespace-keyword.md) | Require the use of the `namespace` keyword instead of the `module` keyword to declare custom TypeScript modules | :heavy_check_mark: | :wrench: | | | [`@typescript-eslint/prefer-nullish-coalescing`](./docs/rules/prefer-nullish-coalescing.md) | Enforce the usage of the nullish coalescing operator instead of logical chaining | | :wrench: | :thought_balloon: | | [`@typescript-eslint/prefer-optional-chain`](./docs/rules/prefer-optional-chain.md) | Prefer using concise optional chain expressions instead of chained logical ands | | :wrench: | | @@ -152,16 +152,16 @@ Pro Tip: For larger codebases you may want to consider splitting our linting int | [`@typescript-eslint/prefer-readonly-parameter-types`](./docs/rules/prefer-readonly-parameter-types.md) | Requires that function parameters are typed as readonly to prevent accidental mutation of inputs | | | :thought_balloon: | | [`@typescript-eslint/prefer-reduce-type-parameter`](./docs/rules/prefer-reduce-type-parameter.md) | Prefer using type parameter when calling `Array#reduce` instead of casting | | :wrench: | :thought_balloon: | | [`@typescript-eslint/prefer-regexp-exec`](./docs/rules/prefer-regexp-exec.md) | Enforce that `RegExp#exec` is used instead of `String#match` if no global flag is provided | :heavy_check_mark: | | :thought_balloon: | -| [`@typescript-eslint/prefer-string-starts-ends-with`](./docs/rules/prefer-string-starts-ends-with.md) | Enforce the use of `String#startsWith` and `String#endsWith` instead of other equivalent methods of checking substrings | :heavy_check_mark: | :wrench: | :thought_balloon: | +| [`@typescript-eslint/prefer-string-starts-ends-with`](./docs/rules/prefer-string-starts-ends-with.md) | Enforce the use of `String#startsWith` and `String#endsWith` instead of other equivalent methods of checking substrings | | :wrench: | :thought_balloon: | | [`@typescript-eslint/prefer-ts-expect-error`](./docs/rules/prefer-ts-expect-error.md) | Recommends using `// @ts-expect-error` over `// @ts-ignore` | | :wrench: | | | [`@typescript-eslint/promise-function-async`](./docs/rules/promise-function-async.md) | Requires any function or method that returns a Promise to be marked async | | | :thought_balloon: | | [`@typescript-eslint/require-array-sort-compare`](./docs/rules/require-array-sort-compare.md) | Requires `Array#sort` calls to always provide a `compareFunction` | | | :thought_balloon: | -| [`@typescript-eslint/restrict-plus-operands`](./docs/rules/restrict-plus-operands.md) | When adding two variables, operands must both be of type number or of type string | | | :thought_balloon: | -| [`@typescript-eslint/restrict-template-expressions`](./docs/rules/restrict-template-expressions.md) | Enforce template literal expressions to be of string type | | | :thought_balloon: | +| [`@typescript-eslint/restrict-plus-operands`](./docs/rules/restrict-plus-operands.md) | When adding two variables, operands must both be of type number or of type string | :heavy_check_mark: | | :thought_balloon: | +| [`@typescript-eslint/restrict-template-expressions`](./docs/rules/restrict-template-expressions.md) | Enforce template literal expressions to be of string type | :heavy_check_mark: | | :thought_balloon: | | [`@typescript-eslint/strict-boolean-expressions`](./docs/rules/strict-boolean-expressions.md) | Restricts the types allowed in boolean expressions | | | :thought_balloon: | | [`@typescript-eslint/switch-exhaustiveness-check`](./docs/rules/switch-exhaustiveness-check.md) | Exhaustiveness checking in switch with union type | | | :thought_balloon: | | [`@typescript-eslint/triple-slash-reference`](./docs/rules/triple-slash-reference.md) | Sets preference level for triple slash directives versus ES6-style import declarations | :heavy_check_mark: | | | -| [`@typescript-eslint/type-annotation-spacing`](./docs/rules/type-annotation-spacing.md) | Require consistent spacing around type annotations | :heavy_check_mark: | :wrench: | | +| [`@typescript-eslint/type-annotation-spacing`](./docs/rules/type-annotation-spacing.md) | Require consistent spacing around type annotations | | :wrench: | | | [`@typescript-eslint/typedef`](./docs/rules/typedef.md) | Requires type annotations to exist | | | | | [`@typescript-eslint/unbound-method`](./docs/rules/unbound-method.md) | Enforces unbound methods are called with their expected scope | :heavy_check_mark: | | :thought_balloon: | | [`@typescript-eslint/unified-signatures`](./docs/rules/unified-signatures.md) | Warns for any two overloads that could be unified into one by using a union or an optional/rest parameter | | | | @@ -192,12 +192,12 @@ In these cases, we create what we call an extension rule; a rule within our plug | [`@typescript-eslint/no-dupe-class-members`](./docs/rules/no-dupe-class-members.md) | Disallow duplicate class members | | | | | [`@typescript-eslint/no-empty-function`](./docs/rules/no-empty-function.md) | Disallow empty functions | :heavy_check_mark: | | | | [`@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 | | :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-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: | | | -| [`@typescript-eslint/no-use-before-define`](./docs/rules/no-use-before-define.md) | Disallow the use of variables before they are defined | :heavy_check_mark: | | | +| [`@typescript-eslint/no-use-before-define`](./docs/rules/no-use-before-define.md) | Disallow the use of variables before they are defined | | | | | [`@typescript-eslint/no-useless-constructor`](./docs/rules/no-useless-constructor.md) | Disallow unnecessary constructors | | | | | [`@typescript-eslint/quotes`](./docs/rules/quotes.md) | Enforce the consistent use of either backticks, double, or single quotes | | :wrench: | | | [`@typescript-eslint/require-await`](./docs/rules/require-await.md) | Disallow async functions which have no `await` expression | :heavy_check_mark: | | :thought_balloon: | diff --git a/packages/eslint-plugin/src/configs/all.json b/packages/eslint-plugin/src/configs/all.json deleted file mode 100644 index 3182e67de26a..000000000000 --- a/packages/eslint-plugin/src/configs/all.json +++ /dev/null @@ -1,126 +0,0 @@ -{ - "extends": "./configs/base.json", - "rules": { - "@typescript-eslint/adjacent-overload-signatures": "error", - "@typescript-eslint/array-type": "error", - "@typescript-eslint/await-thenable": "error", - "@typescript-eslint/ban-ts-comment": "error", - "@typescript-eslint/ban-types": "error", - "brace-style": "off", - "@typescript-eslint/brace-style": "error", - "@typescript-eslint/class-literal-property-style": "error", - "comma-spacing": "off", - "@typescript-eslint/comma-spacing": "error", - "@typescript-eslint/consistent-type-assertions": "error", - "@typescript-eslint/consistent-type-definitions": "error", - "default-param-last": "off", - "@typescript-eslint/default-param-last": "error", - "dot-notation": "off", - "@typescript-eslint/dot-notation": "error", - "@typescript-eslint/explicit-function-return-type": "error", - "@typescript-eslint/explicit-member-accessibility": "error", - "@typescript-eslint/explicit-module-boundary-types": "error", - "func-call-spacing": "off", - "@typescript-eslint/func-call-spacing": "error", - "indent": "off", - "@typescript-eslint/indent": "error", - "lines-between-class-members": "off", - "@typescript-eslint/lines-between-class-members": "error", - "init-declarations": "off", - "@typescript-eslint/init-declarations": "error", - "keyword-spacing": "off", - "@typescript-eslint/keyword-spacing": "error", - "@typescript-eslint/member-delimiter-style": "error", - "@typescript-eslint/member-ordering": "error", - "@typescript-eslint/method-signature-style": "error", - "@typescript-eslint/naming-convention": "error", - "no-array-constructor": "off", - "@typescript-eslint/no-array-constructor": "error", - "@typescript-eslint/no-base-to-string": "error", - "no-dupe-class-members": "off", - "@typescript-eslint/no-dupe-class-members": "error", - "@typescript-eslint/no-dynamic-delete": "error", - "no-empty-function": "off", - "@typescript-eslint/no-empty-function": "error", - "@typescript-eslint/no-empty-interface": "error", - "@typescript-eslint/no-explicit-any": "error", - "@typescript-eslint/no-extra-non-null-assertion": "error", - "no-extra-parens": "off", - "@typescript-eslint/no-extra-parens": "error", - "no-extra-semi": "off", - "@typescript-eslint/no-extra-semi": "error", - "@typescript-eslint/no-extraneous-class": "error", - "@typescript-eslint/no-floating-promises": "error", - "@typescript-eslint/no-for-in-array": "error", - "@typescript-eslint/no-implied-eval": "error", - "@typescript-eslint/no-inferrable-types": "error", - "no-invalid-this": "off", - "@typescript-eslint/no-invalid-this": "error", - "@typescript-eslint/no-invalid-void-type": "error", - "no-magic-numbers": "off", - "@typescript-eslint/no-magic-numbers": "error", - "@typescript-eslint/no-misused-new": "error", - "@typescript-eslint/no-misused-promises": "error", - "@typescript-eslint/no-namespace": "error", - "@typescript-eslint/no-non-null-asserted-optional-chain": "error", - "@typescript-eslint/no-non-null-assertion": "error", - "@typescript-eslint/no-parameter-properties": "error", - "@typescript-eslint/no-require-imports": "error", - "@typescript-eslint/no-this-alias": "error", - "@typescript-eslint/no-throw-literal": "error", - "@typescript-eslint/no-type-alias": "error", - "@typescript-eslint/no-unnecessary-boolean-literal-compare": "error", - "@typescript-eslint/no-unnecessary-condition": "error", - "@typescript-eslint/no-unnecessary-qualifier": "error", - "@typescript-eslint/no-unnecessary-type-arguments": "error", - "@typescript-eslint/no-unnecessary-type-assertion": "error", - "@typescript-eslint/no-unsafe-assignment": "error", - "@typescript-eslint/no-unsafe-call": "error", - "@typescript-eslint/no-unsafe-member-access": "error", - "@typescript-eslint/no-unsafe-return": "error", - "no-unused-expressions": "off", - "@typescript-eslint/no-unused-expressions": "error", - "no-unused-vars": "off", - "@typescript-eslint/no-unused-vars": "error", - "@typescript-eslint/no-unused-vars-experimental": "error", - "no-use-before-define": "off", - "@typescript-eslint/no-use-before-define": "error", - "no-useless-constructor": "off", - "@typescript-eslint/no-useless-constructor": "error", - "@typescript-eslint/no-var-requires": "error", - "@typescript-eslint/prefer-as-const": "error", - "@typescript-eslint/prefer-for-of": "error", - "@typescript-eslint/prefer-function-type": "error", - "@typescript-eslint/prefer-includes": "error", - "@typescript-eslint/prefer-namespace-keyword": "error", - "@typescript-eslint/prefer-nullish-coalescing": "error", - "@typescript-eslint/prefer-optional-chain": "error", - "@typescript-eslint/prefer-readonly": "error", - "@typescript-eslint/prefer-readonly-parameter-types": "error", - "@typescript-eslint/prefer-reduce-type-parameter": "error", - "@typescript-eslint/prefer-regexp-exec": "error", - "@typescript-eslint/prefer-string-starts-ends-with": "error", - "@typescript-eslint/prefer-ts-expect-error": "error", - "@typescript-eslint/promise-function-async": "error", - "quotes": "off", - "@typescript-eslint/quotes": "error", - "@typescript-eslint/require-array-sort-compare": "error", - "require-await": "off", - "@typescript-eslint/require-await": "error", - "@typescript-eslint/restrict-plus-operands": "error", - "@typescript-eslint/restrict-template-expressions": "error", - "no-return-await": "off", - "@typescript-eslint/return-await": "error", - "semi": "off", - "@typescript-eslint/semi": "error", - "space-before-function-paren": "off", - "@typescript-eslint/space-before-function-paren": "error", - "@typescript-eslint/strict-boolean-expressions": "error", - "@typescript-eslint/switch-exhaustiveness-check": "error", - "@typescript-eslint/triple-slash-reference": "error", - "@typescript-eslint/type-annotation-spacing": "error", - "@typescript-eslint/typedef": "error", - "@typescript-eslint/unbound-method": "error", - "@typescript-eslint/unified-signatures": "error" - } -} diff --git a/packages/eslint-plugin/src/configs/all.ts b/packages/eslint-plugin/src/configs/all.ts new file mode 100644 index 000000000000..a02d6db9d696 --- /dev/null +++ b/packages/eslint-plugin/src/configs/all.ts @@ -0,0 +1,126 @@ +export = { + extends: ['./configs/base', './configs/eslint-recommended'], + rules: { + '@typescript-eslint/adjacent-overload-signatures': 'error', + '@typescript-eslint/array-type': 'error', + '@typescript-eslint/await-thenable': 'error', + '@typescript-eslint/ban-ts-comment': 'error', + '@typescript-eslint/ban-types': 'error', + 'brace-style': 'off', + '@typescript-eslint/brace-style': 'error', + '@typescript-eslint/class-literal-property-style': 'error', + 'comma-spacing': 'off', + '@typescript-eslint/comma-spacing': 'error', + '@typescript-eslint/consistent-type-assertions': 'error', + '@typescript-eslint/consistent-type-definitions': 'error', + 'default-param-last': 'off', + '@typescript-eslint/default-param-last': 'error', + 'dot-notation': 'off', + '@typescript-eslint/dot-notation': 'error', + '@typescript-eslint/explicit-function-return-type': 'error', + '@typescript-eslint/explicit-member-accessibility': 'error', + '@typescript-eslint/explicit-module-boundary-types': 'error', + 'func-call-spacing': 'off', + '@typescript-eslint/func-call-spacing': 'error', + indent: 'off', + '@typescript-eslint/indent': 'error', + 'init-declarations': 'off', + '@typescript-eslint/init-declarations': 'error', + 'keyword-spacing': 'off', + '@typescript-eslint/keyword-spacing': 'error', + 'lines-between-class-members': 'off', + '@typescript-eslint/lines-between-class-members': 'error', + '@typescript-eslint/member-delimiter-style': 'error', + '@typescript-eslint/member-ordering': 'error', + '@typescript-eslint/method-signature-style': 'error', + '@typescript-eslint/naming-convention': 'error', + 'no-array-constructor': 'off', + '@typescript-eslint/no-array-constructor': 'error', + '@typescript-eslint/no-base-to-string': 'error', + 'no-dupe-class-members': 'off', + '@typescript-eslint/no-dupe-class-members': 'error', + '@typescript-eslint/no-dynamic-delete': 'error', + 'no-empty-function': 'off', + '@typescript-eslint/no-empty-function': 'error', + '@typescript-eslint/no-empty-interface': 'error', + '@typescript-eslint/no-explicit-any': 'error', + '@typescript-eslint/no-extra-non-null-assertion': 'error', + 'no-extra-parens': 'off', + '@typescript-eslint/no-extra-parens': 'error', + 'no-extra-semi': 'off', + '@typescript-eslint/no-extra-semi': 'error', + '@typescript-eslint/no-extraneous-class': 'error', + '@typescript-eslint/no-floating-promises': 'error', + '@typescript-eslint/no-for-in-array': 'error', + '@typescript-eslint/no-implied-eval': 'error', + '@typescript-eslint/no-inferrable-types': 'error', + 'no-invalid-this': 'off', + '@typescript-eslint/no-invalid-this': 'error', + '@typescript-eslint/no-invalid-void-type': 'error', + 'no-magic-numbers': 'off', + '@typescript-eslint/no-magic-numbers': 'error', + '@typescript-eslint/no-misused-new': 'error', + '@typescript-eslint/no-misused-promises': 'error', + '@typescript-eslint/no-namespace': 'error', + '@typescript-eslint/no-non-null-asserted-optional-chain': 'error', + '@typescript-eslint/no-non-null-assertion': 'error', + '@typescript-eslint/no-parameter-properties': 'error', + '@typescript-eslint/no-require-imports': 'error', + '@typescript-eslint/no-this-alias': 'error', + '@typescript-eslint/no-throw-literal': 'error', + '@typescript-eslint/no-type-alias': 'error', + '@typescript-eslint/no-unnecessary-boolean-literal-compare': 'error', + '@typescript-eslint/no-unnecessary-condition': 'error', + '@typescript-eslint/no-unnecessary-qualifier': 'error', + '@typescript-eslint/no-unnecessary-type-arguments': 'error', + '@typescript-eslint/no-unnecessary-type-assertion': 'error', + '@typescript-eslint/no-unsafe-assignment': 'error', + '@typescript-eslint/no-unsafe-call': 'error', + '@typescript-eslint/no-unsafe-member-access': 'error', + '@typescript-eslint/no-unsafe-return': 'error', + 'no-unused-expressions': 'off', + '@typescript-eslint/no-unused-expressions': 'error', + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': 'error', + '@typescript-eslint/no-unused-vars-experimental': 'error', + 'no-use-before-define': 'off', + '@typescript-eslint/no-use-before-define': 'error', + 'no-useless-constructor': 'off', + '@typescript-eslint/no-useless-constructor': 'error', + '@typescript-eslint/no-var-requires': 'error', + '@typescript-eslint/prefer-as-const': 'error', + '@typescript-eslint/prefer-for-of': 'error', + '@typescript-eslint/prefer-function-type': 'error', + '@typescript-eslint/prefer-includes': 'error', + '@typescript-eslint/prefer-namespace-keyword': 'error', + '@typescript-eslint/prefer-nullish-coalescing': 'error', + '@typescript-eslint/prefer-optional-chain': 'error', + '@typescript-eslint/prefer-readonly': 'error', + '@typescript-eslint/prefer-readonly-parameter-types': 'error', + '@typescript-eslint/prefer-reduce-type-parameter': 'error', + '@typescript-eslint/prefer-regexp-exec': 'error', + '@typescript-eslint/prefer-string-starts-ends-with': 'error', + '@typescript-eslint/prefer-ts-expect-error': 'error', + '@typescript-eslint/promise-function-async': 'error', + quotes: 'off', + '@typescript-eslint/quotes': 'error', + '@typescript-eslint/require-array-sort-compare': 'error', + 'require-await': 'off', + '@typescript-eslint/require-await': 'error', + '@typescript-eslint/restrict-plus-operands': 'error', + '@typescript-eslint/restrict-template-expressions': 'error', + 'no-return-await': 'off', + '@typescript-eslint/return-await': 'error', + semi: 'off', + '@typescript-eslint/semi': 'error', + 'space-before-function-paren': 'off', + '@typescript-eslint/space-before-function-paren': 'error', + '@typescript-eslint/strict-boolean-expressions': 'error', + '@typescript-eslint/switch-exhaustiveness-check': 'error', + '@typescript-eslint/triple-slash-reference': 'error', + '@typescript-eslint/type-annotation-spacing': 'error', + '@typescript-eslint/typedef': 'error', + '@typescript-eslint/unbound-method': 'error', + '@typescript-eslint/unified-signatures': 'error', + }, +}; diff --git a/packages/eslint-plugin/src/configs/base.json b/packages/eslint-plugin/src/configs/base.json deleted file mode 100644 index 9580ed622cfc..000000000000 --- a/packages/eslint-plugin/src/configs/base.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "parser": "@typescript-eslint/parser", - "parserOptions": { "sourceType": "module" }, - "plugins": ["@typescript-eslint"] -} diff --git a/packages/eslint-plugin/src/configs/base.ts b/packages/eslint-plugin/src/configs/base.ts new file mode 100644 index 000000000000..652bf9db1eea --- /dev/null +++ b/packages/eslint-plugin/src/configs/base.ts @@ -0,0 +1,5 @@ +export = { + parser: '@typescript-eslint/parser', + parserOptions: { sourceType: 'module' }, + plugins: ['@typescript-eslint'], +}; diff --git a/packages/eslint-plugin/src/configs/eslint-recommended.ts b/packages/eslint-plugin/src/configs/eslint-recommended.ts index 4999a528bdf8..125c093b2bc2 100644 --- a/packages/eslint-plugin/src/configs/eslint-recommended.ts +++ b/packages/eslint-plugin/src/configs/eslint-recommended.ts @@ -1,8 +1,9 @@ /** - * This is a compatibility ruleset that disables rules from eslint:recommended - * which are already handled by TypeScript. + * This is a compatibility ruleset that: + * - disables rules from eslint:recommended which are already handled by TypeScript. + * - enables rules that make sense due to TS's typechecking / transpilation. */ -export default { +export = { overrides: [ { files: ['*.ts', '*.tsx'], @@ -14,6 +15,7 @@ export default { 'no-dupe-class-members': 'off', // ts(2393) & ts(2300) 'no-dupe-keys': 'off', // ts(1117) 'no-func-assign': 'off', // ts(2539) + 'no-import-assign': 'off', // ts(2539) & ts(2540) 'no-new-symbol': 'off', // ts(2588) 'no-obj-calls': 'off', // ts(2349) 'no-redeclare': 'off', // ts(2451) @@ -22,6 +24,10 @@ export default { 'no-undef': 'off', // ts(2304) 'no-unreachable': 'off', // ts(7027) 'no-unsafe-negation': 'off', // ts(2365) & ts(2360) & ts(2358) + 'no-var': 'error', // ts transpiles let/const to var, so no need for vars any more + 'prefer-const': 'error', // ts provides better types with const + 'prefer-rest-params': 'error', // ts provides better types with rest args over arguments + 'prefer-spread': 'error', // ts transpiles spread to apply, so no need for manual apply 'valid-typeof': 'off', // ts(2367) }, }, diff --git a/packages/eslint-plugin/src/configs/recommended-requiring-type-checking.json b/packages/eslint-plugin/src/configs/recommended-requiring-type-checking.json deleted file mode 100644 index 68867b532483..000000000000 --- a/packages/eslint-plugin/src/configs/recommended-requiring-type-checking.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "extends": "./configs/base.json", - "rules": { - "@typescript-eslint/await-thenable": "error", - "@typescript-eslint/no-for-in-array": "error", - "@typescript-eslint/no-misused-promises": "error", - "@typescript-eslint/no-unnecessary-type-assertion": "error", - "@typescript-eslint/prefer-includes": "error", - "@typescript-eslint/prefer-regexp-exec": "error", - "@typescript-eslint/prefer-string-starts-ends-with": "error", - "require-await": "off", - "@typescript-eslint/require-await": "error", - "@typescript-eslint/unbound-method": "error", - "no-var": "error", - "prefer-const": "error", - "prefer-rest-params": "error", - "prefer-spread": "error" - } -} diff --git a/packages/eslint-plugin/src/configs/recommended-requiring-type-checking.ts b/packages/eslint-plugin/src/configs/recommended-requiring-type-checking.ts new file mode 100644 index 000000000000..57e29f3e401c --- /dev/null +++ b/packages/eslint-plugin/src/configs/recommended-requiring-type-checking.ts @@ -0,0 +1,21 @@ +export = { + extends: ['./configs/base', './configs/eslint-recommended'], + rules: { + '@typescript-eslint/await-thenable': 'error', + '@typescript-eslint/no-floating-promises': 'error', + '@typescript-eslint/no-for-in-array': 'error', + '@typescript-eslint/no-implied-eval': 'error', + '@typescript-eslint/no-misused-promises': 'error', + '@typescript-eslint/no-unnecessary-type-assertion': 'error', + '@typescript-eslint/no-unsafe-assignment': 'error', + '@typescript-eslint/no-unsafe-call': 'error', + '@typescript-eslint/no-unsafe-member-access': 'error', + '@typescript-eslint/no-unsafe-return': 'error', + '@typescript-eslint/prefer-regexp-exec': 'error', + 'require-await': 'off', + '@typescript-eslint/require-await': 'error', + '@typescript-eslint/restrict-plus-operands': 'error', + '@typescript-eslint/restrict-template-expressions': 'error', + '@typescript-eslint/unbound-method': 'error', + }, +}; diff --git a/packages/eslint-plugin/src/configs/recommended.json b/packages/eslint-plugin/src/configs/recommended.json deleted file mode 100644 index 7d7a5628c9d8..000000000000 --- a/packages/eslint-plugin/src/configs/recommended.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "extends": "./configs/base.json", - "rules": { - "@typescript-eslint/adjacent-overload-signatures": "error", - "@typescript-eslint/ban-ts-ignore": "error", - "@typescript-eslint/ban-types": "error", - "camelcase": "off", - "@typescript-eslint/camelcase": "error", - "@typescript-eslint/class-name-casing": "error", - "@typescript-eslint/consistent-type-assertions": "error", - "@typescript-eslint/explicit-function-return-type": "warn", - "@typescript-eslint/interface-name-prefix": "error", - "@typescript-eslint/member-delimiter-style": "error", - "no-array-constructor": "off", - "@typescript-eslint/no-array-constructor": "error", - "no-empty-function": "off", - "@typescript-eslint/no-empty-function": "error", - "@typescript-eslint/no-empty-interface": "error", - "@typescript-eslint/no-explicit-any": "warn", - "@typescript-eslint/no-inferrable-types": "error", - "@typescript-eslint/no-misused-new": "error", - "@typescript-eslint/no-namespace": "error", - "@typescript-eslint/no-non-null-assertion": "warn", - "@typescript-eslint/no-this-alias": "error", - "no-unused-vars": "off", - "@typescript-eslint/no-unused-vars": "warn", - "no-use-before-define": "off", - "@typescript-eslint/no-use-before-define": "error", - "@typescript-eslint/no-var-requires": "error", - "@typescript-eslint/prefer-namespace-keyword": "error", - "@typescript-eslint/triple-slash-reference": "error", - "@typescript-eslint/type-annotation-spacing": "error", - "no-var": "error", - "prefer-const": "error", - "prefer-rest-params": "error", - "prefer-spread": "error" - } -} diff --git a/packages/eslint-plugin/src/configs/recommended.ts b/packages/eslint-plugin/src/configs/recommended.ts new file mode 100644 index 000000000000..8aac1a8a3b01 --- /dev/null +++ b/packages/eslint-plugin/src/configs/recommended.ts @@ -0,0 +1,30 @@ +export = { + extends: ['./configs/base', './configs/eslint-recommended'], + rules: { + '@typescript-eslint/adjacent-overload-signatures': 'error', + '@typescript-eslint/ban-ts-comment': 'error', + '@typescript-eslint/ban-types': 'error', + '@typescript-eslint/explicit-module-boundary-types': 'warn', + 'no-array-constructor': 'off', + '@typescript-eslint/no-array-constructor': 'error', + 'no-empty-function': 'off', + '@typescript-eslint/no-empty-function': 'error', + '@typescript-eslint/no-empty-interface': 'error', + '@typescript-eslint/no-explicit-any': 'warn', + '@typescript-eslint/no-extra-non-null-assertion': 'error', + 'no-extra-semi': 'off', + '@typescript-eslint/no-extra-semi': 'error', + '@typescript-eslint/no-inferrable-types': 'error', + '@typescript-eslint/no-misused-new': 'error', + '@typescript-eslint/no-namespace': 'error', + '@typescript-eslint/no-non-null-asserted-optional-chain': 'error', + '@typescript-eslint/no-non-null-assertion': 'warn', + '@typescript-eslint/no-this-alias': 'error', + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': 'warn', + '@typescript-eslint/no-var-requires': 'error', + '@typescript-eslint/prefer-as-const': 'error', + '@typescript-eslint/prefer-namespace-keyword': 'error', + '@typescript-eslint/triple-slash-reference': 'error', + }, +}; diff --git a/packages/eslint-plugin/src/index.ts b/packages/eslint-plugin/src/index.ts index d8e55844e1d3..a812b44eb7a4 100644 --- a/packages/eslint-plugin/src/index.ts +++ b/packages/eslint-plugin/src/index.ts @@ -1,9 +1,9 @@ import rules from './rules'; -import all from './configs/all.json'; -import base from './configs/base.json'; -import recommended from './configs/recommended.json'; -import recommendedRequiringTypeChecking from './configs/recommended-requiring-type-checking.json'; +import all from './configs/all'; +import base from './configs/base'; +import recommended from './configs/recommended'; +import recommendedRequiringTypeChecking from './configs/recommended-requiring-type-checking'; import eslintRecommended from './configs/eslint-recommended'; export = { diff --git a/packages/eslint-plugin/src/rules/ban-ts-comment.ts b/packages/eslint-plugin/src/rules/ban-ts-comment.ts index a422349eefaa..bcbc02e9a0a1 100644 --- a/packages/eslint-plugin/src/rules/ban-ts-comment.ts +++ b/packages/eslint-plugin/src/rules/ban-ts-comment.ts @@ -26,7 +26,7 @@ export default util.createRule<[Options], MessageIds>({ docs: { description: 'Bans `// @ts-` comments from being used', category: 'Best Practices', - recommended: false, + recommended: 'error', }, messages: { tsDirectiveComment: diff --git a/packages/eslint-plugin/src/rules/ban-ts-ignore.ts b/packages/eslint-plugin/src/rules/ban-ts-ignore.ts index 551bb0401a97..bbeadfe5269d 100644 --- a/packages/eslint-plugin/src/rules/ban-ts-ignore.ts +++ b/packages/eslint-plugin/src/rules/ban-ts-ignore.ts @@ -8,7 +8,7 @@ export default util.createRule({ docs: { description: 'Bans “// @ts-ignore” comments from being used', category: 'Best Practices', - recommended: 'error', + recommended: false, }, schema: [], messages: { diff --git a/packages/eslint-plugin/src/rules/camelcase.ts b/packages/eslint-plugin/src/rules/camelcase.ts index 0c3ba619a42f..7d8c179f2b9d 100644 --- a/packages/eslint-plugin/src/rules/camelcase.ts +++ b/packages/eslint-plugin/src/rules/camelcase.ts @@ -28,7 +28,7 @@ export default util.createRule({ docs: { description: 'Enforce camelCase naming convention', category: 'Stylistic Issues', - recommended: 'error', + recommended: false, extendsBaseRule: true, }, deprecated: true, diff --git a/packages/eslint-plugin/src/rules/class-name-casing.ts b/packages/eslint-plugin/src/rules/class-name-casing.ts index 6326f1910e18..5871f47db92b 100644 --- a/packages/eslint-plugin/src/rules/class-name-casing.ts +++ b/packages/eslint-plugin/src/rules/class-name-casing.ts @@ -18,7 +18,7 @@ export default util.createRule({ docs: { description: 'Require PascalCased class and interface names', category: 'Best Practices', - recommended: 'error', + recommended: false, }, deprecated: true, replacedBy: ['naming-convention'], diff --git a/packages/eslint-plugin/src/rules/consistent-type-assertions.ts b/packages/eslint-plugin/src/rules/consistent-type-assertions.ts index 2457bdb08a97..cc96778cbe06 100644 --- a/packages/eslint-plugin/src/rules/consistent-type-assertions.ts +++ b/packages/eslint-plugin/src/rules/consistent-type-assertions.ts @@ -27,7 +27,7 @@ export default util.createRule({ docs: { category: 'Best Practices', description: 'Enforces consistent usage of type assertions', - recommended: 'error', + recommended: false, }, messages: { as: "Use 'as {{cast}}' instead of '<{{cast}}>'.", diff --git a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts index f0a5978d02f5..f0904f07744e 100644 --- a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts +++ b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts @@ -27,7 +27,7 @@ export default util.createRule({ description: 'Require explicit return types on functions and class methods', category: 'Stylistic Issues', - recommended: 'warn', + recommended: false, }, messages: { missingReturnType: 'Missing return type on function.', diff --git a/packages/eslint-plugin/src/rules/explicit-module-boundary-types.ts b/packages/eslint-plugin/src/rules/explicit-module-boundary-types.ts index b00d8eb1087e..265010adc6d0 100644 --- a/packages/eslint-plugin/src/rules/explicit-module-boundary-types.ts +++ b/packages/eslint-plugin/src/rules/explicit-module-boundary-types.ts @@ -29,7 +29,7 @@ export default util.createRule({ description: "Require explicit return and argument types on exported functions' and classes' public class methods", category: 'Stylistic Issues', - recommended: false, + recommended: 'warn', }, messages: { missingReturnType: 'Missing return type on function.', diff --git a/packages/eslint-plugin/src/rules/interface-name-prefix.ts b/packages/eslint-plugin/src/rules/interface-name-prefix.ts index 493c5e731244..281a9eb61978 100644 --- a/packages/eslint-plugin/src/rules/interface-name-prefix.ts +++ b/packages/eslint-plugin/src/rules/interface-name-prefix.ts @@ -45,9 +45,7 @@ export default util.createRule({ description: 'Require that interface names should or should not prefixed with `I`', category: 'Stylistic Issues', - // this will always be recommended as there's no reason to use this convention - // https://github.com/typescript-eslint/typescript-eslint/issues/374 - recommended: 'error', + recommended: false, }, deprecated: true, replacedBy: ['naming-convention'], diff --git a/packages/eslint-plugin/src/rules/member-delimiter-style.ts b/packages/eslint-plugin/src/rules/member-delimiter-style.ts index 98781d2b8641..75381a8df2cb 100644 --- a/packages/eslint-plugin/src/rules/member-delimiter-style.ts +++ b/packages/eslint-plugin/src/rules/member-delimiter-style.ts @@ -61,7 +61,7 @@ export default util.createRule({ description: 'Require a specific member delimiter style for interfaces and type literals', category: 'Stylistic Issues', - recommended: 'error', + recommended: false, }, fixable: 'code', messages: { diff --git a/packages/eslint-plugin/src/rules/naming-convention.ts b/packages/eslint-plugin/src/rules/naming-convention.ts index 69791b205c56..59b1bdfee803 100644 --- a/packages/eslint-plugin/src/rules/naming-convention.ts +++ b/packages/eslint-plugin/src/rules/naming-convention.ts @@ -21,7 +21,6 @@ enum PredefinedFormats { strictCamelCase = 1 << 1, PascalCase = 1 << 2, StrictPascalCase = 1 << 3, - // eslint-disable-next-line @typescript-eslint/camelcase snake_case = 1 << 4, UPPER_CASE = 1 << 5, } @@ -1080,14 +1079,12 @@ https://gist.github.com/mathiasbynens/6334847 function isPascalCase(name: string): boolean { return ( name.length === 0 || - // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with (name[0] === name[0].toUpperCase() && !name.includes('_')) ); } function isStrictPascalCase(name: string): boolean { return ( name.length === 0 || - // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with (name[0] === name[0].toUpperCase() && hasStrictCamelHumps(name, true)) ); } @@ -1095,14 +1092,12 @@ function isStrictPascalCase(name: string): boolean { function isCamelCase(name: string): boolean { return ( name.length === 0 || - // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with (name[0] === name[0].toLowerCase() && !name.includes('_')) ); } function isStrictCamelCase(name: string): boolean { return ( name.length === 0 || - // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with (name[0] === name[0].toLowerCase() && hasStrictCamelHumps(name, false)) ); } diff --git a/packages/eslint-plugin/src/rules/no-extra-non-null-assertion.ts b/packages/eslint-plugin/src/rules/no-extra-non-null-assertion.ts index 44182650d145..def33bbb827f 100644 --- a/packages/eslint-plugin/src/rules/no-extra-non-null-assertion.ts +++ b/packages/eslint-plugin/src/rules/no-extra-non-null-assertion.ts @@ -8,7 +8,7 @@ export default util.createRule({ docs: { description: 'Disallow extra non-null assertion', category: 'Stylistic Issues', - recommended: false, + recommended: 'error', }, fixable: 'code', schema: [], diff --git a/packages/eslint-plugin/src/rules/no-extra-semi.ts b/packages/eslint-plugin/src/rules/no-extra-semi.ts index 6481b8ac7ed4..d1ffdf61d8d4 100644 --- a/packages/eslint-plugin/src/rules/no-extra-semi.ts +++ b/packages/eslint-plugin/src/rules/no-extra-semi.ts @@ -11,7 +11,7 @@ export default util.createRule({ docs: { description: 'Disallow unnecessary semicolons', category: 'Possible Errors', - recommended: false, + recommended: 'error', extendsBaseRule: true, }, fixable: 'code', diff --git a/packages/eslint-plugin/src/rules/no-floating-promises.ts b/packages/eslint-plugin/src/rules/no-floating-promises.ts index 615f88f25df3..2a0c86e5011e 100644 --- a/packages/eslint-plugin/src/rules/no-floating-promises.ts +++ b/packages/eslint-plugin/src/rules/no-floating-promises.ts @@ -23,7 +23,7 @@ export default util.createRule({ docs: { description: 'Requires Promise-like values to be handled appropriately', category: 'Best Practices', - recommended: false, + recommended: 'error', suggestion: true, requiresTypeChecking: true, }, diff --git a/packages/eslint-plugin/src/rules/no-implied-eval.ts b/packages/eslint-plugin/src/rules/no-implied-eval.ts index 0f6118597868..d983065d5b2e 100644 --- a/packages/eslint-plugin/src/rules/no-implied-eval.ts +++ b/packages/eslint-plugin/src/rules/no-implied-eval.ts @@ -20,7 +20,7 @@ export default util.createRule({ docs: { description: 'Disallow the use of `eval()`-like methods', category: 'Best Practices', - recommended: false, + recommended: 'error', requiresTypeChecking: true, }, messages: { diff --git a/packages/eslint-plugin/src/rules/no-non-null-asserted-optional-chain.ts b/packages/eslint-plugin/src/rules/no-non-null-asserted-optional-chain.ts index 9ebc2d6a61fe..fa14fa661b6d 100644 --- a/packages/eslint-plugin/src/rules/no-non-null-asserted-optional-chain.ts +++ b/packages/eslint-plugin/src/rules/no-non-null-asserted-optional-chain.ts @@ -22,7 +22,7 @@ export default util.createRule<[], MessageIds>({ description: 'Disallows using a non-null assertion after an optional chain expression', category: 'Possible Errors', - recommended: false, + recommended: 'error', suggestion: true, }, messages: { diff --git a/packages/eslint-plugin/src/rules/no-unsafe-assignment.ts b/packages/eslint-plugin/src/rules/no-unsafe-assignment.ts index 638d30363112..e581862b0ed3 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-assignment.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-assignment.ts @@ -21,7 +21,7 @@ export default util.createRule({ docs: { description: 'Disallows assigning any to variables and properties', category: 'Possible Errors', - recommended: false, + recommended: 'error', requiresTypeChecking: true, }, messages: { diff --git a/packages/eslint-plugin/src/rules/no-unsafe-call.ts b/packages/eslint-plugin/src/rules/no-unsafe-call.ts index 4cd123708229..43ca4a0140f9 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-call.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-call.ts @@ -10,7 +10,7 @@ export default util.createRule<[], MessageIds>({ docs: { description: 'Disallows calling an any type value', category: 'Possible Errors', - recommended: false, + recommended: 'error', requiresTypeChecking: true, }, messages: { diff --git a/packages/eslint-plugin/src/rules/no-unsafe-member-access.ts b/packages/eslint-plugin/src/rules/no-unsafe-member-access.ts index a17818efb414..c6280dea92cc 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-member-access.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-member-access.ts @@ -16,7 +16,7 @@ export default util.createRule({ docs: { description: 'Disallows member access on any typed variables', category: 'Possible Errors', - recommended: false, + recommended: 'error', requiresTypeChecking: true, }, messages: { diff --git a/packages/eslint-plugin/src/rules/no-unsafe-return.ts b/packages/eslint-plugin/src/rules/no-unsafe-return.ts index 53429898da4e..b0168dc6f500 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-return.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-return.ts @@ -12,7 +12,7 @@ export default util.createRule({ docs: { description: 'Disallows returning any from a function', category: 'Possible Errors', - recommended: false, + recommended: 'error', requiresTypeChecking: true, }, messages: { diff --git a/packages/eslint-plugin/src/rules/no-use-before-define.ts b/packages/eslint-plugin/src/rules/no-use-before-define.ts index 2c66ec1ee5af..ed0240082d2b 100644 --- a/packages/eslint-plugin/src/rules/no-use-before-define.ts +++ b/packages/eslint-plugin/src/rules/no-use-before-define.ts @@ -177,7 +177,7 @@ export default util.createRule({ docs: { description: 'Disallow the use of variables before they are defined', category: 'Variables', - recommended: 'error', + recommended: false, extendsBaseRule: true, }, messages: { diff --git a/packages/eslint-plugin/src/rules/prefer-as-const.ts b/packages/eslint-plugin/src/rules/prefer-as-const.ts index 9fb619b74b52..91f432420214 100644 --- a/packages/eslint-plugin/src/rules/prefer-as-const.ts +++ b/packages/eslint-plugin/src/rules/prefer-as-const.ts @@ -12,7 +12,7 @@ export default util.createRule({ docs: { description: 'Prefer usage of `as const` over literal type', category: 'Best Practices', - recommended: false, + recommended: 'error', suggestion: true, }, fixable: 'code', diff --git a/packages/eslint-plugin/src/rules/prefer-includes.ts b/packages/eslint-plugin/src/rules/prefer-includes.ts index 5b3b1c19b878..721c53850df4 100644 --- a/packages/eslint-plugin/src/rules/prefer-includes.ts +++ b/packages/eslint-plugin/src/rules/prefer-includes.ts @@ -15,7 +15,7 @@ export default createRule({ docs: { description: 'Enforce `includes` method over `indexOf` method', category: 'Best Practices', - recommended: 'error', + recommended: false, requiresTypeChecking: true, }, fixable: 'code', diff --git a/packages/eslint-plugin/src/rules/prefer-string-starts-ends-with.ts b/packages/eslint-plugin/src/rules/prefer-string-starts-ends-with.ts index 795c877a8e3d..90b38f18e78d 100644 --- a/packages/eslint-plugin/src/rules/prefer-string-starts-ends-with.ts +++ b/packages/eslint-plugin/src/rules/prefer-string-starts-ends-with.ts @@ -26,7 +26,7 @@ export default createRule({ description: 'Enforce the use of `String#startsWith` and `String#endsWith` instead of other equivalent methods of checking substrings', category: 'Best Practices', - recommended: 'error', + recommended: false, requiresTypeChecking: true, }, messages: { @@ -87,7 +87,6 @@ export default createRule({ evaluated != null && typeof evaluated.value === 'string' && // checks if the string is a character long - // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with evaluated.value[0] === evaluated.value ); } diff --git a/packages/eslint-plugin/src/rules/restrict-plus-operands.ts b/packages/eslint-plugin/src/rules/restrict-plus-operands.ts index 2702009046ff..0917484ea029 100644 --- a/packages/eslint-plugin/src/rules/restrict-plus-operands.ts +++ b/packages/eslint-plugin/src/rules/restrict-plus-operands.ts @@ -17,7 +17,7 @@ export default util.createRule({ description: 'When adding two variables, operands must both be of type number or of type string', category: 'Best Practices', - recommended: false, + recommended: 'error', requiresTypeChecking: true, }, messages: { diff --git a/packages/eslint-plugin/src/rules/restrict-template-expressions.ts b/packages/eslint-plugin/src/rules/restrict-template-expressions.ts index 6ba846ed5980..aeda73af5216 100644 --- a/packages/eslint-plugin/src/rules/restrict-template-expressions.ts +++ b/packages/eslint-plugin/src/rules/restrict-template-expressions.ts @@ -23,7 +23,7 @@ export default util.createRule({ docs: { description: 'Enforce template literal expressions to be of string type', category: 'Best Practices', - recommended: false, + recommended: 'error', requiresTypeChecking: true, }, messages: { diff --git a/packages/eslint-plugin/src/rules/type-annotation-spacing.ts b/packages/eslint-plugin/src/rules/type-annotation-spacing.ts index b33ec8fd7b41..985e008c16d2 100644 --- a/packages/eslint-plugin/src/rules/type-annotation-spacing.ts +++ b/packages/eslint-plugin/src/rules/type-annotation-spacing.ts @@ -114,7 +114,7 @@ export default util.createRule({ docs: { description: 'Require consistent spacing around type annotations', category: 'Stylistic Issues', - recommended: 'error', + recommended: false, }, fixable: 'whitespace', messages: { diff --git a/packages/eslint-plugin/tests/rules/naming-convention.test.ts b/packages/eslint-plugin/tests/rules/naming-convention.test.ts index b4326c8fe754..3787dd4acdde 100644 --- a/packages/eslint-plugin/tests/rules/naming-convention.test.ts +++ b/packages/eslint-plugin/tests/rules/naming-convention.test.ts @@ -67,7 +67,6 @@ const formatTestNames: Readonly a[0].localeCompare(b[0]), @@ -122,8 +116,9 @@ function reducer( * Helper function writes configuration. */ function writeConfig(config: LinterConfig, filePath: string): void { - const configStr = format(JSON.stringify(config), { - parser: 'json', + const code = `export = ${JSON.stringify(config)};`; + const configStr = format(code, { + parser: 'typescript', ...prettierConfig, }); fs.writeFileSync(filePath, configStr); @@ -136,25 +131,25 @@ const baseConfig: LinterConfig = { }, plugins: ['@typescript-eslint'], }; -writeConfig(baseConfig, path.resolve(__dirname, '../src/configs/base.json')); +writeConfig(baseConfig, path.resolve(__dirname, '../src/configs/base.ts')); console.log(); console.log( - '------------------------------------------------ all.json ------------------------------------------------', + '------------------------------------------------ all.ts ------------------------------------------------', ); const allConfig: LinterConfig = { - extends: './configs/base.json', + extends: EXTENDS, rules: ruleEntries.reduce( (config, entry) => reducer(config, entry, { errorLevel: 'error', filterDeprecated: true }), {}, ), }; -writeConfig(allConfig, path.resolve(__dirname, '../src/configs/all.json')); +writeConfig(allConfig, path.resolve(__dirname, '../src/configs/all.ts')); console.log(); console.log( - '------------------------------ recommended.json (should not require program) ------------------------------', + '------------------------------ recommended.ts (should not require program) ------------------------------', ); const recommendedRules = ruleEntries .filter(entry => !!entry[1].meta.docs?.recommended) @@ -166,21 +161,18 @@ const recommendedRules = ruleEntries }), {}, ); -BASE_RULES_THAT_ARE_RECOMMENDED.forEach(ruleName => { - recommendedRules[ruleName] = 'error'; -}); const recommendedConfig: LinterConfig = { - extends: './configs/base.json', + extends: EXTENDS, rules: recommendedRules, }; writeConfig( recommendedConfig, - path.resolve(__dirname, '../src/configs/recommended.json'), + path.resolve(__dirname, '../src/configs/recommended.ts'), ); console.log(); console.log( - '--------------------------------- recommended-requiring-type-checking.json ---------------------------------', + '--------------------------------- recommended-requiring-type-checking.ts ---------------------------------', ); const recommendedRulesRequiringProgram = ruleEntries .filter(entry => !!entry[1].meta.docs?.recommended) @@ -192,17 +184,14 @@ const recommendedRulesRequiringProgram = ruleEntries }), {}, ); -BASE_RULES_THAT_ARE_RECOMMENDED.forEach(ruleName => { - recommendedRulesRequiringProgram[ruleName] = 'error'; -}); const recommendedRequiringTypeCheckingConfig: LinterConfig = { - extends: './configs/base.json', + extends: EXTENDS, rules: recommendedRulesRequiringProgram, }; writeConfig( recommendedRequiringTypeCheckingConfig, path.resolve( __dirname, - '../src/configs/recommended-requiring-type-checking.json', + '../src/configs/recommended-requiring-type-checking.ts', ), ); diff --git a/tools/generate-contributors.ts b/tools/generate-contributors.ts index c0f84c712a73..4c3c2b0a36d4 100644 --- a/tools/generate-contributors.ts +++ b/tools/generate-contributors.ts @@ -91,7 +91,7 @@ async function main(): Promise { return { login: usr.login, name: usr.name || usr.login, - avatar_url: usr.avatar_url, // eslint-disable-line @typescript-eslint/camelcase + avatar_url: usr.avatar_url, profile: usr.html_url, contributions: [], }; From da0aec2cfa27902aae7c438a2fe91343c822e4ae Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Sun, 10 May 2020 13:27:50 -0700 Subject: [PATCH 18/33] feat(eslint-plugin): delete deprecated rules (#2002) --- .../eslint-plugin/docs/rules/ban-ts-ignore.md | 44 -- .../eslint-plugin/docs/rules/camelcase.md | 136 +---- .../docs/rules/class-name-casing.md | 61 -- .../docs/rules/generic-type-naming.md | 47 -- .../docs/rules/interface-name-prefix.md | 141 ----- .../eslint-plugin/docs/rules/member-naming.md | 46 -- .../docs/rules/no-untyped-public-signature.md | 65 --- .../eslint-plugin/src/rules/ban-ts-ignore.ts | 44 -- packages/eslint-plugin/src/rules/camelcase.ts | 166 ------ .../src/rules/class-name-casing.ts | 138 ----- .../src/rules/generic-type-naming.ts | 52 -- packages/eslint-plugin/src/rules/index.ts | 14 - .../src/rules/interface-name-prefix.ts | 144 ----- .../eslint-plugin/src/rules/member-naming.ts | 140 ----- .../src/rules/no-base-to-string.ts | 7 - .../src/rules/no-untyped-public-signature.ts | 125 ---- packages/eslint-plugin/tests/docs.test.ts | 5 +- .../tests/rules/ban-ts-ignore.test.ts | 66 --- .../tests/rules/camelcase.test.ts | 552 ------------------ .../tests/rules/class-name-casing.test.ts | 196 ------- .../tests/rules/generic-type-naming.test.ts | 207 ------- .../tests/rules/interface-name-prefix.test.ts | 191 ------ .../tests/rules/member-naming.test.ts | 453 -------------- .../tests/rules/no-base-to-string.test.ts | 15 +- .../rules/no-untyped-public-signature.test.ts | 305 ---------- 25 files changed, 12 insertions(+), 3348 deletions(-) delete mode 100644 packages/eslint-plugin/docs/rules/ban-ts-ignore.md delete mode 100644 packages/eslint-plugin/docs/rules/class-name-casing.md delete mode 100644 packages/eslint-plugin/docs/rules/generic-type-naming.md delete mode 100644 packages/eslint-plugin/docs/rules/interface-name-prefix.md delete mode 100644 packages/eslint-plugin/docs/rules/member-naming.md delete mode 100644 packages/eslint-plugin/docs/rules/no-untyped-public-signature.md delete mode 100644 packages/eslint-plugin/src/rules/ban-ts-ignore.ts delete mode 100644 packages/eslint-plugin/src/rules/camelcase.ts delete mode 100644 packages/eslint-plugin/src/rules/class-name-casing.ts delete mode 100644 packages/eslint-plugin/src/rules/generic-type-naming.ts delete mode 100644 packages/eslint-plugin/src/rules/interface-name-prefix.ts delete mode 100644 packages/eslint-plugin/src/rules/member-naming.ts delete mode 100644 packages/eslint-plugin/src/rules/no-untyped-public-signature.ts delete mode 100644 packages/eslint-plugin/tests/rules/ban-ts-ignore.test.ts delete mode 100644 packages/eslint-plugin/tests/rules/camelcase.test.ts delete mode 100644 packages/eslint-plugin/tests/rules/class-name-casing.test.ts delete mode 100644 packages/eslint-plugin/tests/rules/generic-type-naming.test.ts delete mode 100644 packages/eslint-plugin/tests/rules/interface-name-prefix.test.ts delete mode 100644 packages/eslint-plugin/tests/rules/member-naming.test.ts delete mode 100644 packages/eslint-plugin/tests/rules/no-untyped-public-signature.test.ts diff --git a/packages/eslint-plugin/docs/rules/ban-ts-ignore.md b/packages/eslint-plugin/docs/rules/ban-ts-ignore.md deleted file mode 100644 index 936d7936afc9..000000000000 --- a/packages/eslint-plugin/docs/rules/ban-ts-ignore.md +++ /dev/null @@ -1,44 +0,0 @@ -# Bans “// @ts-ignore” comments from being used (`ban-ts-ignore`) - -This rule has been deprecated in favor of [`ban-ts-comment`](./ban-ts-comment.md) - -Suppressing TypeScript Compiler Errors can be hard to discover. - -## DEPRECATED - -This rule has been deprecated in favour of the [`ban-ts-comment`](./ban-ts-comment.md) rule. -It will be removed in a future version of this plugin. - -## Rule Details - -Does not allow the use of `// @ts-ignore` comments. - -The following patterns are considered warnings: - -```ts -if (false) { - // @ts-ignore: Unreachable code error - console.log('hello'); -} -``` - -The following patterns are not warnings: - -```ts -if (false) { - // Compiler warns about unreachable code error - console.log('hello'); -} -``` - -## When Not To Use It - -If you are sure, compiler errors won't affect functionality and you need to disable them. - -## Further Reading - -- TypeScript [Type Checking JavaScript Files](https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html) - -## Compatibility - -- TSLint: [ban-ts-ignore](https://palantir.github.io/tslint/rules/ban-ts-ignore/) diff --git a/packages/eslint-plugin/docs/rules/camelcase.md b/packages/eslint-plugin/docs/rules/camelcase.md index 89cd63aa9295..cea28224965f 100644 --- a/packages/eslint-plugin/docs/rules/camelcase.md +++ b/packages/eslint-plugin/docs/rules/camelcase.md @@ -1,136 +1,8 @@ -# Enforce camelCase naming convention (`camelcase`) - ## DEPRECATED This rule has been deprecated in favour of the [`naming-convention`](./naming-convention.md) rule. -It will be removed in a future version of this plugin. - -## Rule Details - -This rule extends the base [`eslint/camelcase`](https://eslint.org/docs/rules/camelcase) rule. -It adds support for numerous TypeScript features. - -## How to use - -```jsonc -{ - // note you must disable the base rule as it can report incorrect errors - "camelcase": "off", - "@typescript-eslint/camelcase": ["error"] -} -``` - -## Options - -See [`eslint/camelcase` options](https://eslint.org/docs/rules/camelcase#options). -This rule adds the following options: - -```ts -interface Options extends BaseCamelcaseOptions { - genericType?: 'always' | 'never'; -} - -const defaultOptions: Options = { - ...baseCamelcaseDefaultOptions, - genericType: 'never', -}; -``` - -- `"genericType": "never"` (default) does not check generic identifiers -- `"genericType": "always"` enforces camelCase style for generic identifiers - -### `genericType: "always"` - -Examples of **incorrect** code for this rule with the default `{ "genericType": "always" }` option: - -```typescript -/* eslint @typescript-eslint/camelcase: ["error", { "genericType": "always" }] */ - -interface Foo {} -function foo() {} -class Foo {} -type Foo = {}; -class Foo { - method() {} -} - -interface Foo {} -function foo() {} -class Foo {} -type Foo = {}; -class Foo { - method() {} -} - -interface Foo {} -function foo() {} -class Foo {} -type Foo = {}; -class Foo { - method() {} -} -``` - -Examples of **correct** code for this rule with the default `{ "genericType": "always" }` option: - -```typescript -/* eslint @typescript-eslint/camelcase: ["error", { "genericType": "always" }] */ - -interface Foo {} -function foo() {} -class Foo {} -type Foo = {}; -class Foo { - method() {} -} - -interface Foo {} -function foo() {} -class Foo {} -type Foo = {}; -class Foo { - method() {} -} - -interface Foo {} -function foo() {} -class Foo {} -type Foo = {}; -class Foo { - method() {} -} -``` - -### `genericType: "never"` - -Examples of **correct** code for this rule with the `{ "genericType": "never" }` option: - -```typescript -/* eslint @typescript-eslint/camelcase: ["error", { "genericType": "never" }] */ - -interface Foo {} -function foo() {} -class Foo {} -type Foo = {}; -class Foo { - method() {} -} - -interface Foo {} -function foo() {} -class Foo {} -type Foo = {}; -class Foo { - method() {} -} - -interface Foo {} -function foo() {} -class Foo {} -type Foo = {}; -class Foo { - method() {} -} -``` -Taken with ❤️ [from ESLint core](https://github.com/eslint/eslint/blob/master/docs/rules/camelcase.md) + diff --git a/packages/eslint-plugin/docs/rules/class-name-casing.md b/packages/eslint-plugin/docs/rules/class-name-casing.md deleted file mode 100644 index ae5d5da7a2e6..000000000000 --- a/packages/eslint-plugin/docs/rules/class-name-casing.md +++ /dev/null @@ -1,61 +0,0 @@ -# Require PascalCased class and interface names (`class-name-casing`) - -This rule enforces PascalCase names for classes and interfaces. - -## DEPRECATED - -This rule has been deprecated in favour of the [`naming-convention`](./naming-convention.md) rule. -It will be removed in a future version of this plugin. - -## Rule Details - -This rule aims to make it easy to differentiate classes from regular variables at a glance. -The `_` prefix is sometimes used to designate a private declaration, so the rule also supports a name -that might be `_Example` instead of `Example`. - -## Options - -This rule has an object option: - -- `"allowUnderscorePrefix": false`: (default) does not allow the name to have an underscore prefix -- `"allowUnderscorePrefix": true`: allows the name to optionally have an underscore prefix - -## Examples - -Examples of **incorrect** code for this rule: - -```ts -class invalidClassName {} - -class Another_Invalid_Class_Name {} - -var bar = class invalidName {}; - -interface someInterface {} - -class _InternalClass {} -``` - -Examples of **correct** code for this rule: - -```ts -class ValidClassName {} - -export default class {} - -var foo = class {}; - -interface SomeInterface {} - -/* eslint @typescript-eslint/class-name-casing: { "allowUnderscorePrefix": true } */ -class _InternalClass {} -``` - -## When Not To Use It - -You should turn off this rule if you do not care about class name casing, or if -you use a different type of casing. - -## Further Reading - -- [`class-name`](https://palantir.github.io/tslint/rules/class-name/) in [TSLint](https://palantir.github.io/tslint/) diff --git a/packages/eslint-plugin/docs/rules/generic-type-naming.md b/packages/eslint-plugin/docs/rules/generic-type-naming.md deleted file mode 100644 index dc9642735359..000000000000 --- a/packages/eslint-plugin/docs/rules/generic-type-naming.md +++ /dev/null @@ -1,47 +0,0 @@ -# Enforces naming of generic type variables (`generic-type-naming`) - -It can be helpful to enforce a consistent naming style for generic type variables used within a type. -For example, prefixing them with `T` and ensuring a somewhat descriptive name, or enforcing Hungarian notation. - -## DEPRECATED - -This rule has been deprecated in favour of the [`naming-convention`](./naming-convention.md) rule. -It will be removed in a future version of this plugin. - -## Rule Details - -This rule allows you to enforce conventions over type variables. By default, it does nothing. - -## Options - -The rule takes a single string option, which is a regular expression that type variables should match. - -Examples of **correct** code with a configuration of `'^T[A-Z][a-zA-Z]+$'`: - -```ts -type ReadOnly = { - readonly [TKey in keyof TType]: TType[TKey]; -}; - -interface SimpleMap { - [key: string]: TValue; -} -``` - -Examples of **incorrect** code with a configuration of `'^T[A-Z][a-zA-Z]+$'`: - -```ts -type ReadOnly = { readonly [Key in keyof T]: T[Key] }; - -interface SimpleMap { - [key: string]: T; -} -``` - -## When Not To Use It - -If you do not want to enforce a naming convention for type variables. - -## Further Reading - -- [TypeScript Generics](https://www.typescriptlang.org/docs/handbook/generics.html) diff --git a/packages/eslint-plugin/docs/rules/interface-name-prefix.md b/packages/eslint-plugin/docs/rules/interface-name-prefix.md deleted file mode 100644 index 6322c9c79d65..000000000000 --- a/packages/eslint-plugin/docs/rules/interface-name-prefix.md +++ /dev/null @@ -1,141 +0,0 @@ -# Require that interface names should or should not prefixed with `I` (`interface-name-prefix`) - -Interfaces often represent important software contracts, so it can be helpful to prefix their names with `I`. -The unprefixed name is then available for a class that provides a standard implementation of the interface. -Alternatively, the contributor guidelines for the TypeScript repo suggest -[never prefixing](https://github.com/Microsoft/TypeScript/wiki/Coding-guidelines#names) interfaces with `I`. - -## DEPRECATED - -This rule has been deprecated in favour of the [`naming-convention`](./naming-convention.md) rule. -It will be removed in a future version of this plugin. - -## Rule Details - -This rule enforces whether or not the `I` prefix is required for interface names. -The `_` prefix is sometimes used to designate a private declaration, so the rule also supports a private interface -that might be named `_IAnimal` instead of `IAnimal`. - -## Options - -This rule has an object option: - -- `{ "prefixWithI": "never" }`: (default) disallows all interfaces being prefixed with `"I"` or `"_I"` -- `{ "prefixWithI": "always" }`: requires all interfaces be prefixed with `"I"` (but does not allow `"_I"`) -- `{ "prefixWithI": "always", "allowUnderscorePrefix": true }`: requires all interfaces be prefixed with - either `"I"` or `"_I"` - -For backwards compatibility, this rule supports a string option instead: - -- `"never"`: Equivalent to `{ "prefixWithI": "never" }` -- `"always"`: Equivalent to `{ "prefixWithI": "always" }` - -## Examples - -### never - -**Configuration:** `{ "prefixWithI": "never" }` - -The following patterns are considered warnings: - -```ts -interface IAnimal { - name: string; -} - -interface IIguana { - name: string; -} - -interface _IAnimal { - name: string; -} -``` - -The following patterns are not warnings: - -```ts -interface Animal { - name: string; -} - -interface Iguana { - name: string; -} -``` - -### always - -**Configuration:** `{ "prefixWithI": "always" }` - -The following patterns are considered warnings: - -```ts -interface Animal { - name: string; -} - -interface Iguana { - name: string; -} - -interface _IAnimal { - name: string; -} -``` - -The following patterns are not warnings: - -```ts -interface IAnimal { - name: string; -} - -interface IIguana { - name: string; -} -``` - -### always and allowing underscores - -**Configuration:** `{ "prefixWithI": "always", "allowUnderscorePrefix": true }` - -The following patterns are considered warnings: - -```ts -interface Animal { - name: string; -} - -interface Iguana { - name: string; -} -``` - -The following patterns are not warnings: - -```ts -interface IAnimal { - name: string; -} - -interface IIguana { - name: string; -} - -interface _IAnimal { - name: string; -} -``` - -## When Not To Use It - -If you do not want to enforce interface name prefixing. - -## Further Reading - -TypeScript [Interfaces](https://www.typescriptlang.org/docs/handbook/interfaces.html) - -## Compatibility - -TSLint: [interface-name](https://palantir.github.io/tslint/rules/interface-name/) diff --git a/packages/eslint-plugin/docs/rules/member-naming.md b/packages/eslint-plugin/docs/rules/member-naming.md deleted file mode 100644 index 0dd8a5a2f29c..000000000000 --- a/packages/eslint-plugin/docs/rules/member-naming.md +++ /dev/null @@ -1,46 +0,0 @@ -# Enforces naming conventions for class members by visibility (`member-naming`) - -It can be helpful to enforce naming conventions for `private` (and sometimes `protected`) members of an object. For example, prefixing private properties with a `_` allows them to be easily discerned when being inspected by tools that do not have knowledge of TypeScript (such as most debuggers). - -## DEPRECATED - -This rule has been deprecated in favour of the [`naming-convention`](./naming-convention.md) rule. -It will be removed in a future version of this plugin. - -## Rule Details - -This rule allows you to enforce conventions for class property and method names by their visibility. By default, it enforces nothing. - -> Note: constructors are explicitly ignored regardless of the the regular expression options provided - -## Options - -You can specify a regular expression to test the names of properties for each visibility level: `public`, `protected`, `private`. - -Examples of **correct** code with `{ "private": "^_" }` specified: - -```ts -class HappyClass { - private _foo: string; - private _bar = 123; - private _fizz() {} -} -``` - -Examples of **incorrect** code with `{ "private": "^_" }` specified: - -```ts -class SadClass { - private foo: string; - private bar = 123; - private fizz() {} -} -``` - -## When Not To Use It - -If you do not want to enforce per-visibility naming rules for member properties. - -## Further Reading - -- ESLint's [`camelcase` rule](https://eslint.org/docs/rules/camelcase) diff --git a/packages/eslint-plugin/docs/rules/no-untyped-public-signature.md b/packages/eslint-plugin/docs/rules/no-untyped-public-signature.md deleted file mode 100644 index ffcd083b57dc..000000000000 --- a/packages/eslint-plugin/docs/rules/no-untyped-public-signature.md +++ /dev/null @@ -1,65 +0,0 @@ -# Disallow untyped public methods (`no-untyped-public-signature`) - -public methods are meant to be used by code outside of your class. By typing both the parameters and the return type of public methods they will be more readable and easy to use. - -## DEPRECATED - -This rule has been deprecated in favour of the [`explicit-module-boundary-types`](./explicit-module-boundary-types.md) rule. -It will be removed in a future version of this plugin. - -## Rule Details - -This rule aims to ensure that only typed public methods are declared in the code. - -The following patterns are considered warnings: - -```ts -// untyped parameter -public foo(param1): void { -} - -// untyped parameter -public foo(param1: any): void { -} - -// untyped return type -public foo(param1: string) { -} - -// untyped return type -public foo(param1: string): any { -} -``` - -The following patterns are not warnings: - -```ts -// typed public method -public foo(param1: string): void { -} - -// untyped private method -private foo(param1) { -} -``` - -## Options - -This rule, in its default state, does not require any argument. - -### `ignoredMethods` - -You may pass method names you would like this rule to ignore, like so: - -```jsonc -{ - "@typescript-eslint/no-untyped-public-signature": [ - "error", - { "ignoredMethods": ["ignoredMethodName"] } - ] -} -``` - -## When Not To Use It - -If you don't wish to type public methods. diff --git a/packages/eslint-plugin/src/rules/ban-ts-ignore.ts b/packages/eslint-plugin/src/rules/ban-ts-ignore.ts deleted file mode 100644 index bbeadfe5269d..000000000000 --- a/packages/eslint-plugin/src/rules/ban-ts-ignore.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { AST_TOKEN_TYPES } from '@typescript-eslint/experimental-utils'; -import * as util from '../util'; - -export default util.createRule({ - name: 'ban-ts-ignore', - meta: { - type: 'problem', - docs: { - description: 'Bans “// @ts-ignore” comments from being used', - category: 'Best Practices', - recommended: false, - }, - schema: [], - messages: { - tsIgnoreComment: - 'Do not use "// @ts-ignore" comments because they suppress compilation errors.', - }, - deprecated: true, - replacedBy: ['ban-ts-comment'], - }, - defaultOptions: [], - create(context) { - const tsIgnoreRegExp = /^\/*\s*@ts-ignore/; - const sourceCode = context.getSourceCode(); - - return { - Program(): void { - const comments = sourceCode.getAllComments(); - - comments.forEach(comment => { - if (comment.type !== AST_TOKEN_TYPES.Line) { - return; - } - if (tsIgnoreRegExp.test(comment.value)) { - context.report({ - node: comment, - messageId: 'tsIgnoreComment', - }); - } - }); - }, - }; - }, -}); diff --git a/packages/eslint-plugin/src/rules/camelcase.ts b/packages/eslint-plugin/src/rules/camelcase.ts deleted file mode 100644 index 7d8c179f2b9d..000000000000 --- a/packages/eslint-plugin/src/rules/camelcase.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { - TSESTree, - AST_NODE_TYPES, -} from '@typescript-eslint/experimental-utils'; -import baseRule from 'eslint/lib/rules/camelcase'; -import * as util from '../util'; - -type Options = util.InferOptionsTypeFromRule; -type MessageIds = util.InferMessageIdsTypeFromRule; - -const schema = util.deepMerge( - Array.isArray(baseRule.meta.schema) - ? baseRule.meta.schema[0] - : baseRule.meta.schema, - { - properties: { - genericType: { - enum: ['always', 'never'], - }, - }, - }, -); - -export default util.createRule({ - name: 'camelcase', - meta: { - type: 'suggestion', - docs: { - description: 'Enforce camelCase naming convention', - category: 'Stylistic Issues', - recommended: false, - extendsBaseRule: true, - }, - deprecated: true, - replacedBy: ['naming-convention'], - schema: [schema], - messages: baseRule.meta.messages, - }, - defaultOptions: [ - { - allow: ['^UNSAFE_'], - ignoreDestructuring: false, - properties: 'never', - genericType: 'never', - }, - ], - create(context, [options]) { - const rules = baseRule.create(context); - const TS_PROPERTY_TYPES = [ - AST_NODE_TYPES.TSPropertySignature, - AST_NODE_TYPES.ClassProperty, - AST_NODE_TYPES.TSParameterProperty, - AST_NODE_TYPES.TSAbstractClassProperty, - ]; - - const genericType = options.genericType; - const properties = options.properties; - const allow = - options.allow?.map(entry => ({ - name: entry, - regex: new RegExp(entry), - })) ?? []; - - /** - * Checks if a string contains an underscore and isn't all upper-case - * @param name The string to check. - */ - function isUnderscored(name: string): boolean { - // if there's an underscore, it might be A_CONSTANT, which is okay - return name.includes('_') && name !== name.toUpperCase(); - } - - /** - * Checks if a string match the ignore list - * @param name The string to check. - * @returns if the string is ignored - * @private - */ - function isAllowed(name: string): boolean { - return ( - allow.findIndex( - entry => name === entry.name || entry.regex.test(name), - ) !== -1 - ); - } - - /** - * Checks if the the node is a valid TypeScript property type. - * @param node the node to be validated. - * @returns true if the node is a TypeScript property type. - * @private - */ - function isTSPropertyType(node: TSESTree.Node): boolean { - if (TS_PROPERTY_TYPES.includes(node.type)) { - return true; - } - - if (node.type === AST_NODE_TYPES.AssignmentPattern) { - return ( - node.parent !== undefined && - TS_PROPERTY_TYPES.includes(node.parent.type) - ); - } - - return false; - } - - function report(node: TSESTree.Identifier): void { - context.report({ - node, - messageId: 'notCamelCase', - data: { name: node.name }, - }); - } - - return { - Identifier(node): void { - /* - * Leading and trailing underscores are commonly used to flag - * private/protected identifiers, strip them - */ - const name = node.name.replace(/^_+|_+$/g, ''); - - // First, we ignore the node if it match the ignore list - if (isAllowed(name)) { - return; - } - - // Check TypeScript specific nodes - const parent = node.parent; - if (parent && isTSPropertyType(parent)) { - if (properties === 'always' && isUnderscored(name)) { - report(node); - } - - return; - } - - if (parent && parent.type === AST_NODE_TYPES.TSTypeParameter) { - if (genericType === 'always' && isUnderscored(name)) { - report(node); - } - - return; - } - - if (parent && parent.type === AST_NODE_TYPES.OptionalMemberExpression) { - // Report underscored object names - if ( - properties === 'always' && - parent.object.type === AST_NODE_TYPES.Identifier && - parent.object.name === node.name && - isUnderscored(name) - ) { - report(node); - } - - return; - } - - // Let the base rule deal with the rest - rules.Identifier(node); - }, - }; - }, -}); diff --git a/packages/eslint-plugin/src/rules/class-name-casing.ts b/packages/eslint-plugin/src/rules/class-name-casing.ts deleted file mode 100644 index 5871f47db92b..000000000000 --- a/packages/eslint-plugin/src/rules/class-name-casing.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { - TSESTree, - AST_NODE_TYPES, -} from '@typescript-eslint/experimental-utils'; -import * as util from '../util'; - -type Options = [ - { - allowUnderscorePrefix?: boolean; - }, -]; -type MessageIds = 'notPascalCased'; - -export default util.createRule({ - name: 'class-name-casing', - meta: { - type: 'suggestion', - docs: { - description: 'Require PascalCased class and interface names', - category: 'Best Practices', - recommended: false, - }, - deprecated: true, - replacedBy: ['naming-convention'], - messages: { - notPascalCased: "{{friendlyName}} '{{name}}' must be PascalCased.", - }, - schema: [ - { - type: 'object', - properties: { - allowUnderscorePrefix: { - type: 'boolean', - default: false, - }, - }, - additionalProperties: false, - }, - ], - }, - defaultOptions: [{ allowUnderscorePrefix: false }], - create(context, [options]) { - const UNDERSCORE = '_'; - - /** - * Determine if the string is Upper cased - * @param str - */ - function isUpperCase(str: string): boolean { - return str === str.toUpperCase(); - } - - /** - * Determine if the identifier name is PascalCased - * @param name The identifier name - */ - function isPascalCase(name: string): boolean { - const startIndex = - options.allowUnderscorePrefix && name.startsWith(UNDERSCORE) ? 1 : 0; - - return ( - isUpperCase(name.charAt(startIndex)) && - !name.includes(UNDERSCORE, startIndex) - ); - } - - /** - * Report a class declaration as invalid - * @param decl The declaration - * @param id The name of the declaration - */ - function report( - decl: - | TSESTree.ClassDeclaration - | TSESTree.TSInterfaceDeclaration - | TSESTree.ClassExpression, - id: TSESTree.Identifier, - ): void { - let friendlyName; - - switch (decl.type) { - case AST_NODE_TYPES.ClassDeclaration: - case AST_NODE_TYPES.ClassExpression: - friendlyName = decl.abstract ? 'Abstract class' : 'Class'; - break; - case AST_NODE_TYPES.TSInterfaceDeclaration: - friendlyName = 'Interface'; - break; - } - - context.report({ - node: id, - messageId: 'notPascalCased', - data: { - friendlyName, - name: id.name, - }, - }); - } - - return { - 'ClassDeclaration, TSInterfaceDeclaration, ClassExpression'( - node: - | TSESTree.ClassDeclaration - | TSESTree.TSInterfaceDeclaration - | TSESTree.ClassExpression, - ): void { - // class expressions (i.e. export default class {}) are OK - if (node.id && !isPascalCase(node.id.name)) { - report(node, node.id); - } - }, - "VariableDeclarator[init.type='ClassExpression']"( - node: TSESTree.VariableDeclarator, - ): void { - if ( - node.id.type === AST_NODE_TYPES.ArrayPattern || - node.id.type === AST_NODE_TYPES.ObjectPattern - ) { - // TODO - handle the BindingPattern case maybe? - /* - // this example makes me barf, but it's valid code - var { bar } = class { - static bar() { return 2 } - } - */ - } else { - const id = node.id; - const nodeInit = node.init as TSESTree.ClassExpression; - - if (id && !nodeInit.id && !isPascalCase(id.name)) { - report(nodeInit, id); - } - } - }, - }; - }, -}); diff --git a/packages/eslint-plugin/src/rules/generic-type-naming.ts b/packages/eslint-plugin/src/rules/generic-type-naming.ts deleted file mode 100644 index 14a697f2e604..000000000000 --- a/packages/eslint-plugin/src/rules/generic-type-naming.ts +++ /dev/null @@ -1,52 +0,0 @@ -import * as util from '../util'; - -type Options = [string?]; -type MessageIds = 'paramNotMatchRule'; - -export default util.createRule({ - name: 'generic-type-naming', - meta: { - type: 'suggestion', - docs: { - description: 'Enforces naming of generic type variables', - category: 'Stylistic Issues', - // too opinionated to be recommended - recommended: false, - }, - deprecated: true, - replacedBy: ['naming-convention'], - messages: { - paramNotMatchRule: - 'Type parameter {{name}} does not match rule {{rule}}.', - }, - schema: [ - { - type: 'string', - }, - ], - }, - defaultOptions: [ - // Matches: T , TA , TAbc , TA1Bca , T1 , T2 - '^T([A-Z0-9][a-zA-Z0-9]*){0,1}$', - ], - create(context, [rule]) { - const regex = new RegExp(rule!); - - return { - TSTypeParameter(node): void { - const name = node.name.name; - - if (name && !regex.test(name)) { - context.report({ - node, - messageId: 'paramNotMatchRule', - data: { - name, - rule, - }, - }); - } - }, - }; - }, -}); diff --git a/packages/eslint-plugin/src/rules/index.ts b/packages/eslint-plugin/src/rules/index.ts index 9a97a3c5bf02..03ebb633b008 100644 --- a/packages/eslint-plugin/src/rules/index.ts +++ b/packages/eslint-plugin/src/rules/index.ts @@ -2,11 +2,8 @@ import adjacentOverloadSignatures from './adjacent-overload-signatures'; import arrayType from './array-type'; import awaitThenable from './await-thenable'; import banTsComment from './ban-ts-comment'; -import banTsIgnore from './ban-ts-ignore'; import banTypes from './ban-types'; import braceStyle from './brace-style'; -import camelcase from './camelcase'; -import classNameCasing from './class-name-casing'; import classLiteralPropertyStyle from './class-literal-property-style'; import commaSpacing from './comma-spacing'; import consistentTypeAssertions from './consistent-type-assertions'; @@ -17,12 +14,9 @@ import explicitFunctionReturnType from './explicit-function-return-type'; import explicitMemberAccessibility from './explicit-member-accessibility'; import explicitModuleBoundaryTypes from './explicit-module-boundary-types'; import funcCallSpacing from './func-call-spacing'; -import genericTypeNaming from './generic-type-naming'; import indent from './indent'; -import interfaceNamePrefix from './interface-name-prefix'; import keywordSpacing from './keyword-spacing'; import memberDelimiterStyle from './member-delimiter-style'; -import memberNaming from './member-naming'; import memberOrdering from './member-ordering'; import methodSignatureStyle from './method-signature-style'; import namingConvention from './naming-convention'; @@ -63,7 +57,6 @@ import noUnsafeAssignment from './no-unsafe-assignment'; import noUnsafeCall from './no-unsafe-call'; import noUnsafeMemberAccess from './no-unsafe-member-access'; import noUnsafeReturn from './no-unsafe-return'; -import noUntypedPublicSignature from './no-untyped-public-signature'; import noUnusedExpressions from './no-unused-expressions'; import noUnusedVars from './no-unused-vars'; import noUnusedVarsExperimental from './no-unused-vars-experimental'; @@ -107,11 +100,8 @@ export default { 'array-type': arrayType, 'await-thenable': awaitThenable, 'ban-ts-comment': banTsComment, - 'ban-ts-ignore': banTsIgnore, 'ban-types': banTypes, 'brace-style': braceStyle, - camelcase: camelcase, - 'class-name-casing': classNameCasing, 'class-literal-property-style': classLiteralPropertyStyle, 'comma-spacing': commaSpacing, 'consistent-type-assertions': consistentTypeAssertions, @@ -122,13 +112,10 @@ export default { 'explicit-member-accessibility': explicitMemberAccessibility, 'explicit-module-boundary-types': explicitModuleBoundaryTypes, 'func-call-spacing': funcCallSpacing, - 'generic-type-naming': genericTypeNaming, indent: indent, 'init-declarations': initDeclarations, - 'interface-name-prefix': interfaceNamePrefix, 'keyword-spacing': keywordSpacing, 'member-delimiter-style': memberDelimiterStyle, - 'member-naming': memberNaming, 'member-ordering': memberOrdering, 'method-signature-style': methodSignatureStyle, 'naming-convention': namingConvention, @@ -169,7 +156,6 @@ export default { 'no-unsafe-call': noUnsafeCall, 'no-unsafe-member-access': noUnsafeMemberAccess, 'no-unsafe-return': noUnsafeReturn, - 'no-untyped-public-signature': noUntypedPublicSignature, 'no-unused-expressions': noUnusedExpressions, 'no-unused-vars-experimental': noUnusedVarsExperimental, 'no-unused-vars': noUnusedVars, diff --git a/packages/eslint-plugin/src/rules/interface-name-prefix.ts b/packages/eslint-plugin/src/rules/interface-name-prefix.ts deleted file mode 100644 index 281a9eb61978..000000000000 --- a/packages/eslint-plugin/src/rules/interface-name-prefix.ts +++ /dev/null @@ -1,144 +0,0 @@ -import * as util from '../util'; - -type ParsedOptions = - | { - prefixWithI: 'never'; - } - | { - prefixWithI: 'always'; - allowUnderscorePrefix: boolean; - }; -type Options = [ - | 'never' - | 'always' - | { - prefixWithI?: 'never'; - } - | { - prefixWithI: 'always'; - allowUnderscorePrefix?: boolean; - }, -]; -type MessageIds = 'noPrefix' | 'alwaysPrefix'; - -/** - * Parses a given value as options. - */ -export function parseOptions([options]: Options): ParsedOptions { - if (options === 'always') { - return { prefixWithI: 'always', allowUnderscorePrefix: false }; - } - if (options !== 'never' && options.prefixWithI === 'always') { - return { - prefixWithI: 'always', - allowUnderscorePrefix: !!options.allowUnderscorePrefix, - }; - } - return { prefixWithI: 'never' }; -} - -export default util.createRule({ - name: 'interface-name-prefix', - meta: { - type: 'suggestion', - docs: { - description: - 'Require that interface names should or should not prefixed with `I`', - category: 'Stylistic Issues', - recommended: false, - }, - deprecated: true, - replacedBy: ['naming-convention'], - messages: { - noPrefix: 'Interface name must not be prefixed with "I".', - alwaysPrefix: 'Interface name must be prefixed with "I".', - }, - schema: [ - { - oneOf: [ - { - enum: [ - // Deprecated, equivalent to: { prefixWithI: 'never' } - 'never', - // Deprecated, equivalent to: { prefixWithI: 'always', allowUnderscorePrefix: false } - 'always', - ], - }, - { - type: 'object', - properties: { - prefixWithI: { - type: 'string', - enum: ['never'], - }, - }, - additionalProperties: false, - }, - { - type: 'object', - properties: { - prefixWithI: { - type: 'string', - enum: ['always'], - }, - allowUnderscorePrefix: { - type: 'boolean', - }, - }, - required: ['prefixWithI'], // required to select this "oneOf" alternative - additionalProperties: false, - }, - ], - }, - ], - }, - defaultOptions: [{ prefixWithI: 'never' }], - create(context, [options]) { - const parsedOptions = parseOptions([options]); - - /** - * Checks if a string is prefixed with "I". - * @param name The string to check - */ - function isPrefixedWithI(name: string): boolean { - return /^I[A-Z]/.test(name); - } - - /** - * Checks if a string is prefixed with "I" or "_I". - * @param name The string to check - */ - function isPrefixedWithIOrUnderscoreI(name: string): boolean { - return /^_?I[A-Z]/.test(name); - } - - return { - TSInterfaceDeclaration(node): void { - if (parsedOptions.prefixWithI === 'never') { - if (isPrefixedWithIOrUnderscoreI(node.id.name)) { - context.report({ - node: node.id, - messageId: 'noPrefix', - }); - } - } else { - if (parsedOptions.allowUnderscorePrefix) { - if (!isPrefixedWithIOrUnderscoreI(node.id.name)) { - context.report({ - node: node.id, - messageId: 'alwaysPrefix', - }); - } - } else { - if (!isPrefixedWithI(node.id.name)) { - context.report({ - node: node.id, - messageId: 'alwaysPrefix', - }); - } - } - } - }, - }; - }, -}); diff --git a/packages/eslint-plugin/src/rules/member-naming.ts b/packages/eslint-plugin/src/rules/member-naming.ts deleted file mode 100644 index 4facce887e5f..000000000000 --- a/packages/eslint-plugin/src/rules/member-naming.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { - TSESTree, - AST_NODE_TYPES, -} from '@typescript-eslint/experimental-utils'; -import * as util from '../util'; - -interface Config { - private?: T; - protected?: T; - public?: T; -} -type Modifiers = keyof Config; -type Options = [Config]; -type MessageIds = 'incorrectName'; - -export default util.createRule({ - name: 'member-naming', - meta: { - type: 'suggestion', - docs: { - description: - 'Enforces naming conventions for class members by visibility', - category: 'Stylistic Issues', - recommended: false, - }, - deprecated: true, - replacedBy: ['naming-convention'], - messages: { - incorrectName: - '{{accessibility}} property {{name}} should match {{convention}}.', - }, - schema: [ - { - type: 'object', - properties: { - public: { - type: 'string', - minLength: 1, - format: 'regex', - }, - protected: { - type: 'string', - minLength: 1, - format: 'regex', - }, - private: { - type: 'string', - minLength: 1, - format: 'regex', - }, - }, - additionalProperties: false, - minProperties: 1, - }, - ], - }, - defaultOptions: [{}], - create(context, [config]) { - const sourceCode = context.getSourceCode(); - - const conventions = (Object.keys(config) as Modifiers[]).reduce< - Config - >((acc, accessibility) => { - acc[accessibility] = new RegExp(config[accessibility]!); - - return acc; - }, {}); - - function getParameterNode( - node: TSESTree.TSParameterProperty, - ): TSESTree.Identifier | null { - if (node.parameter.type === AST_NODE_TYPES.AssignmentPattern) { - return node.parameter.left as TSESTree.Identifier; - } - - if (node.parameter.type === AST_NODE_TYPES.Identifier) { - return node.parameter; - } - - return null; - } - - function validateParameterName(node: TSESTree.TSParameterProperty): void { - const parameterNode = getParameterNode(node); - if (!parameterNode) { - return; - } - - validate(parameterNode, parameterNode.name, node.accessibility); - } - - function validateName( - node: TSESTree.MethodDefinition | TSESTree.ClassProperty, - ): void { - if ( - node.type === AST_NODE_TYPES.MethodDefinition && - node.kind === 'constructor' - ) { - return; - } - - validate( - node.key, - util.getNameFromMember(node, sourceCode), - node.accessibility, - ); - } - - /** - * Check that the name matches the convention for its accessibility. - * @param {ASTNode} node the named node to evaluate. - * @param {string} name - * @param {Modifiers} accessibility - * @returns {void} - * @private - */ - function validate( - node: TSESTree.Identifier | TSESTree.Expression, - name: string, - accessibility: Modifiers = 'public', - ): void { - const convention = conventions[accessibility]; - if (!convention || convention.test(name)) { - return; - } - - context.report({ - node, - messageId: 'incorrectName', - data: { accessibility, name, convention }, - }); - } - - return { - TSParameterProperty: validateParameterName, - MethodDefinition: validateName, - ClassProperty: validateName, - }; - }, -}); 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 5a07edc11c36..34fa2c7d6dc0 100644 --- a/packages/eslint-plugin/src/rules/no-base-to-string.ts +++ b/packages/eslint-plugin/src/rules/no-base-to-string.ts @@ -14,8 +14,6 @@ enum Usefulness { type Options = [ { - /** @deprecated This option is now ignored and treated as always true, it will be removed in 3.0 */ - ignoreTaggedTemplateExpressions?: boolean; ignoredTypeNames?: string[]; }, ]; @@ -39,10 +37,6 @@ export default util.createRule({ { type: 'object', properties: { - ignoreTaggedTemplateExpressions: { - type: 'boolean', - default: true, - }, ignoredTypeNames: { type: 'array', items: { @@ -57,7 +51,6 @@ export default util.createRule({ }, defaultOptions: [ { - ignoreTaggedTemplateExpressions: true, ignoredTypeNames: ['RegExp'], }, ], diff --git a/packages/eslint-plugin/src/rules/no-untyped-public-signature.ts b/packages/eslint-plugin/src/rules/no-untyped-public-signature.ts deleted file mode 100644 index cff725facc9c..000000000000 --- a/packages/eslint-plugin/src/rules/no-untyped-public-signature.ts +++ /dev/null @@ -1,125 +0,0 @@ -import * as util from '../util'; -import { - AST_NODE_TYPES, - TSESTree, -} from '@typescript-eslint/experimental-utils'; - -type MessageIds = 'noReturnType' | 'untypedParameter'; - -type Options = [{ ignoredMethods: string[] }]; - -export default util.createRule({ - name: 'no-untyped-public-signature', - meta: { - deprecated: true, - replacedBy: ['explicit-module-boundary-types'], - docs: { - description: 'Disallow untyped public methods', - category: 'Best Practices', - recommended: false, - }, - messages: { - noReturnType: 'Public method has no return type.', - untypedParameter: 'Public method parameters should be typed.', - }, - schema: [ - { - allowAdditionalProperties: false, - properties: { - ignoredMethods: { - type: 'array', - items: { - type: 'string', - }, - }, - }, - type: 'object', - }, - ], - type: 'suggestion', - }, - defaultOptions: [{ ignoredMethods: [] }], - create(context, [options]) { - const ignoredMethods = new Set(options.ignoredMethods); - - function isPublicMethod( - node: TSESTree.MethodDefinition | TSESTree.TSAbstractMethodDefinition, - ): boolean { - return node.accessibility === 'public' || !node.accessibility; - } - - function isIgnoredMethod( - node: TSESTree.MethodDefinition | TSESTree.TSAbstractMethodDefinition, - ignoredMethods: Set, - ): boolean { - if ( - node.key.type === AST_NODE_TYPES.Literal && - typeof node.key.value === 'string' - ) { - return ignoredMethods.has(node.key.value); - } - if ( - node.key.type === AST_NODE_TYPES.TemplateLiteral && - node.key.expressions.length === 0 - ) { - return ignoredMethods.has(node.key.quasis[0].value.raw); - } - if (!node.computed && node.key.type === AST_NODE_TYPES.Identifier) { - return ignoredMethods.has(node.key.name); - } - - return false; - } - - function isParamTyped(node: TSESTree.Identifier): boolean { - return ( - !!node.typeAnnotation && - node.typeAnnotation.typeAnnotation.type !== AST_NODE_TYPES.TSAnyKeyword - ); - } - - function isReturnTyped( - node: TSESTree.TSTypeAnnotation | undefined, - ): boolean { - if (!node) { - return false; - } - return ( - node.typeAnnotation && - node.typeAnnotation.type !== AST_NODE_TYPES.TSAnyKeyword - ); - } - - return { - 'TSAbstractMethodDefinition, MethodDefinition'( - node: TSESTree.MethodDefinition | TSESTree.TSAbstractMethodDefinition, - ): void { - if (isPublicMethod(node) && !isIgnoredMethod(node, ignoredMethods)) { - const paramIdentifiers = node.value.params.filter( - param => param.type === AST_NODE_TYPES.Identifier, - ) as TSESTree.Identifier[]; - const identifiersHaveTypes = paramIdentifiers.every(isParamTyped); - if (!identifiersHaveTypes) { - context.report({ - node, - messageId: 'untypedParameter', - data: {}, - }); - } - - if ( - node.kind !== 'constructor' && - node.kind !== 'set' && - !isReturnTyped(node.value.returnType) - ) { - context.report({ - node, - messageId: 'noReturnType', - data: {}, - }); - } - } - }, - }; - }, -}); diff --git a/packages/eslint-plugin/tests/docs.test.ts b/packages/eslint-plugin/tests/docs.test.ts index 9376af4daa5c..1d8ae897d31c 100644 --- a/packages/eslint-plugin/tests/docs.test.ts +++ b/packages/eslint-plugin/tests/docs.test.ts @@ -40,7 +40,10 @@ function parseReadme(): { describe('Validating rule docs', () => { it('All rules must have a corresponding rule doc', () => { - const files = fs.readdirSync(docsRoot); + const files = fs + .readdirSync(docsRoot) + // this rule doc was left behind on purpose for legacy reasons + .filter(rule => rule !== 'camelcase.md'); const ruleFiles = Object.keys(rules) .map(rule => `${rule}.md`) .sort(); diff --git a/packages/eslint-plugin/tests/rules/ban-ts-ignore.test.ts b/packages/eslint-plugin/tests/rules/ban-ts-ignore.test.ts deleted file mode 100644 index e1471950f464..000000000000 --- a/packages/eslint-plugin/tests/rules/ban-ts-ignore.test.ts +++ /dev/null @@ -1,66 +0,0 @@ -import rule from '../../src/rules/ban-ts-ignore'; -import { RuleTester } from '../RuleTester'; - -const ruleTester = new RuleTester({ - parser: '@typescript-eslint/parser', -}); - -ruleTester.run('ban-ts-ignore', rule, { - valid: [ - '// just a comment containing @ts-ignore somewhere', - '/* @ts-ignore */', - '/** @ts-ignore */', - ` -/* -// @ts-ignore in a block -*/ - `, - ], - invalid: [ - { - code: '// @ts-ignore', - errors: [ - { - messageId: 'tsIgnoreComment', - line: 1, - column: 1, - }, - ], - }, - { - code: '// @ts-ignore: Suppress next line', - errors: [ - { - messageId: 'tsIgnoreComment', - line: 1, - column: 1, - }, - ], - }, - { - code: '/////@ts-ignore: Suppress next line', - errors: [ - { - messageId: 'tsIgnoreComment', - line: 1, - column: 1, - }, - ], - }, - { - code: ` -if (false) { - // @ts-ignore: Unreachable code error - console.log('hello'); -} - `, - errors: [ - { - messageId: 'tsIgnoreComment', - line: 3, - column: 3, - }, - ], - }, - ], -}); diff --git a/packages/eslint-plugin/tests/rules/camelcase.test.ts b/packages/eslint-plugin/tests/rules/camelcase.test.ts deleted file mode 100644 index 1a35ee87cc82..000000000000 --- a/packages/eslint-plugin/tests/rules/camelcase.test.ts +++ /dev/null @@ -1,552 +0,0 @@ -import rule from '../../src/rules/camelcase'; -import { RuleTester, noFormat } from '../RuleTester'; - -const ruleTester = new RuleTester({ - parser: '@typescript-eslint/parser', -}); - -ruleTester.run('camelcase', rule, { - valid: [ - { - code: ` -interface Foo { - b_ar: number; -} - `, - options: [{ properties: 'never' }], - }, - { - code: ` -interface Foo { - bar: number; -} - `, - options: [{ properties: 'always' }], - }, - { - code: ` -class Foo { - b_ar: number; -} - `, - options: [{ properties: 'never' }], - }, - { - code: ` -class Foo { - bar: number; -} - `, - options: [{ properties: 'always' }], - }, - { - code: ` -class Foo { - b_ar: number = 0; -} - `, - options: [{ properties: 'never' }], - }, - { - code: ` -class Foo { - bar: number = 0; -} - `, - options: [{ properties: 'always' }], - }, - { - code: ` -class Foo { - constructor(private b_ar: number) {} -} - `, - options: [{ properties: 'never' }], - }, - { - code: ` -class Foo { - constructor(private bar: number) {} -} - `, - options: [{ properties: 'always' }], - }, - { - code: ` -class Foo { - constructor(private b_ar: number = 0) {} -} - `, - options: [{ properties: 'never' }], - }, - { - code: ` -class Foo { - constructor(private bar: number = 0) {} -} - `, - options: [{ properties: 'always' }], - }, - { - code: ` -abstract class Foo { - b_ar: number; -} - `, - options: [{ properties: 'never' }], - }, - { - code: ` -abstract class Foo { - bar: number; -} - `, - options: [{ properties: 'always' }], - }, - { - code: ` -abstract class Foo { - b_ar: number = 0; -} - `, - options: [{ properties: 'never' }], - }, - { - code: ` -abstract class Foo { - bar: number = 0; -} - `, - options: [{ properties: 'always' }], - }, - { - code: ` -abstract class Foo { - abstract b_ar: number; -} - `, - options: [{ properties: 'never' }], - }, - { - code: ` -abstract class Foo { - abstract bar: number; -} - `, - options: [{ properties: 'always' }], - }, - { - code: ` -abstract class Foo { - abstract b_ar: number = 0; -} - `, - options: [{ properties: 'never' }], - }, - { - code: ` -abstract class Foo { - abstract bar: number = 0; -} - `, - options: [{ properties: 'always' }], - }, - { - code: 'interface Foo {}', - options: [{ genericType: 'never' }], - }, - { - code: 'interface Foo {}', - options: [{ genericType: 'always' }], - }, - { - code: 'interface Foo {}', - options: [{ genericType: 'always' }], - }, - { - code: 'function fn() {}', - options: [{ genericType: 'never' }], - }, - { - code: 'function fn() {}', - options: [{ genericType: 'always' }], - }, - { - code: 'function fn() {}', - options: [{ genericType: 'always' }], - }, - { - code: 'class Foo {}', - options: [{ genericType: 'never' }], - }, - { - code: 'class Foo {}', - options: [{ genericType: 'always' }], - }, - { - code: 'class Foo {}', - options: [{ genericType: 'always' }], - }, - { - code: ` -class Foo { - method() {} -} - `, - options: [{ genericType: 'never' }], - }, - { - code: ` -class Foo { - method() {} -} - `, - options: [{ genericType: 'always' }], - }, - { - code: ` -class Foo { - method() {} -} - `, - options: [{ genericType: 'always' }], - }, - { - code: ` -type Foo = {}; - `, - options: [{ genericType: 'always' }], - }, - { - code: ` -type Foo = {}; - `, - options: [{ genericType: 'always' }], - }, - { - code: ` -type Foo = {}; - `, - options: [{ genericType: 'never' }], - }, - { - code: ` -class Foo { - FOO_method() {} -} - `, - options: [{ allow: ['^FOO'] }], - }, - { - code: ` -class Foo { - method() {} -} - `, - options: [{}], - }, - { - code: 'const foo = foo?.baz;', - }, - { - code: 'const foo = foo?.foo_bar?.foo_bar_baz;', - }, - { - code: 'const foo = foo.bar?.foo_bar_baz;', - }, - { - code: noFormat`const foo = (foo?.bar?.baz)?.foo_bar_baz;`, - }, - { - code: 'const foo = foo_bar?.foo;', - options: [{ properties: 'never' }], - }, - ], - - invalid: [ - { - code: ` -interface Foo { - b_ar: number; -} - `, - options: [{ properties: 'always' }], - errors: [ - { - messageId: 'notCamelCase', - data: { - name: 'b_ar', - }, - line: 3, - column: 3, - }, - ], - }, - { - code: ` -class Foo { - b_ar: number; -} - `, - options: [{ properties: 'always' }], - errors: [ - { - messageId: 'notCamelCase', - data: { - name: 'b_ar', - }, - line: 3, - column: 3, - }, - ], - }, - { - code: ` -class Foo { - constructor(private b_ar: number) {} -} - `, - options: [{ properties: 'always' }], - errors: [ - { - messageId: 'notCamelCase', - data: { - name: 'b_ar', - }, - line: 3, - column: 23, - }, - ], - }, - { - code: ` -class Foo { - constructor(private b_ar: number = 0) {} -} - `, - options: [{ properties: 'always' }], - errors: [ - { - messageId: 'notCamelCase', - data: { - name: 'b_ar', - }, - line: 3, - column: 23, - }, - ], - }, - { - code: ` -abstract class Foo { - b_ar: number; -} - `, - options: [{ properties: 'always' }], - errors: [ - { - messageId: 'notCamelCase', - data: { - name: 'b_ar', - }, - line: 3, - column: 3, - }, - ], - }, - { - code: ` -abstract class Foo { - b_ar: number = 0; -} - `, - options: [{ properties: 'always' }], - errors: [ - { - messageId: 'notCamelCase', - data: { - name: 'b_ar', - }, - line: 3, - column: 3, - }, - ], - }, - { - code: ` -abstract class Foo { - abstract b_ar: number; -} - `, - options: [{ properties: 'always' }], - errors: [ - { - messageId: 'notCamelCase', - data: { - name: 'b_ar', - }, - line: 3, - column: 12, - }, - ], - }, - { - code: ` -abstract class Foo { - abstract b_ar: number = 0; -} - `, - options: [{ properties: 'always' }], - errors: [ - { - messageId: 'notCamelCase', - data: { - name: 'b_ar', - }, - line: 3, - column: 12, - }, - ], - }, - { - code: 'const foo = foo_bar?.foo;', - options: [{ properties: 'always' }], - errors: [ - { - messageId: 'notCamelCase', - data: { - name: 'foo_bar', - }, - line: 1, - column: 13, - }, - ], - }, - { - code: noFormat`const foo = (foo_test?.bar)?.baz;`, - options: [{ properties: 'always' }], - errors: [ - { - messageId: 'notCamelCase', - data: { - name: 'foo_test', - }, - line: 1, - column: 14, - }, - ], - }, - { - code: 'interface Foo {}', - options: [{ genericType: 'always' }], - errors: [ - { - messageId: 'notCamelCase', - data: { - name: 't_foo', - }, - line: 1, - column: 15, - }, - ], - }, - { - code: 'function fn() {}', - options: [{ genericType: 'always' }], - errors: [ - { - messageId: 'notCamelCase', - data: { - name: 't_foo', - }, - line: 1, - column: 13, - }, - ], - }, - { - code: 'class Foo {}', - options: [{ genericType: 'always' }], - errors: [ - { - messageId: 'notCamelCase', - data: { - name: 't_foo', - }, - line: 1, - column: 11, - }, - ], - }, - { - code: ` -class Foo { - method() {} -} - `, - options: [{ genericType: 'always' }], - errors: [ - { - messageId: 'notCamelCase', - data: { - name: 't_foo', - }, - line: 3, - column: 10, - }, - ], - }, - { - code: ` -class Foo { - method() {} -} - `, - options: [{ genericType: 'always' }], - errors: [ - { - messageId: 'notCamelCase', - data: { - name: 't_foo', - }, - line: 3, - column: 10, - }, - { - messageId: 'notCamelCase', - data: { - name: 't_bar', - }, - line: 3, - column: 24, - }, - ], - }, - { - code: ` -class Foo { - method() {} -} - `, - options: [{ genericType: 'always' }], - errors: [ - { - messageId: 'notCamelCase', - data: { - name: 't_foo', - }, - line: 3, - column: 10, - }, - { - messageId: 'notCamelCase', - data: { - name: 't_bar', - }, - line: 3, - column: 18, - }, - ], - }, - ], -}); diff --git a/packages/eslint-plugin/tests/rules/class-name-casing.test.ts b/packages/eslint-plugin/tests/rules/class-name-casing.test.ts deleted file mode 100644 index 1977a36415da..000000000000 --- a/packages/eslint-plugin/tests/rules/class-name-casing.test.ts +++ /dev/null @@ -1,196 +0,0 @@ -import rule from '../../src/rules/class-name-casing'; -import { RuleTester } from '../RuleTester'; - -const ruleTester = new RuleTester({ - parser: '@typescript-eslint/parser', -}); - -ruleTester.run('class-name-casing', rule, { - valid: [ - 'class ValidClassName {}', - { - code: 'export default class {}', - parserOptions: { - sourceType: 'module', - }, - }, - { - code: 'class _NameWithUnderscore {}', - options: [{ allowUnderscorePrefix: true }], - }, - { - code: 'class Foo {}', - options: [{ allowUnderscorePrefix: true }], - }, - { - code: 'class _ÈFoo {}', - options: [{ allowUnderscorePrefix: true }], - }, - 'var Foo = class {};', - 'interface SomeInterface {}', - 'class ClassNameWithDigit2 {}', - 'abstract class ClassNameWithDigit2 {}', - 'var ba_zz = class Foo {};', - 'class ClassNameWithUnicodeÈ {}', - 'class ÈClassNameWithUnicode {}', - 'class ClassNameWithæUnicode {}', - // Following test cases are valid, but no one is going to write code like this - ` -var { bar } = class { - static bar() { - return 2; - } -}; - `, - ` -var [bar] = class { - static [Symbol.iterator]() { - return { next: () => ({ value: 1, done: false }) }; - } -}; - `, - ], - - invalid: [ - { - code: 'class invalidClassName {}', - errors: [ - { - messageId: 'notPascalCased', - data: { - friendlyName: 'Class', - name: 'invalidClassName', - }, - line: 1, - column: 7, - }, - ], - }, - { - code: 'class Another_Invalid_Class_Name {}', - errors: [ - { - messageId: 'notPascalCased', - data: { - friendlyName: 'Class', - name: 'Another_Invalid_Class_Name', - }, - line: 1, - column: 7, - }, - ], - }, - { - code: 'class _NameWithUnderscore {}', - errors: [ - { - messageId: 'notPascalCased', - data: { - friendlyName: 'Class', - name: '_NameWithUnderscore', - }, - line: 1, - column: 7, - }, - ], - }, - { - code: 'var foo = class {};', - errors: [ - { - messageId: 'notPascalCased', - data: { - friendlyName: 'Class', - name: 'foo', - }, - line: 1, - column: 5, - }, - ], - }, - { - code: 'const foo = class {};', - errors: [ - { - messageId: 'notPascalCased', - data: { - friendlyName: 'Class', - name: 'foo', - }, - line: 1, - column: 7, - }, - ], - }, - { - code: 'var bar = class invalidName {};', - errors: [ - { - messageId: 'notPascalCased', - data: { - friendlyName: 'Class', - name: 'invalidName', - }, - line: 1, - column: 17, - }, - ], - }, - { - code: 'interface someInterface {}', - errors: [ - { - messageId: 'notPascalCased', - data: { - friendlyName: 'Interface', - name: 'someInterface', - }, - line: 1, - column: 11, - }, - ], - }, - { - code: 'abstract class invalidClassName {}', - errors: [ - { - messageId: 'notPascalCased', - data: { - friendlyName: 'Abstract class', - name: 'invalidClassName', - }, - line: 1, - column: 16, - }, - ], - }, - { - code: 'declare class invalidClassName {}', - errors: [ - { - messageId: 'notPascalCased', - data: { - friendlyName: 'Class', - name: 'invalidClassName', - }, - line: 1, - column: 15, - }, - ], - }, - { - code: 'class æInvalidClassNameWithUnicode {}', - errors: [ - { - messageId: 'notPascalCased', - data: { - friendlyName: 'Class', - name: 'æInvalidClassNameWithUnicode', - }, - line: 1, - column: 7, - }, - ], - }, - ], -}); diff --git a/packages/eslint-plugin/tests/rules/generic-type-naming.test.ts b/packages/eslint-plugin/tests/rules/generic-type-naming.test.ts deleted file mode 100644 index da26e9675b64..000000000000 --- a/packages/eslint-plugin/tests/rules/generic-type-naming.test.ts +++ /dev/null @@ -1,207 +0,0 @@ -import rule from '../../src/rules/generic-type-naming'; -import { RuleTester } from '../RuleTester'; - -const ruleTester = new RuleTester({ - parser: '@typescript-eslint/parser', -}); - -ruleTester.run('generic-type-naming', rule, { - valid: [ - { - code: 'class {}', - options: [], - }, - { - code: 'type ReadOnly = {};', - options: [], - }, - { - code: 'interface SimpleMap {}', - options: [], - }, - { - code: 'function get() {}', - options: [], - }, - { - code: ` -interface GenericIdentityFn { - (arg: T): T; -} - `, - options: [], - }, - { - code: 'class {}', - options: ['^x+$'], - }, - { - code: 'class {}', - options: ['^[A-Z]$'], - }, - { - code: 'class extends B implements Foo {}', - options: ['^[A-Z]$'], - }, - { - code: ` -class extends B implements Foo { - test() { - type Foo = Bar; - } -} - `, - options: ['^[A-Z]$'], - }, - { - code: 'class CounterContainer extends Container {}', - options: ['^T$'], - }, - ], - invalid: [ - { - code: 'class {}', - options: [], - errors: [ - { - messageId: 'paramNotMatchRule', - data: { name: 'U', rule: '^T([A-Z0-9][a-zA-Z0-9]*){0,1}$' }, - }, - { - messageId: 'paramNotMatchRule', - data: { name: 'V', rule: '^T([A-Z0-9][a-zA-Z0-9]*){0,1}$' }, - }, - ], - }, - { - code: 'class {}', - options: ['^[A-Z]+$'], - errors: [ - { - messageId: 'paramNotMatchRule', - data: { name: 'x', rule: '^[A-Z]+$' }, - line: 1, - column: 7, - }, - ], - }, - { - code: 'interface SimpleMap {}', - options: ['^[A-Z]+$'], - errors: [ - { - messageId: 'paramNotMatchRule', - data: { name: 'x', rule: '^[A-Z]+$' }, - line: 1, - column: 21, - }, - ], - }, - { - code: 'type R = {};', - options: ['^[A-Z]+$'], - errors: [ - { - messageId: 'paramNotMatchRule', - data: { name: 'x', rule: '^[A-Z]+$' }, - line: 1, - column: 8, - }, - ], - }, - { - code: 'function get() {}', - options: ['^[A-Z]+$'], - errors: [ - { - messageId: 'paramNotMatchRule', - data: { name: 'x', rule: '^[A-Z]+$' }, - line: 1, - column: 14, - }, - ], - }, - { - code: ` -interface GenericIdentityFn { - (arg: x): x; -} - `, - options: ['^[A-Z]+$'], - errors: [ - { - messageId: 'paramNotMatchRule', - data: { name: 'x', rule: '^[A-Z]+$' }, - line: 3, - column: 4, - }, - ], - }, - { - code: ` -class extends B implements Foo { - test() { - type Foo = Bar; - } -} - `, - options: ['^[A-Z][0-9]$'], - errors: [ - { - messageId: 'paramNotMatchRule', - data: { name: 'A', rule: '^[A-Z][0-9]$' }, - line: 2, - column: 7, - }, - { - messageId: 'paramNotMatchRule', - data: { name: 'Z', rule: '^[A-Z][0-9]$' }, - line: 3, - column: 8, - }, - { - messageId: 'paramNotMatchRule', - data: { name: 'T', rule: '^[A-Z][0-9]$' }, - line: 4, - column: 14, - }, - ], - }, - { - code: ` -abstract class extends B implements Foo { - test() { - type Foo = Bar; - } -} - `, - options: ['^[A-Z][0-9]$'], - errors: [ - { - messageId: 'paramNotMatchRule', - data: { name: 'A', rule: '^[A-Z][0-9]$' }, - line: 2, - column: 16, - }, - { - messageId: 'paramNotMatchRule', - data: { name: 'B', rule: '^[A-Z][0-9]$' }, - line: 2, - column: 19, - }, - { - messageId: 'paramNotMatchRule', - data: { name: 'Z', rule: '^[A-Z][0-9]$' }, - line: 3, - column: 8, - }, - { - messageId: 'paramNotMatchRule', - data: { name: 'T', rule: '^[A-Z][0-9]$' }, - line: 4, - column: 14, - }, - ], - }, - ], -}); diff --git a/packages/eslint-plugin/tests/rules/interface-name-prefix.test.ts b/packages/eslint-plugin/tests/rules/interface-name-prefix.test.ts deleted file mode 100644 index 23c58a4687a0..000000000000 --- a/packages/eslint-plugin/tests/rules/interface-name-prefix.test.ts +++ /dev/null @@ -1,191 +0,0 @@ -import rule, { parseOptions } from '../../src/rules/interface-name-prefix'; -import { RuleTester } from '../RuleTester'; - -describe('interface-name-prefix', () => { - it('parseOptions', () => { - expect(parseOptions(['never'])).toEqual({ prefixWithI: 'never' }); - expect(parseOptions(['always'])).toEqual({ - prefixWithI: 'always', - allowUnderscorePrefix: false, - }); - expect(parseOptions([{}])).toEqual({ prefixWithI: 'never' }); - expect(parseOptions([{ prefixWithI: 'never' }])).toEqual({ - prefixWithI: 'never', - }); - expect(parseOptions([{ prefixWithI: 'always' }])).toEqual({ - prefixWithI: 'always', - allowUnderscorePrefix: false, - }); - expect( - parseOptions([{ prefixWithI: 'always', allowUnderscorePrefix: true }]), - ).toEqual({ prefixWithI: 'always', allowUnderscorePrefix: true }); - }); -}); - -const ruleTester = new RuleTester({ - parser: '@typescript-eslint/parser', -}); - -ruleTester.run('interface-name-prefix', rule, { - valid: [ - ` -interface Animal { - name: string; -} - `, - { - code: ` -interface IAnimal { - name: string; -} - `, - options: ['always'], - }, - { - code: ` -interface _IAnimal { - name: string; -} - `, - options: [{ prefixWithI: 'always', allowUnderscorePrefix: true }], - }, - { - code: ` -interface IIguana { - name: string; -} - `, - options: ['always'], - }, - { - code: ` -interface Iguana { - name: string; -} - `, - options: ['never'], - }, - { - code: ` -interface Animal { - name: string; -} - `, - options: ['never'], - }, - { - code: ` -interface I18n { - name: string; -} - `, - options: ['never'], - }, - ], - invalid: [ - { - code: ` -interface IAnimal { - name: string; -} - `, - errors: [ - { - messageId: 'noPrefix', - line: 2, - column: 11, - }, - ], - }, - { - code: ` -interface Animal { - name: string; -} - `, - options: ['always'], - errors: [ - { - messageId: 'alwaysPrefix', - line: 2, - column: 11, - }, - ], - }, - { - code: ` -interface Animal { - name: string; -} - `, - options: [{ prefixWithI: 'always', allowUnderscorePrefix: true }], - errors: [ - { - messageId: 'alwaysPrefix', - line: 2, - column: 11, - }, - ], - }, - { - code: ` -interface Iguana { - name: string; -} - `, - options: ['always'], - errors: [ - { - messageId: 'alwaysPrefix', - line: 2, - column: 11, - }, - ], - }, - { - code: ` -interface IIguana { - name: string; -} - `, - options: ['never'], - errors: [ - { - messageId: 'noPrefix', - line: 2, - column: 11, - }, - ], - }, - { - code: ` -interface IAnimal { - name: string; -} - `, - options: ['never'], - errors: [ - { - messageId: 'noPrefix', - line: 2, - column: 11, - }, - ], - }, - { - code: ` -interface _IAnimal { - name: string; -} - `, - options: ['never'], - errors: [ - { - messageId: 'noPrefix', - line: 2, - column: 11, - }, - ], - }, - ], -}); diff --git a/packages/eslint-plugin/tests/rules/member-naming.test.ts b/packages/eslint-plugin/tests/rules/member-naming.test.ts deleted file mode 100644 index e3befcffbe1a..000000000000 --- a/packages/eslint-plugin/tests/rules/member-naming.test.ts +++ /dev/null @@ -1,453 +0,0 @@ -import rule from '../../src/rules/member-naming'; -import { RuleTester } from '../RuleTester'; - -const ruleTester = new RuleTester({ - parser: '@typescript-eslint/parser', -}); - -ruleTester.run('member-naming', rule, { - valid: [ - { - code: ` -class Class { - _fooBar() {} -} - `, - options: [{ public: '^_' }], - }, - { - code: ` -class Class { - private constructor(); - _fooBar() {} -} - `, - options: [{ private: '^_' }], - }, - { - code: ` -class Class { - constructor() {} - _fooBar() {} -} - `, - options: [{ public: '^_' }], - }, - { - code: ` -class Class { - public _fooBar() {} -} - `, - options: [{ public: '^_' }], - }, - { - code: ` -class Class { - protected _fooBar() {} -} - `, - options: [{ protected: '^_' }], - }, - { - code: ` -class Class { - private _fooBar() {} -} - `, - options: [{ private: '^_' }], - }, - { - code: ` -class Class { - protected fooBar() {} -} - `, - options: [{ private: '^_' }], - }, - { - code: ` -class Class { - pubOne() {} - public pubTwo() {} - protected protThree() {} - private privFour() {} -} - `, - options: [ - { - public: '^pub[A-Z]', - protected: '^prot[A-Z]', - private: '^priv[A-Z]', - }, - ], - }, - { - code: ` -class Class { - pubOne: string; - public pubTwo: string; - protected protThree: string; - private privFour: string; -} - `, - options: [ - { - public: '^pub[A-Z]', - protected: '^prot[A-Z]', - private: '^priv[A-Z]', - }, - ], - }, - { - code: ` -class Class { - pubOne = true; - public pubTwo = true; - protected protThree = true; - private privFour = true; -} - `, - options: [ - { - public: '^pub[A-Z]', - protected: '^prot[A-Z]', - private: '^priv[A-Z]', - }, - ], - }, - - { - code: ` -class Test { - constructor( - public __a: string, - protected __b: string, - private __c: string = 100, - ) {} -} - `, - options: [ - { - protected: '^__', - private: '^__', - public: '^__', - }, - ], - }, - { - code: - // Semantically invalid test case, TS has to throw an error. - ` -class Foo { - constructor(private ...name: string[], private [test]: [string]) {} -} - `, - }, - ], - invalid: [ - { - code: ` -class Class { - fooBar() {} -} - `, - options: [{ public: '^_' }], - errors: [ - { - messageId: 'incorrectName', - data: { - accessibility: 'public', - convention: '/^_/', - name: 'fooBar', - }, - line: 3, - column: 3, - }, - ], - }, - { - code: ` -class Class { - public fooBar() {} -} - `, - options: [{ public: '^_' }], - errors: [ - { - messageId: 'incorrectName', - data: { - accessibility: 'public', - convention: '/^_/', - name: 'fooBar', - }, - line: 3, - column: 10, - }, - ], - }, - { - code: ` -class Class { - protected fooBar() {} -} - `, - options: [{ protected: '^_' }], - errors: [ - { - messageId: 'incorrectName', - data: { - accessibility: 'protected', - convention: '/^_/', - name: 'fooBar', - }, - line: 3, - column: 13, - }, - ], - }, - { - code: ` -class Class { - private fooBar() {} -} - `, - options: [{ private: '^_' }], - errors: [ - { - messageId: 'incorrectName', - data: { - accessibility: 'private', - convention: '/^_/', - name: 'fooBar', - }, - line: 3, - column: 11, - }, - ], - }, - { - code: ` -class Class { - one() {} - public two() {} - protected three() {} - private four() {} -} - `, - options: [ - { - public: '^pub[A-Z]', - protected: '^prot[A-Z]', - private: '^priv[A-Z]', - }, - ], - errors: [ - { - messageId: 'incorrectName', - data: { - accessibility: 'public', - convention: '/^pub[A-Z]/', - name: 'one', - }, - line: 3, - column: 3, - }, - { - messageId: 'incorrectName', - data: { - accessibility: 'public', - convention: '/^pub[A-Z]/', - name: 'two', - }, - line: 4, - column: 10, - }, - { - messageId: 'incorrectName', - data: { - accessibility: 'protected', - convention: '/^prot[A-Z]/', - name: 'three', - }, - line: 5, - column: 13, - }, - { - messageId: 'incorrectName', - data: { - accessibility: 'private', - convention: '/^priv[A-Z]/', - name: 'four', - }, - line: 6, - column: 11, - }, - ], - }, - { - code: ` -class Class { - one: string; - public two: string; - protected three: string; - private four: string; -} - `, - options: [ - { - public: '^pub[A-Z]', - protected: '^prot[A-Z]', - private: '^priv[A-Z]', - }, - ], - errors: [ - { - messageId: 'incorrectName', - data: { - accessibility: 'public', - convention: '/^pub[A-Z]/', - name: 'one', - }, - line: 3, - column: 3, - }, - { - messageId: 'incorrectName', - data: { - accessibility: 'public', - convention: '/^pub[A-Z]/', - name: 'two', - }, - line: 4, - column: 10, - }, - { - messageId: 'incorrectName', - data: { - accessibility: 'protected', - convention: '/^prot[A-Z]/', - name: 'three', - }, - line: 5, - column: 13, - }, - { - messageId: 'incorrectName', - data: { - accessibility: 'private', - convention: '/^priv[A-Z]/', - name: 'four', - }, - line: 6, - column: 11, - }, - ], - }, - { - code: ` -class Class { - one = true; - public two = true; - protected three = true; - private four = true; -} - `, - options: [ - { - public: '^pub[A-Z]', - protected: '^prot[A-Z]', - private: '^priv[A-Z]', - }, - ], - errors: [ - { - messageId: 'incorrectName', - data: { - accessibility: 'public', - convention: '/^pub[A-Z]/', - name: 'one', - }, - line: 3, - column: 3, - }, - { - messageId: 'incorrectName', - data: { - accessibility: 'public', - convention: '/^pub[A-Z]/', - name: 'two', - }, - line: 4, - column: 10, - }, - { - messageId: 'incorrectName', - data: { - accessibility: 'protected', - convention: '/^prot[A-Z]/', - name: 'three', - }, - line: 5, - column: 13, - }, - { - messageId: 'incorrectName', - data: { - accessibility: 'private', - convention: '/^priv[A-Z]/', - name: 'four', - }, - line: 6, - column: 11, - }, - ], - }, - { - code: ` -class Test { - constructor(public a: string, protected b: string, private c: string = 100) {} -} - `, - options: [ - { - public: '^__', - protected: '^__', - private: '^__', - }, - ], - errors: [ - { - messageId: 'incorrectName', - data: { - accessibility: 'public', - convention: '/^__/', - name: 'a', - }, - line: 3, - column: 22, - }, - { - messageId: 'incorrectName', - data: { - accessibility: 'protected', - convention: '/^__/', - name: 'b', - }, - line: 3, - column: 43, - }, - { - messageId: 'incorrectName', - data: { - accessibility: 'private', - convention: '/^__/', - name: 'c', - }, - line: 3, - column: 62, - }, - ], - }, - ], -}); 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 99d949437670..86babb99ae1f 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 @@ -103,17 +103,10 @@ printer(true); function tag() {} tag\`\${{}}\`; `, - { - code: ` - function tag() {} - tag\`\${{}}\`; - `, - options: [ - { - ignoreTaggedTemplateExpressions: true, - }, - ], - }, + ` + function tag() {} + tag\`\${{}}\`; + `, ], invalid: [ { diff --git a/packages/eslint-plugin/tests/rules/no-untyped-public-signature.test.ts b/packages/eslint-plugin/tests/rules/no-untyped-public-signature.test.ts deleted file mode 100644 index d71b98ce3c10..000000000000 --- a/packages/eslint-plugin/tests/rules/no-untyped-public-signature.test.ts +++ /dev/null @@ -1,305 +0,0 @@ -import rule from '../../src/rules/no-untyped-public-signature'; -import { RuleTester } from '../RuleTester'; - -const ruleTester = new RuleTester({ - parserOptions: { - ecmaVersion: 6, - sourceType: 'module', - ecmaFeatures: {}, - }, - parser: '@typescript-eslint/parser', -}); - -ruleTester.run('no-untyped-public-signature', rule, { - valid: [ - { - code: ` -class A { - private a(c) {} -} - `, - }, - { - code: ` -class A { - private async a(c) {} -} - `, - }, - { - code: ` -class A { - public b(c: string): void {} -} - `, - }, - { - code: ` -class A { - public b(...c): void {} -} - `, - }, - { - code: ` -class A { - b(c): void {} -} - `, - options: [{ ignoredMethods: ['b'] }], - }, - { - code: ` -class A { - ['b'](c): void {} -} - `, - options: [{ ignoredMethods: ['b'] }], - }, - { - code: ` -class A { - [\`b\`](c): void {} -} - `, - options: [{ ignoredMethods: ['b'] }], - }, - { - code: ` -class A { - b(...c): void {} - - d(c): void {} -} - `, - options: [{ ignoredMethods: ['b', 'd'] }], - }, - // https://github.com/typescript-eslint/typescript-eslint/issues/1229 - ` -class Foo { - constructor() {} -} - `, - ` -class Foo { - abstract constructor() {} -} - `, - ` -class Foo { - constructor(c: string) {} -} - `, - ` -class Foo { - abstract constructor(c: string) {} -} - `, - - // https://github.com/typescript-eslint/typescript-eslint/issues/1263 - ` -class Foo { - private _x: string; - - public get x(): string { - return this._x; - } - - public set x(x: string) { - this._x = x; - } -} - `, - ` -class Foo { - private _x: string; - - get x(): string { - return this._x; - } - - set x(x: string) { - this._x = x; - } -} - `, - ], - invalid: [ - //untyped parameter - { - code: ` -class A { - public b(c): void {} -} - `, - errors: [{ messageId: 'untypedParameter' }], - }, - //untyped parameter (any) - { - code: ` -class A { - public b(c: any): void {} -} - `, - errors: [{ messageId: 'untypedParameter' }], - }, - //implicit public method - { - code: ` -class A { - b(c): void {} -} - `, - errors: [{ messageId: 'untypedParameter' }], - }, - //implicit async public method - { - code: ` -class A { - async a(c): void {} -} - `, - errors: [{ messageId: 'untypedParameter' }], - }, - //no return type - { - code: ` -class A { - public a(c: number) {} -} - `, - errors: [{ messageId: 'noReturnType' }], - }, - //no return type + untyped parameter - { - code: ` -class A { - public b(c) {} -} - `, - errors: [ - { messageId: 'untypedParameter' }, - { messageId: 'noReturnType' }, - ], - }, - //any return type - { - code: ` -class A { - public b(c: number): any {} -} - `, - errors: [{ messageId: 'noReturnType' }], - }, - //with ignored methods - { - code: ` -class A { - public b(c: number): any {} - - c() {} -} - `, - options: [{ ignoredMethods: ['c'] }], - errors: [{ messageId: 'noReturnType' }], - }, - { - code: ` -let c = 'd'; -class A { - [methodName]() {} -} - `, - options: [{ ignoredMethods: ['methodName'] }], - errors: [{ messageId: 'noReturnType' }], - }, - { - code: ` -class A { - [1]() {} -} - `, - options: [{ ignoredMethods: ['1'] }], - errors: [{ messageId: 'noReturnType' }], - }, - { - code: ` -let c = 'C'; -class A { - [\`methodName\${c}\`]() {} -} - `, - options: [{ ignoredMethods: ['methodNameC', 'methodNamec'] }], - errors: [{ messageId: 'noReturnType' }], - }, - { - code: ` -let c = '1'; -class A { - [c as number]() {} -} - `, - options: [{ ignoredMethods: ['1'] }], - errors: [{ messageId: 'noReturnType' }], - }, - { - code: ` -class A { - abstract c() {} -} - `, - errors: [{ messageId: 'noReturnType' }], - }, - // https://github.com/typescript-eslint/typescript-eslint/issues/1229 - { - code: ` -class Foo { - constructor(c) {} -} - `, - errors: [{ messageId: 'untypedParameter' }], - }, - { - code: ` -class Foo { - abstract constructor(c) {} -} - `, - errors: [{ messageId: 'untypedParameter' }], - }, - - // https://github.com/typescript-eslint/typescript-eslint/issues/1263 - { - code: ` -class Foo { - private _x: string; - - public get x(): string { - return this._x; - } - - public set x(x) { - this._x = x; - } -} - `, - errors: [{ messageId: 'untypedParameter' }], - }, - { - code: ` -class Foo { - private _x: string; - - get x(): string { - return this._x; - } - - set x(x) { - this._x = x; - } -} - `, - errors: [{ messageId: 'untypedParameter' }], - }, - ], -}); From 3626a673cf8117cc995245cd86e466e2553e9b0e Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Sun, 10 May 2020 13:40:09 -0700 Subject: [PATCH 19/33] feat(eslint-plugin): [no-floating-promises] ignore void operator by default (#2003) --- .../docs/rules/no-floating-promises.md | 5 +- .../src/rules/no-floating-promises.ts | 2 +- .../tests/rules/no-floating-promises.test.ts | 105 +++++++++--------- 3 files changed, 58 insertions(+), 54 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/no-floating-promises.md b/packages/eslint-plugin/docs/rules/no-floating-promises.md index 9ed1f23455ae..bda8c26b7855 100644 --- a/packages/eslint-plugin/docs/rules/no-floating-promises.md +++ b/packages/eslint-plugin/docs/rules/no-floating-promises.md @@ -56,7 +56,8 @@ type Options = { }; const defaults = { - ignoreVoid: false, + ignoreVoid: true, + ignoreIIFE: false, }; ``` @@ -76,6 +77,8 @@ void returnsPromise(); void Promise.reject('value'); ``` +With this option set to `true`, and if you are using `no-void`, you should turn on the [`allowAsAStatement`](https://eslint.org/docs/rules/no-void#allowasstatement) option. + ### `ignoreIIFE` This allows you to skip checking of async iife diff --git a/packages/eslint-plugin/src/rules/no-floating-promises.ts b/packages/eslint-plugin/src/rules/no-floating-promises.ts index 2a0c86e5011e..deb4ee5c00f9 100644 --- a/packages/eslint-plugin/src/rules/no-floating-promises.ts +++ b/packages/eslint-plugin/src/rules/no-floating-promises.ts @@ -48,7 +48,7 @@ export default util.createRule({ }, defaultOptions: [ { - ignoreVoid: false, + ignoreVoid: true, ignoreIIFE: false, }, ], diff --git a/packages/eslint-plugin/tests/rules/no-floating-promises.test.ts b/packages/eslint-plugin/tests/rules/no-floating-promises.test.ts index e5c0ea5210f7..e7dfe710f15d 100644 --- a/packages/eslint-plugin/tests/rules/no-floating-promises.test.ts +++ b/packages/eslint-plugin/tests/rules/no-floating-promises.test.ts @@ -398,19 +398,19 @@ async function test() { errors: [ { line: 3, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 4, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 5, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 6, - messageId: 'floating', + messageId: 'floatingVoid', }, ], }, @@ -450,19 +450,19 @@ async function test() { errors: [ { line: 3, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 4, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 5, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 6, - messageId: 'floating', + messageId: 'floatingVoid', }, ], }, @@ -478,19 +478,19 @@ async function test() { errors: [ { line: 3, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 4, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 5, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 6, - messageId: 'floating', + messageId: 'floatingVoid', }, ], }, @@ -508,19 +508,19 @@ async function test() { errors: [ { line: 5, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 6, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 7, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 8, - messageId: 'floating', + messageId: 'floatingVoid', }, ], }, @@ -534,11 +534,11 @@ async function test() { errors: [ { line: 3, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 4, - messageId: 'floating', + messageId: 'floatingVoid', }, ], }, @@ -553,15 +553,15 @@ async function test() { errors: [ { line: 3, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 4, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 5, - messageId: 'floating', + messageId: 'floatingVoid', }, ], }, @@ -571,6 +571,7 @@ async function test() { void Promise.resolve(); } `, + options: [{ ignoreVoid: false }], errors: [ { line: 3, @@ -588,7 +589,7 @@ async function test() { errors: [ { line: 4, - messageId: 'floating', + messageId: 'floatingVoid', }, ], }, @@ -601,7 +602,7 @@ async function test() { errors: [ { line: 3, - messageId: 'floating', + messageId: 'floatingVoid', }, ], }, @@ -619,19 +620,19 @@ async function test() { errors: [ { line: 5, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 6, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 7, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 8, - messageId: 'floating', + messageId: 'floatingVoid', }, ], }, @@ -646,7 +647,7 @@ async function test() { errors: [ { line: 5, - messageId: 'floating', + messageId: 'floatingVoid', }, ], }, @@ -664,19 +665,19 @@ async function test() { errors: [ { line: 5, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 6, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 7, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 8, - messageId: 'floating', + messageId: 'floatingVoid', }, ], }, @@ -695,19 +696,19 @@ async function test() { errors: [ { line: 6, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 7, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 8, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 9, - messageId: 'floating', + messageId: 'floatingVoid', }, ], }, @@ -728,11 +729,11 @@ async function test() { errors: [ { line: 10, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 11, - messageId: 'floating', + messageId: 'floatingVoid', }, ], }, @@ -762,15 +763,15 @@ async function test() { errors: [ { line: 18, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 19, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 20, - messageId: 'floating', + messageId: 'floatingVoid', }, ], }, @@ -783,7 +784,7 @@ async function test() { errors: [ { line: 2, - messageId: 'floating', + messageId: 'floatingVoid', }, ], }, @@ -796,7 +797,7 @@ async function test() { errors: [ { line: 2, - messageId: 'floating', + messageId: 'floatingVoid', }, ], }, @@ -805,7 +806,7 @@ async function test() { errors: [ { line: 1, - messageId: 'floating', + messageId: 'floatingVoid', }, ], }, @@ -818,7 +819,7 @@ async function test() { errors: [ { line: 3, - messageId: 'floating', + messageId: 'floatingVoid', }, ], }, @@ -834,7 +835,7 @@ async function test() { errors: [ { line: 4, - messageId: 'floating', + messageId: 'floatingVoid', }, ], }, @@ -847,7 +848,7 @@ async function test() { errors: [ { line: 2, - messageId: 'floating', + messageId: 'floatingVoid', }, ], }, @@ -861,7 +862,7 @@ async function test() { errors: [ { line: 3, - messageId: 'floating', + messageId: 'floatingVoid', }, ], }, @@ -879,19 +880,19 @@ async function test() { errors: [ { line: 4, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 5, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 6, - messageId: 'floating', + messageId: 'floatingVoid', }, { line: 7, - messageId: 'floating', + messageId: 'floatingVoid', }, ], }, From 643ec240bd901295d9e9ea5c43fc20109c33e982 Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Sun, 10 May 2020 14:16:31 -0700 Subject: [PATCH 20/33] feat(eslint-plugin): [restrict-template-expressions] `allowNumber: true` by default (#2005) --- .../docs/rules/restrict-template-expressions.md | 2 +- .../src/rules/restrict-template-expressions.ts | 6 +++++- .../tests/rules/restrict-template-expressions.test.ts | 2 ++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/restrict-template-expressions.md b/packages/eslint-plugin/docs/rules/restrict-template-expressions.md index 4bb2a062ad94..260a8eb188dd 100644 --- a/packages/eslint-plugin/docs/rules/restrict-template-expressions.md +++ b/packages/eslint-plugin/docs/rules/restrict-template-expressions.md @@ -38,7 +38,7 @@ type Options = { }; const defaults = { - allowNumber: false, + allowNumber: true, allowBoolean: false, allowAny: false, allowNullable: false, diff --git a/packages/eslint-plugin/src/rules/restrict-template-expressions.ts b/packages/eslint-plugin/src/rules/restrict-template-expressions.ts index aeda73af5216..dd030cf5bc08 100644 --- a/packages/eslint-plugin/src/rules/restrict-template-expressions.ts +++ b/packages/eslint-plugin/src/rules/restrict-template-expressions.ts @@ -41,7 +41,11 @@ export default util.createRule({ }, ], }, - defaultOptions: [{}], + defaultOptions: [ + { + allowNumber: true, + }, + ], create(context, [options]) { const service = util.getParserServices(context); const typeChecker = service.program.getTypeChecker(); diff --git a/packages/eslint-plugin/tests/rules/restrict-template-expressions.test.ts b/packages/eslint-plugin/tests/rules/restrict-template-expressions.test.ts index b0b3069062d2..2d1a7422183f 100644 --- a/packages/eslint-plugin/tests/rules/restrict-template-expressions.test.ts +++ b/packages/eslint-plugin/tests/rules/restrict-template-expressions.test.ts @@ -206,6 +206,7 @@ ruleTester.run('restrict-template-expressions', rule, { code: ` const msg = \`arg = \${123}\`; `, + options: [{ allowNumber: false }], errors: [ { messageId: 'invalidType', @@ -246,6 +247,7 @@ ruleTester.run('restrict-template-expressions', rule, { declare const arg: number; const msg = \`arg = \${arg}\`; `, + options: [{ allowNumber: false }], errors: [ { messageId: 'invalidType', From 7fa906073903c5eb70609c25f1a91ada14dcdc71 Mon Sep 17 00:00:00 2001 From: Retsam Date: Sun, 10 May 2020 20:34:01 -0400 Subject: [PATCH 21/33] feat(eslint-plugin): [no-unnecessary-condition] report when non-nullish is compared to `null`/`undefined` (#1659) --- .../src/rules/no-unnecessary-condition.ts | 45 +++++++++++++++---- .../rules/no-unnecessary-condition.test.ts | 31 +++++++++++++ 2 files changed, 68 insertions(+), 8 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts b/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts index 919e182a7490..85503bbfa7fa 100644 --- a/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts +++ b/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts @@ -11,6 +11,7 @@ import { isBooleanLiteralType, isLiteralType, getCallSignaturesOfType, + isStrictCompilerOptionEnabled, } from 'tsutils'; import { createRule, @@ -21,6 +22,9 @@ import { NullThrowsReasons, } from '../util'; +const typeContainsFlag = (type: ts.Type, flag: ts.TypeFlags): boolean => { + return unionTypeParts(type).some(t => isTypeFlagSet(t, flag)); +}; // Truthiness utilities // #region const isTruthyLiteral = (type: ts.Type): boolean => @@ -72,6 +76,7 @@ export type MessageId = | 'neverNullish' | 'alwaysNullish' | 'literalBooleanExpression' + | 'noOverlapBooleanExpression' | 'never' | 'neverOptionalChain'; export default createRule({ @@ -112,9 +117,11 @@ export default createRule({ alwaysNullish: 'Unnecessary conditional, left-hand side of `??` operator is always `null` or `undefined`.', literalBooleanExpression: - 'Unnecessary conditional, both sides of the expression are literal values.', - never: 'Unnecessary conditional, value is `never`.', - neverOptionalChain: 'Unnecessary optional chain on a non-nullish value.', + 'Unnecessary conditional, both sides of the expression are literal values', + noOverlapBooleanExpression: + 'Unnecessary conditional, the types have no overlap', + never: 'Unnecessary conditional, value is `never`', + neverOptionalChain: 'Unnecessary optional chain on a non-nullish value', }, }, defaultOptions: [ @@ -127,6 +134,7 @@ export default createRule({ const service = getParserServices(context); const checker = service.program.getTypeChecker(); const sourceCode = context.getSourceCode(); + const compilerOptions = service.program.getCompilerOptions(); function getNodeType(node: TSESTree.Expression): ts.Type { const tsNode = service.esTreeNodeToTSNodeMap.get(node); @@ -234,6 +242,9 @@ export default createRule({ * * NOTE: It's also unnecessary if the types that don't overlap at all * but that case is handled by the Typescript compiler itself. + * Known exceptions: + * * https://github.com/microsoft/TypeScript/issues/32627 + * * https://github.com/microsoft/TypeScript/issues/37160 (handled) */ const BOOL_OPERATORS = new Set([ '<', @@ -248,12 +259,30 @@ export default createRule({ function checkIfBinaryExpressionIsNecessaryConditional( node: TSESTree.BinaryExpression, ): void { - if ( - BOOL_OPERATORS.has(node.operator) && - isLiteral(getNodeType(node.left)) && - isLiteral(getNodeType(node.right)) - ) { + if (!BOOL_OPERATORS.has(node.operator)) { + return; + } + const leftType = getNodeType(node.left); + const rightType = getNodeType(node.right); + if (isLiteral(leftType) && isLiteral(rightType)) { context.report({ node, messageId: 'literalBooleanExpression' }); + return; + } + // Workaround for https://github.com/microsoft/TypeScript/issues/37160 + if (isStrictCompilerOptionEnabled(compilerOptions, 'strictNullChecks')) { + const UNDEFINED = ts.TypeFlags.Undefined; + const NULL = ts.TypeFlags.Null; + if ( + (leftType.flags === UNDEFINED && + !typeContainsFlag(rightType, UNDEFINED)) || + (rightType.flags === UNDEFINED && + !typeContainsFlag(leftType, UNDEFINED)) || + (leftType.flags === NULL && !typeContainsFlag(rightType, NULL)) || + (rightType.flags === NULL && !typeContainsFlag(leftType, NULL)) + ) { + context.report({ node, messageId: 'noOverlapBooleanExpression' }); + return; + } } } diff --git a/packages/eslint-plugin/tests/rules/no-unnecessary-condition.test.ts b/packages/eslint-plugin/tests/rules/no-unnecessary-condition.test.ts index 913aca555655..d33eec46d063 100644 --- a/packages/eslint-plugin/tests/rules/no-unnecessary-condition.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unnecessary-condition.test.ts @@ -103,6 +103,12 @@ function test(a: string) { return a === 'a'; } `, + ` +function test(a?: string) { + const t1 = a === undefined; + const t3 = undefined === a; +} + `, /** * Predicate functions @@ -403,6 +409,31 @@ if (x === Foo.a) { `, errors: [ruleError(8, 5, 'literalBooleanExpression')], }, + // Workaround https://github.com/microsoft/TypeScript/issues/37160 + { + code: ` +function test(a: string) { + const t1 = a !== undefined; + const t3 = undefined === a; +} + `, + errors: [ + ruleError(3, 14, 'noOverlapBooleanExpression'), + ruleError(4, 14, 'noOverlapBooleanExpression'), + ], + }, + { + code: ` +function test(a?: string) { + const t1 = a === null; + const t3 = null !== a; +} + `, + errors: [ + ruleError(3, 14, 'noOverlapBooleanExpression'), + ruleError(4, 14, 'noOverlapBooleanExpression'), + ], + }, // Nullish coalescing operator { code: ` From bfd9b606d17d30d5694967a1f01e0e1501ba1022 Mon Sep 17 00:00:00 2001 From: Retsam Date: Sun, 10 May 2020 20:54:02 -0400 Subject: [PATCH 22/33] feat(eslint-plugin): [no-unnecessary-condition] remove `checkArrayPredicates` and always check it (#1579) --- .../docs/rules/no-unnecessary-condition.md | 21 ++++++--------- .../src/rules/no-unnecessary-condition.ts | 18 ++++--------- .../rules/no-unnecessary-condition.test.ts | 26 +++---------------- 3 files changed, 16 insertions(+), 49 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/no-unnecessary-condition.md b/packages/eslint-plugin/docs/rules/no-unnecessary-condition.md index f2bea6f4fd84..5b24b4cc9659 100644 --- a/packages/eslint-plugin/docs/rules/no-unnecessary-condition.md +++ b/packages/eslint-plugin/docs/rules/no-unnecessary-condition.md @@ -28,6 +28,12 @@ function bar(arg: string) { // arg can never be nullish, so ?. is unnecessary return arg?.length; } + +// Checks array predicate return types, where possible +[ + [1, 2], + [3, 4], +].filter(t => t); // number[] is always truthy ``` Examples of **correct** code for this rule: @@ -50,6 +56,8 @@ function bar(arg?: string | null) { // Necessary, since arg might be nullish return arg?.length; } + +[0, 1, 2, 3].filter(t => t); // number can be truthy or falsy ``` ## Options @@ -74,19 +82,6 @@ for (; true; ) {} do {} while (true); ``` -- `checkArrayPredicates` (default: `false`) - if set checks that the return value from certain array method callbacks (`filter`, `find`, `some`, `every`) is necessarily conditional. - -```ts -// Valid: numbers can be truthy or falsy. -[0, 1, 2, 3].filter(t => t); - -// Invalid: arrays are always falsy. -[ - [1, 2], - [3, 4], -].filter(t => t); -``` - ## When Not To Use It The main downside to using this rule is the need for type information. diff --git a/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts b/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts index 85503bbfa7fa..1c73614c8a77 100644 --- a/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts +++ b/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts @@ -64,7 +64,6 @@ const isLiteral = (type: ts.Type): boolean => export type Options = [ { allowConstantLoopConditions?: boolean; - checkArrayPredicates?: boolean; }, ]; @@ -97,9 +96,6 @@ export default createRule({ allowConstantLoopConditions: { type: 'boolean', }, - checkArrayPredicates: { - type: 'boolean', - }, }, additionalProperties: false, }, @@ -127,10 +123,9 @@ export default createRule({ defaultOptions: [ { allowConstantLoopConditions: false, - checkArrayPredicates: false, }, ], - create(context, [{ allowConstantLoopConditions, checkArrayPredicates }]) { + create(context, [{ allowConstantLoopConditions }]) { const service = getParserServices(context); const checker = service.program.getTypeChecker(); const sourceCode = context.getSourceCode(); @@ -337,11 +332,9 @@ export default createRule({ 'some', 'every', ]); - function shouldCheckCallback(node: TSESTree.CallExpression): boolean { + function isArrayPredicateFunction(node: TSESTree.CallExpression): boolean { const { callee } = node; return ( - // option is on - !!checkArrayPredicates && // looks like `something.filter` or `something.find` callee.type === AST_NODE_TYPES.MemberExpression && callee.property.type === AST_NODE_TYPES.Identifier && @@ -351,10 +344,9 @@ export default createRule({ ); } function checkCallExpression(node: TSESTree.CallExpression): void { - const { - arguments: [callback], - } = node; - if (callback && shouldCheckCallback(node)) { + // If this is something like arr.filter(x => /*condition*/), check `condition` + if (isArrayPredicateFunction(node) && node.arguments.length) { + const callback = node.arguments[0]!; // Inline defined functions if ( (callback.type === AST_NODE_TYPES.ArrowFunctionExpression || diff --git a/packages/eslint-plugin/tests/rules/no-unnecessary-condition.test.ts b/packages/eslint-plugin/tests/rules/no-unnecessary-condition.test.ts index d33eec46d063..91deb63f58cc 100644 --- a/packages/eslint-plugin/tests/rules/no-unnecessary-condition.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unnecessary-condition.test.ts @@ -113,20 +113,7 @@ function test(a?: string) { /** * Predicate functions **/ - // valid, with the flag off ` -[1, 3, 5].filter(() => true); -[1, 2, 3].find(() => false); -function truthy() { - return []; -} -function falsy() {} -[1, 3, 5].filter(truthy); -[1, 2, 3].find(falsy); - `, - { - options: [{ checkArrayPredicates: true }], - code: ` // with literal arrow function [0, 1, 2].filter(x => x); @@ -140,20 +127,16 @@ function length(x: string) { function nonEmptyStrings(x: string[]) { return x.filter(length); } - `, - }, + `, // Ignores non-array methods of the same name - { - options: [{ checkArrayPredicates: true }], - code: ` + ` const notArray = { filter: (func: () => boolean) => func(), find: (func: () => boolean) => func(), }; notArray.filter(() => true); notArray.find(() => true); - `, - }, + `, // Nullish coalescing operator ` @@ -470,7 +453,6 @@ function test(a: never) { // Predicate functions { - options: [{ checkArrayPredicates: true }], code: ` [1, 3, 5].filter(() => true); [1, 2, 3].find(() => { @@ -534,7 +516,6 @@ if (arr.filter) { errors: [ruleError(3, 5, 'alwaysTruthy')], }, { - options: [{ checkArrayPredicates: true }], code: ` function truthy() { return []; @@ -551,7 +532,6 @@ function falsy() {} // Supports generics // TODO: fix this // { - // options: [{ checkArrayPredicates: true }], // code: ` // const isTruthy = (t: T) => T; // // Valid: numbers can be truthy or falsy (0). From 264b017c11c2ab132fcbad18b42a9a0fe639386e Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Sun, 10 May 2020 17:54:56 -0700 Subject: [PATCH 23/33] feat(eslint-plugin): [restrict-template-expressions] rename `allowNullable` to `allowNullish` (#2006) --- .../rules/restrict-template-expressions.md | 8 ++++---- .../rules/restrict-template-expressions.ts | 6 +++--- .../restrict-template-expressions.test.ts | 20 +++++++++---------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/restrict-template-expressions.md b/packages/eslint-plugin/docs/rules/restrict-template-expressions.md index 260a8eb188dd..0ee7427ddac1 100644 --- a/packages/eslint-plugin/docs/rules/restrict-template-expressions.md +++ b/packages/eslint-plugin/docs/rules/restrict-template-expressions.md @@ -34,14 +34,14 @@ type Options = { // if true, also allow any in template expressions allowAny?: boolean; // if true, also allow null and undefined in template expressions - allowNullable?: boolean; + allowNullish?: boolean; }; const defaults = { allowNumber: true, allowBoolean: false, allowAny: false, - allowNullable: false, + allowNullish: false, }; ``` @@ -75,9 +75,9 @@ const msg1 = `arg = ${user.name}`; const msg2 = `arg = ${user.name || 'the user with no name'}`; ``` -### `allowNullable` +### `allowNullish` -Examples of additional **correct** code for this rule with `{ allowNullable: true }`: +Examples of additional **correct** code for this rule with `{ allowNullish: true }`: ```ts const arg = condition ? 'ok' : null; diff --git a/packages/eslint-plugin/src/rules/restrict-template-expressions.ts b/packages/eslint-plugin/src/rules/restrict-template-expressions.ts index dd030cf5bc08..a3cbb0b6f3bf 100644 --- a/packages/eslint-plugin/src/rules/restrict-template-expressions.ts +++ b/packages/eslint-plugin/src/rules/restrict-template-expressions.ts @@ -10,7 +10,7 @@ type Options = [ allowNumber?: boolean; allowBoolean?: boolean; allowAny?: boolean; - allowNullable?: boolean; + allowNullish?: boolean; }, ]; @@ -36,7 +36,7 @@ export default util.createRule({ allowNumber: { type: 'boolean' }, allowBoolean: { type: 'boolean' }, allowAny: { type: 'boolean' }, - allowNullable: { type: 'boolean' }, + allowNullish: { type: 'boolean' }, }, }, ], @@ -77,7 +77,7 @@ export default util.createRule({ } if ( - options.allowNullable && + options.allowNullish && util.isTypeFlagSet(type, ts.TypeFlags.Null | ts.TypeFlags.Undefined) ) { return true; diff --git a/packages/eslint-plugin/tests/rules/restrict-template-expressions.test.ts b/packages/eslint-plugin/tests/rules/restrict-template-expressions.test.ts index 2d1a7422183f..df5d5aefb259 100644 --- a/packages/eslint-plugin/tests/rules/restrict-template-expressions.test.ts +++ b/packages/eslint-plugin/tests/rules/restrict-template-expressions.test.ts @@ -158,23 +158,23 @@ ruleTester.run('restrict-template-expressions', rule, { const msg = \`arg = \${user.name || 'the user with no name'}\`; `, }, - // allowNullable + // allowNullish { - options: [{ allowNullable: true }], + options: [{ allowNullish: true }], code: ` const arg = null; const msg = \`arg = \${arg}\`; `, }, { - options: [{ allowNullable: true }], + options: [{ allowNullish: true }], code: ` declare const arg: string | null | undefined; const msg = \`arg = \${arg}\`; `, }, { - options: [{ allowNullable: true }], + options: [{ allowNullish: true }], code: ` function test(arg: T) { return \`arg = \${arg}\`; @@ -182,7 +182,7 @@ ruleTester.run('restrict-template-expressions', rule, { `, }, { - options: [{ allowNullable: true }], + options: [{ allowNullish: true }], code: ` function test(arg: T) { return \`arg = \${arg}\`; @@ -191,7 +191,7 @@ ruleTester.run('restrict-template-expressions', rule, { }, // allow ALL { - options: [{ allowNumber: true, allowBoolean: true, allowNullable: true }], + options: [{ allowNumber: true, allowBoolean: true, allowNullish: true }], code: ` type All = string | number | boolean | null | undefined; function test(arg: T) { @@ -272,7 +272,7 @@ ruleTester.run('restrict-template-expressions', rule, { ], }, { - options: [{ allowNumber: true, allowBoolean: true, allowNullable: true }], + options: [{ allowNumber: true, allowBoolean: true, allowNullish: true }], code: ` const arg = {}; const msg = \`arg = \${arg}\`; @@ -296,7 +296,7 @@ ruleTester.run('restrict-template-expressions', rule, { ], }, { - options: [{ allowNumber: true, allowBoolean: true, allowNullable: true }], + options: [{ allowNumber: true, allowBoolean: true, allowNullish: true }], code: ` function test(arg: T) { return \`arg = \${arg}\`; @@ -307,7 +307,7 @@ ruleTester.run('restrict-template-expressions', rule, { ], }, { - options: [{ allowNumber: true, allowBoolean: true, allowNullable: true }], + options: [{ allowNumber: true, allowBoolean: true, allowNullish: true }], code: ` function test(arg: T) { return \`arg = \${arg}\`; @@ -323,7 +323,7 @@ ruleTester.run('restrict-template-expressions', rule, { ], }, { - options: [{ allowNumber: true, allowBoolean: true, allowNullable: true }], + options: [{ allowNumber: true, allowBoolean: true, allowNullish: true }], code: ` function test(arg: any) { return \`arg = \${arg}\`; From 7ad4d7c2db088b6f779b9d883a4acad13eee3775 Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Mon, 11 May 2020 13:12:32 -0700 Subject: [PATCH 24/33] feat: bump minimum required TS version (#2004) --- .eslintrc.js | 1 + README.md | 8 +++++--- package.json | 6 +++--- packages/typescript-estree/README.md | 4 +--- packages/typescript-estree/src/parser.ts | 4 ++-- yarn.lock | 2 +- 6 files changed, 13 insertions(+), 12 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 4974d31f8c9b..f25eb9271c84 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -21,6 +21,7 @@ module.exports = { sourceType: 'module', project: ['./tsconfig.eslint.json', './packages/*/tsconfig.json'], tsconfigRootDir: __dirname, + warnOnUnsupportedTypeScriptVersion: false, }, rules: { // diff --git a/README.md b/README.md index c298f8069507..13c792bdd976 100644 --- a/README.md +++ b/README.md @@ -234,11 +234,13 @@ The latest version under the `canary` tag **(latest commit to master)** is: ## Supported TypeScript Version -We will always endeavor to support the latest stable version of TypeScript. Sometimes, but not always, changes in TypeScript will not require breaking changes in this project, and so we are able to support more than one version of TypeScript. In some cases, we may even be able to support additional pre-releases (i.e. betas and release candidates) of TypeScript, but only if doing so does not require us to compromise on support for the latest stable version. +**The version range of TypeScript currently supported by this parser is `>=3.3.1 <3.8.0`.** + +These versions are what we test against. -**The version range of TypeScript currently supported by this parser is `>=3.2.1 <3.8.0`.** +We will always endeavor to support the latest stable version of TypeScript. Sometimes, but not always, changes in TypeScript will not require breaking changes in this project, and so we are able to support more than one version of TypeScript. In some cases, we may even be able to support additional pre-releases (i.e. betas and release candidates) of TypeScript, but only if doing so does not require us to compromise on support for the latest stable version. -This is reflected in the `devDependency` requirement within the package.json file, and it is what the tests will be run against. We have an open `peerDependency` requirement in order to allow for experimentation on newer/beta versions of TypeScript. +Note that our packages have an open `peerDependency` requirement in order to allow for experimentation on newer/beta versions of TypeScript. If you use a non-supported version of TypeScript, the parser will log a warning to the console. If you want to disable this warning, you can configure this in your `parserOptions`. See: [`@typescript-eslint/parser`](./packages/parser/) and [`@typescript-eslint/typescript-estree`](./packages/typescript-estree/). diff --git a/package.json b/package.json index 41ba35916588..5b00b8bb2644 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "lint:markdown:fix": "lint:markdown --fix", "lint:markdown": "markdownlint '**/*.md' --config=.markdownlint.json --ignore-path=.markdownlintignore", "lint": "eslint . --ext .js,.ts", - "postinstall": "yarn lerna-init && yarn build", + "postinstall": "yarn lerna:init && yarn build", "pre-commit": "yarn lint-staged", "pre-push": "yarn check:format", "test": "lerna run test --concurrency 1", @@ -79,9 +79,9 @@ "ts-jest": "^25.5.1", "ts-node": "^8.10.1", "tslint": "^6.1.2", - "typescript": ">=3.2.1 <4.0.0" + "typescript": ">=3.3.1 <4.0.0" }, "resolutions": { - "typescript": "^3.8.3" + "typescript": "3.9.2" } } diff --git a/packages/typescript-estree/README.md b/packages/typescript-estree/README.md index df2492c56b34..5ab7fe44a7b9 100644 --- a/packages/typescript-estree/README.md +++ b/packages/typescript-estree/README.md @@ -249,9 +249,7 @@ Types for the AST produced by the parse functions. ## Supported TypeScript Version -We will always endeavor to support the latest stable version of TypeScript. - -The version of TypeScript currently supported by this parser is `~3.2.1`. This is reflected in the `devDependency` requirement within the package.json file, and it is what the tests will be run against. We have an open `peerDependency` requirement in order to allow for experimentation on newer/beta versions of TypeScript. +See the [Supported TypeScript Version](../../README.md#supported-typescript-version) section in the project root. If you use a non-supported version of TypeScript, the parser will log a warning to the console. diff --git a/packages/typescript-estree/src/parser.ts b/packages/typescript-estree/src/parser.ts index 57fbc01abab5..f4a1d2047c9d 100644 --- a/packages/typescript-estree/src/parser.ts +++ b/packages/typescript-estree/src/parser.ts @@ -20,12 +20,12 @@ const log = debug('typescript-eslint:typescript-estree:parser'); * This needs to be kept in sync with the top-level README.md in the * typescript-eslint monorepo */ -const SUPPORTED_TYPESCRIPT_VERSIONS = '>=3.2.1 <3.8.0'; +const SUPPORTED_TYPESCRIPT_VERSIONS = '>=3.3.1 <3.8.0'; /* * The semver package will ignore prerelease ranges, and we don't want to explicitly document every one * List them all separately here, so we can automatically create the full string */ -const SUPPORTED_PRERELEASE_RANGES = ['>3.7.0-dev.0', '3.7.1-rc']; +const SUPPORTED_PRERELEASE_RANGES: string[] = []; const ACTIVE_TYPESCRIPT_VERSION = ts.version; const isRunningSupportedTypeScriptVersion = semver.satisfies( ACTIVE_TYPESCRIPT_VERSION, diff --git a/yarn.lock b/yarn.lock index 8990a0267b14..397043be8f60 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8451,7 +8451,7 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@*, "typescript@>=3.2.1 <4.0.0", typescript@^3.8.3: +typescript@*, typescript@3.9.2, "typescript@>=3.3.1 <4.0.0": version "3.9.2" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.2.tgz#64e9c8e9be6ea583c54607677dd4680a1cf35db9" integrity sha512-q2ktq4n/uLuNNShyayit+DTobV2ApPEo/6so68JaD5ojvc/6GClBipedB9zNWYxRSAlZXAe405Rlijzl6qDiSw== From 208de71059746bf38e94bd460346ffb2698a3e12 Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Wed, 13 May 2020 21:31:01 -0700 Subject: [PATCH 25/33] feat: upgrade to ESLint v7 (#2022) --- .eslintrc.js | 6 +- package.json | 2 +- .../src/rules/no-poorly-typed-ts-props.ts | 1 + .../rules/plugin-test-formatting.test.ts | 58 + packages/eslint-plugin-tslint/package.json | 2 +- .../eslint-plugin-tslint/tests/index.spec.ts | 2 + packages/eslint-plugin/package.json | 2 +- .../src/rules/func-call-spacing.ts | 16 +- .../src/rules/no-empty-function.ts | 2 + .../src/rules/no-implied-eval.ts | 3 +- .../src/rules/space-before-function-paren.ts | 17 +- .../no-restricted-globals.test.ts | 27 +- .../tests/rules/array-type.test.ts | 2 + .../tests/rules/ban-types.test.ts | 1 + .../tests/rules/func-call-spacing.test.ts | 180 +- .../tests/rules/keyword-spacing.test.ts | 1 + .../rules/member-delimiter-style.test.ts | 26 + .../tests/rules/no-empty-interface.test.ts | 7 + .../tests/rules/no-extra-parens.test.ts | 28 + .../tests/rules/no-implied-eval.test.ts | 114 ++ .../tests/rules/no-invalid-this.test.ts | 9 +- .../rules/no-unnecessary-condition.test.ts | 7 + .../no-unnecessary-type-assertion.test.ts | 20 +- .../tests/rules/no-unused-vars.test.ts | 206 +- .../rules/no-useless-constructor.test.ts | 6 +- .../eslint-plugin/tests/rules/quotes.test.ts | 27 +- .../tests/rules/return-await.test.ts | 1 + .../eslint-plugin/tests/rules/semi.test.ts | 1715 ++++++++--------- .../rules/space-before-function-paren.test.ts | 18 +- .../eslint-plugin/tools/generate-configs.ts | 7 +- .../eslint-plugin/typings/eslint-rules.d.ts | 22 +- .../src/eslint-utils/RuleTester.ts | 5 + packages/parser/package.json | 2 +- .../fixtures/markdown/.eslintrc.js | 25 + .../fixtures/markdown/.eslintrc.yml | 23 - .../integration/fixtures/markdown/Dockerfile | 2 +- .../fixtures/markdown/test.js.snap | 293 --- tests/integration/fixtures/markdown/test.sh | 2 +- .../.eslintrc.js | 18 + .../.eslintrc.yml | 17 - .../Dockerfile | 2 +- .../test.js.snap | 44 - .../test.sh | 2 +- .../.eslintrc.js | 38 + .../.eslintrc.yml | 25 - .../Dockerfile | 2 +- .../test.js.snap | 2 + .../test.sh | 2 +- .../integration/fixtures/vue-jsx/.eslintrc.js | 27 + .../fixtures/vue-jsx/.eslintrc.yml | 25 - tests/integration/fixtures/vue-jsx/Dockerfile | 2 +- .../integration/fixtures/vue-jsx/test.js.snap | 87 - tests/integration/fixtures/vue-jsx/test.sh | 2 +- .../integration/fixtures/vue-sfc/.eslintrc.js | 25 + .../fixtures/vue-sfc/.eslintrc.yml | 24 - tests/integration/fixtures/vue-sfc/Dockerfile | 2 +- .../integration/fixtures/vue-sfc/test.js.snap | 95 - tests/integration/fixtures/vue-sfc/test.sh | 2 +- tests/integration/utils/jsconfig.json | 6 +- yarn.lock | 109 +- 60 files changed, 1699 insertions(+), 1746 deletions(-) create mode 100644 tests/integration/fixtures/markdown/.eslintrc.js delete mode 100644 tests/integration/fixtures/markdown/.eslintrc.yml delete mode 100644 tests/integration/fixtures/markdown/test.js.snap create mode 100644 tests/integration/fixtures/recommended-does-not-require-program/.eslintrc.js delete mode 100644 tests/integration/fixtures/recommended-does-not-require-program/.eslintrc.yml delete mode 100644 tests/integration/fixtures/recommended-does-not-require-program/test.js.snap create mode 100644 tests/integration/fixtures/typescript-and-tslint-plugins-together/.eslintrc.js delete mode 100644 tests/integration/fixtures/typescript-and-tslint-plugins-together/.eslintrc.yml create mode 100644 tests/integration/fixtures/vue-jsx/.eslintrc.js delete mode 100644 tests/integration/fixtures/vue-jsx/.eslintrc.yml delete mode 100644 tests/integration/fixtures/vue-jsx/test.js.snap create mode 100644 tests/integration/fixtures/vue-sfc/.eslintrc.js delete mode 100644 tests/integration/fixtures/vue-sfc/.eslintrc.yml delete mode 100644 tests/integration/fixtures/vue-sfc/test.js.snap diff --git a/.eslintrc.js b/.eslintrc.js index f25eb9271c84..8b4cfa2db36a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -19,7 +19,11 @@ module.exports = { ], parserOptions: { sourceType: 'module', - project: ['./tsconfig.eslint.json', './packages/*/tsconfig.json'], + project: [ + './tsconfig.eslint.json', + './tests/integration/utils/jsconfig.json', + './packages/*/tsconfig.json', + ], tsconfigRootDir: __dirname, warnOnUnsupportedTypeScriptVersion: false, }, diff --git a/package.json b/package.json index 5b00b8bb2644..6010da4c5c88 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "all-contributors-cli": "^6.14.2", "cspell": "^4.0.61", "cz-conventional-changelog": "^3.2.0", - "eslint": "^6.7.0", + "eslint": "^7.0.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-internal/src/rules/no-poorly-typed-ts-props.ts b/packages/eslint-plugin-internal/src/rules/no-poorly-typed-ts-props.ts index b769e05d9265..e112b8205b20 100644 --- a/packages/eslint-plugin-internal/src/rules/no-poorly-typed-ts-props.ts +++ b/packages/eslint-plugin-internal/src/rules/no-poorly-typed-ts-props.ts @@ -94,6 +94,7 @@ export default createRule({ suggest: [ { messageId: 'suggestedFix', + data: banned, fix(fixer): TSESLint.RuleFix | null { if (banned.fixWith == null) { return null; diff --git a/packages/eslint-plugin-internal/tests/rules/plugin-test-formatting.test.ts b/packages/eslint-plugin-internal/tests/rules/plugin-test-formatting.test.ts index c2af09bec90a..3b8bb47dafd8 100644 --- a/packages/eslint-plugin-internal/tests/rules/plugin-test-formatting.test.ts +++ b/packages/eslint-plugin-internal/tests/rules/plugin-test-formatting.test.ts @@ -417,6 +417,27 @@ ruleTester.run({ ], }, ], +}); + `, + output: ` +ruleTester.run({ + valid: [], + invalid: [ + { + code: 'const x = 1;', + errors: [ + { + messageId: 'foo', + suggestions: [ + { + messageId: 'bar', + output: 'const x = 1;', + }, + ], + }, + ], + }, + ], }); `, errors: [ @@ -459,6 +480,40 @@ ruleTester.run({ foo\`, }, ], +}); + `, + output: ` +ruleTester.run({ + valid: [ + { + code: 'foo', + }, + { + code: \` +foo +\`, + }, + { + code: \` + foo +\`, + }, + ], + invalid: [ + { + code: 'foo', + }, + { + code: \` +foo +\`, + }, + { + code: \` + foo +\`, + }, + ], }); `, errors: [ @@ -508,6 +563,9 @@ ruleTester.run({ }, { code: wrap`\`const a = "1"; +${CODE_INDENT}\`.trimRight()`, + output: wrap`\` +const a = "1"; ${CODE_INDENT}\`.trimRight()`, errors: [ { diff --git a/packages/eslint-plugin-tslint/package.json b/packages/eslint-plugin-tslint/package.json index d56f9232de09..1f132c9aec23 100644 --- a/packages/eslint-plugin-tslint/package.json +++ b/packages/eslint-plugin-tslint/package.json @@ -35,7 +35,7 @@ "lodash": "^4.17.15" }, "peerDependencies": { - "eslint": "^5.0.0 || ^6.0.0", + "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0", "tslint": "^5.0.0 || ^6.0.0", "typescript": "*" }, diff --git a/packages/eslint-plugin-tslint/tests/index.spec.ts b/packages/eslint-plugin-tslint/tests/index.spec.ts index 5241f8907caa..ab88970867ec 100644 --- a/packages/eslint-plugin-tslint/tests/index.spec.ts +++ b/packages/eslint-plugin-tslint/tests/index.spec.ts @@ -13,6 +13,7 @@ const ruleTester = new TSESLint.RuleTester({ * within @typescript-eslint/parser */ project: './tests/fixture-project/tsconfig.json', + warnOnUnsupportedTypeScriptVersion: false, }, parser: require.resolve('@typescript-eslint/parser'), }); @@ -71,6 +72,7 @@ ruleTester.run('tslint/config', rule, { { options: [{ lintFile: './tests/test-project/tslint.json' }], code: 'throw "err" // no-string-throw', + output: 'throw new Error("err") // no-string-throw', filename: './tests/fixture-project/3.ts', errors: [ { diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index 7cb77b22ab70..2fcdcfd86099 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -56,7 +56,7 @@ }, "peerDependencies": { "@typescript-eslint/parser": "^2.0.0", - "eslint": "^5.0.0 || ^6.0.0" + "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" }, "peerDependenciesMeta": { "typescript": { diff --git a/packages/eslint-plugin/src/rules/func-call-spacing.ts b/packages/eslint-plugin/src/rules/func-call-spacing.ts index 53858ad18ab4..21a62af1950d 100644 --- a/packages/eslint-plugin/src/rules/func-call-spacing.ts +++ b/packages/eslint-plugin/src/rules/func-call-spacing.ts @@ -7,7 +7,10 @@ export type Options = [ allowNewlines?: boolean; }?, ]; -export type MessageIds = 'unexpected' | 'missing'; +export type MessageIds = + | 'unexpectedWhitespace' + | 'unexpectedNewline' + | 'missing'; export default util.createRule({ name: 'func-call-spacing', @@ -56,8 +59,9 @@ export default util.createRule({ }, messages: { - unexpected: - 'Unexpected space or newline between function name and paren.', + unexpectedWhitespace: + 'Unexpected whitespace between function name and paren.', + unexpectedNewline: 'Unexpected newline between function name and paren.', missing: 'Missing space between function name and paren.', }, }, @@ -110,7 +114,7 @@ export default util.createRule({ return context.report({ node, loc: lastCalleeToken.loc.start, - messageId: 'unexpected', + messageId: 'unexpectedWhitespace', fix(fixer) { /* * Only autofix if there is no newline @@ -140,7 +144,7 @@ export default util.createRule({ context.report({ node, loc: lastCalleeToken.loc.start, - messageId: 'unexpected', + messageId: 'unexpectedWhitespace', }); } } else { @@ -157,7 +161,7 @@ export default util.createRule({ context.report({ node, loc: lastCalleeToken.loc.start, - messageId: 'unexpected', + messageId: 'unexpectedNewline', fix(fixer) { return fixer.replaceTextRange( [lastCalleeToken.range[1], openingParenToken.range[0]], diff --git a/packages/eslint-plugin/src/rules/no-empty-function.ts b/packages/eslint-plugin/src/rules/no-empty-function.ts index 5d85dd306bbf..e1bc1ed716bd 100644 --- a/packages/eslint-plugin/src/rules/no-empty-function.ts +++ b/packages/eslint-plugin/src/rules/no-empty-function.ts @@ -27,6 +27,8 @@ const schema = util.deepMerge( 'constructors', 'private-constructors', 'protected-constructors', + 'asyncFunctions', + 'asyncMethods', ], }, }, diff --git a/packages/eslint-plugin/src/rules/no-implied-eval.ts b/packages/eslint-plugin/src/rules/no-implied-eval.ts index d983065d5b2e..dd36fb73ec45 100644 --- a/packages/eslint-plugin/src/rules/no-implied-eval.ts +++ b/packages/eslint-plugin/src/rules/no-implied-eval.ts @@ -7,6 +7,7 @@ import * as tsutils from 'tsutils'; import * as util from '../util'; const FUNCTION_CONSTRUCTOR = 'Function'; +const GLOBAL_CANDIDATES = new Set(['global', 'window', 'globalThis']); const EVAL_LIKE_METHODS = new Set([ 'setImmediate', 'setInterval', @@ -46,7 +47,7 @@ export default util.createRule({ if ( node.type === AST_NODE_TYPES.MemberExpression && node.object.type === AST_NODE_TYPES.Identifier && - node.object.name === 'window' + GLOBAL_CANDIDATES.has(node.object.name) ) { if (node.property.type === AST_NODE_TYPES.Identifier) { return node.property.name; diff --git a/packages/eslint-plugin/src/rules/space-before-function-paren.ts b/packages/eslint-plugin/src/rules/space-before-function-paren.ts index bc2ad8b0d047..41a817938dac 100644 --- a/packages/eslint-plugin/src/rules/space-before-function-paren.ts +++ b/packages/eslint-plugin/src/rules/space-before-function-paren.ts @@ -9,11 +9,11 @@ type FuncOption = Option | 'ignore'; export type Options = [ | Option - | Partial<{ - anonymous: FuncOption; - named: FuncOption; - asyncArrow: FuncOption; - }>, + | { + anonymous?: FuncOption; + named?: FuncOption; + asyncArrow?: FuncOption; + }, ]; export type MessageIds = 'unexpected' | 'missing'; @@ -150,7 +150,10 @@ export default util.createRule({ if (hasSpacing && functionConfig === 'never') { context.report({ node, - loc: leftToken.loc.end, + loc: { + start: leftToken.loc.end, + end: rightToken.loc.start, + }, messageId: 'unexpected', fix: fixer => fixer.removeRange([leftToken.range[1], rightToken.range[0]]), @@ -162,7 +165,7 @@ export default util.createRule({ ) { context.report({ node, - loc: leftToken.loc.end, + loc: rightToken.loc, messageId: 'missing', fix: fixer => fixer.insertTextAfter(leftToken, ' '), }); diff --git a/packages/eslint-plugin/tests/eslint-rules/no-restricted-globals.test.ts b/packages/eslint-plugin/tests/eslint-rules/no-restricted-globals.test.ts index 0cb6ec5d2919..21e6369d1b22 100644 --- a/packages/eslint-plugin/tests/eslint-rules/no-restricted-globals.test.ts +++ b/packages/eslint-plugin/tests/eslint-rules/no-restricted-globals.test.ts @@ -64,10 +64,11 @@ fdescribe("foo", function() { options: ['event'], errors: [ { - message: "Unexpected use of 'event'.", - // the base rule doesn't use messageId - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } as any, + messageId: 'defaultMessage', + data: { + name: 'event', + }, + }, ], }, { @@ -77,10 +78,11 @@ confirm("TEST"); options: ['confirm'], errors: [ { - message: "Unexpected use of 'confirm'.", - // the base rule doesn't use messageId - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } as any, + messageId: 'defaultMessage', + data: { + name: 'confirm', + }, + }, ], }, { @@ -90,10 +92,11 @@ var a = confirm("TEST")?.a; options: ['confirm'], errors: [ { - message: "Unexpected use of 'confirm'.", - // the base rule doesn't use messageId - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } as any, + messageId: 'defaultMessage', + data: { + name: 'confirm', + }, + }, ], }, ], diff --git a/packages/eslint-plugin/tests/rules/array-type.test.ts b/packages/eslint-plugin/tests/rules/array-type.test.ts index 5f15ba5e8220..ec6ad4ccf8fe 100644 --- a/packages/eslint-plugin/tests/rules/array-type.test.ts +++ b/packages/eslint-plugin/tests/rules/array-type.test.ts @@ -717,6 +717,7 @@ function fooFunction(foo: ArrayClass[]) { }, { code: 'let fooVar: Array[];', + output: 'let fooVar: any[][];', options: [{ default: 'array' }], errors: [ { @@ -729,6 +730,7 @@ function fooFunction(foo: ArrayClass[]) { }, { code: 'let fooVar: Array[];', + output: 'let fooVar: any[][];', options: [{ default: 'array-simple' }], errors: [ { diff --git a/packages/eslint-plugin/tests/rules/ban-types.test.ts b/packages/eslint-plugin/tests/rules/ban-types.test.ts index 9f11202a07f6..46e258f8e310 100644 --- a/packages/eslint-plugin/tests/rules/ban-types.test.ts +++ b/packages/eslint-plugin/tests/rules/ban-types.test.ts @@ -101,6 +101,7 @@ ruleTester.run('ban-types', rule, { invalid: [ { code: 'let a: String;', + output: 'let a: string;', errors: [ { messageId: 'bannedTypeMessage', diff --git a/packages/eslint-plugin/tests/rules/func-call-spacing.test.ts b/packages/eslint-plugin/tests/rules/func-call-spacing.test.ts index db884fd3cf12..2c5d0e577764 100644 --- a/packages/eslint-plugin/tests/rules/func-call-spacing.test.ts +++ b/packages/eslint-plugin/tests/rules/func-call-spacing.test.ts @@ -142,12 +142,22 @@ ruleTester.run('func-call-spacing', rule, { { code: 'f.b ();', output: 'f.b();', - errors: [{ messageId: 'unexpected', column: 3 }], + errors: [ + { + messageId: 'unexpectedWhitespace' as const, + column: 3, + }, + ], }, { code: 'f.b().c ();', output: 'f.b().c();', - errors: [{ messageId: 'unexpected', column: 7 }], + errors: [ + { + messageId: 'unexpectedWhitespace' as const, + column: 7, + }, + ], }, { code: 'f() ()', @@ -172,7 +182,14 @@ ruleTester.run('func-call-spacing', rule, { { code: 'f ();\n t ();', output: 'f();\n t();', - errors: [{ messageId: 'unexpected' }, { messageId: 'unexpected' }], + errors: [ + { + messageId: 'unexpectedWhitespace' as const, + }, + { + messageId: 'unexpectedWhitespace' as const, + }, + ], }, // https://github.com/eslint/eslint/issues/7787 @@ -189,7 +206,7 @@ this.decrement(request) output: null, // no change errors: [ { - messageId: 'unexpected', + messageId: 'unexpectedWhitespace' as const, line: 3, column: 23, }, @@ -203,7 +220,7 @@ var a = foo output: null, // no change errors: [ { - messageId: 'unexpected', + messageId: 'unexpectedWhitespace' as const, line: 2, column: 9, }, @@ -217,7 +234,7 @@ var a = foo output: null, // no change errors: [ { - messageId: 'unexpected', + messageId: 'unexpectedWhitespace' as const, line: 2, column: 9, }, @@ -239,14 +256,15 @@ var a = foo code: 'f\r\n();', output: null, // no change }, - ].map( - code => - ({ - options: ['never'], - errors: [{ messageId: 'unexpected' }], - ...code, - } as TSESLint.InvalidTestCase), - ), + ].map>(code => ({ + options: ['never'], + errors: [ + { + messageId: 'unexpectedWhitespace', + }, + ], + ...code, + })), // "always" ...[ @@ -274,14 +292,15 @@ var a = foo code: 'f(0) (1)', output: 'f (0) (1)', }, - ].map( - code => - ({ - options: ['always'], - errors: [{ messageId: 'missing' }], - ...code, - } as TSESLint.InvalidTestCase), - ), + ].map>(code => ({ + options: ['always'], + errors: [ + { + messageId: 'missing', + }, + ], + ...code, + })), ...[ { code: 'f\n();', @@ -294,7 +313,12 @@ var a = foo { code: 'f.b();', output: 'f.b ();', - errors: [{ messageId: 'missing' as MessageIds, column: 3 }], + errors: [ + { + messageId: 'missing' as const, + column: 3, + }, + ], }, { code: 'f.b\n();', @@ -303,7 +327,12 @@ var a = foo { code: 'f.b().c ();', output: 'f.b ().c ();', - errors: [{ messageId: 'missing' as MessageIds, column: 3 }], + errors: [ + { + messageId: 'missing' as const, + column: 3, + }, + ], }, { code: 'f.b\n().c ();', @@ -317,21 +346,33 @@ var a = foo code: 'f\n()()', output: 'f () ()', errors: [ - { messageId: 'unexpected' as MessageIds }, - { messageId: 'missing' as MessageIds }, + { + messageId: 'unexpectedNewline' as const, + }, + { + messageId: 'missing' as const, + }, ], }, { code: '(function() {}())', output: '(function() {} ())', - errors: [{ messageId: 'missing' }], + errors: [ + { + messageId: 'missing' as const, + }, + ], }, { code: 'f();\n t();', output: 'f ();\n t ();', errors: [ - { messageId: 'missing' as MessageIds }, - { messageId: 'missing' as MessageIds }, + { + messageId: 'missing' as const, + }, + { + messageId: 'missing' as const, + }, ], }, { @@ -341,23 +382,37 @@ var a = foo { code: 'f\u2028();', output: 'f ();', + errors: [ + { + messageId: 'unexpectedNewline' as const, + }, + ], }, { code: 'f\u2029();', output: 'f ();', + errors: [ + { + messageId: 'unexpectedNewline' as const, + }, + ], }, { code: 'f\r\n();', output: 'f ();', }, - ].map( - code => - ({ - options: ['always'], - errors: [{ messageId: 'unexpected' as MessageIds }], - ...code, - } as TSESLint.InvalidTestCase), - ), + ].map>(code => ({ + options: ['always'], + errors: [ + { + messageId: + code.code.includes('\n') || code.code.includes('\r') + ? 'unexpectedNewline' + : 'unexpectedWhitespace', + }, + ], + ...code, + })), // "always", "allowNewlines": true ...[ @@ -372,7 +427,12 @@ var a = foo { code: 'f.b();', output: 'f.b ();', - errors: [{ messageId: 'missing', column: 3 }], + errors: [ + { + messageId: 'missing' as const, + column: 3, + }, + ], }, { code: 'f.b().c ();', @@ -401,16 +461,24 @@ var a = foo { code: 'f();\n t();', output: 'f ();\n t ();', - errors: [{ messageId: 'missing' }, { messageId: 'missing' }], + errors: [ + { + messageId: 'missing' as const, + }, + { + messageId: 'missing' as const, + }, + ], }, - ].map( - code => - ({ - options: ['always', { allowNewlines: true }], - errors: [{ messageId: 'missing' }], - ...code, - } as TSESLint.InvalidTestCase), - ), + ].map>(code => ({ + options: ['always', { allowNewlines: true }], + errors: [ + { + messageId: 'missing', + }, + ], + ...code, + })), // optional chain ...[ @@ -424,21 +492,33 @@ var a = foo acc.push( { options: ['always', { allowNewlines: true }], - errors: [{ messageId: 'unexpected' }], + errors: [ + { + messageId: 'unexpectedWhitespace', + }, + ], code, // apply no fixers to it output: null, }, { options: ['always'], - errors: [{ messageId: 'unexpected' }], + errors: [ + { + messageId: 'unexpectedWhitespace', + }, + ], code, // apply no fixers to it output: null, }, { options: ['never'], - errors: [{ messageId: 'unexpected' }], + errors: [ + { + messageId: 'unexpectedWhitespace', + }, + ], code, // apply no fixers to it output: null, diff --git a/packages/eslint-plugin/tests/rules/keyword-spacing.test.ts b/packages/eslint-plugin/tests/rules/keyword-spacing.test.ts index 987caebb1e43..ec94928c1c59 100644 --- a/packages/eslint-plugin/tests/rules/keyword-spacing.test.ts +++ b/packages/eslint-plugin/tests/rules/keyword-spacing.test.ts @@ -145,6 +145,7 @@ ruleTester.run('keyword-spacing', rule, { }, { code: 'const foo = {} as{};', + output: 'const foo = {} as {};', options: [{ overrides: { as: {} } }], parserOptions: { ecmaVersion: 6, sourceType: 'module' }, errors: expectedAfter('as'), diff --git a/packages/eslint-plugin/tests/rules/member-delimiter-style.test.ts b/packages/eslint-plugin/tests/rules/member-delimiter-style.test.ts index 0ace26623133..d0fa7895b9c6 100644 --- a/packages/eslint-plugin/tests/rules/member-delimiter-style.test.ts +++ b/packages/eslint-plugin/tests/rules/member-delimiter-style.test.ts @@ -3236,6 +3236,12 @@ type Foo = { interface Foo { name: string; age: number; +} + `, + output: ` +interface Foo { + name: string; + age: number } `, options: [{ multiline: { delimiter: 'semi', requireLast: false } }], @@ -3252,6 +3258,12 @@ interface Foo { interface Foo { name: string; age: number; +} + `, + output: ` +interface Foo { + name: string; + age: number } `, options: [ @@ -3277,6 +3289,7 @@ interface Foo { }, { code: 'interface Foo { a: any, [key: string]: any }', + output: 'interface Foo { a: any; [key: string]: any }', errors: [ { messageId: 'expectedSemi', @@ -3290,6 +3303,12 @@ interface Foo { type Foo = { name: string; age: number; +} + `, + output: ` +type Foo = { + name: string; + age: number } `, options: [{ multiline: { delimiter: 'semi', requireLast: false } }], @@ -3306,6 +3325,12 @@ type Foo = { type Foo = { name: string; age: number; +} + `, + output: ` +type Foo = { + name: string; + age: number } `, options: [ @@ -3331,6 +3356,7 @@ type Foo = { }, { code: 'type Foo = { a: any, [key: string]: any }', + output: 'type Foo = { a: any; [key: string]: any }', errors: [ { messageId: 'expectedSemi', diff --git a/packages/eslint-plugin/tests/rules/no-empty-interface.test.ts b/packages/eslint-plugin/tests/rules/no-empty-interface.test.ts index d0281ec77a03..f974af09c186 100644 --- a/packages/eslint-plugin/tests/rules/no-empty-interface.test.ts +++ b/packages/eslint-plugin/tests/rules/no-empty-interface.test.ts @@ -63,6 +63,13 @@ interface Foo { } interface Bar extends Foo {} + `, + output: noFormat` +interface Foo { + name: string; +} + +type Bar = Foo `, options: [{ allowSingleExtends: false }], errors: [ diff --git a/packages/eslint-plugin/tests/rules/no-extra-parens.test.ts b/packages/eslint-plugin/tests/rules/no-extra-parens.test.ts index 03414b9bc490..45cdf1f99c1c 100644 --- a/packages/eslint-plugin/tests/rules/no-extra-parens.test.ts +++ b/packages/eslint-plugin/tests/rules/no-extra-parens.test.ts @@ -233,6 +233,14 @@ for (a in (b, c)); for (a in (b)); for (a of (b)); typeof (a); + `, + output: ` +a = b * c; +a * b + c; +for (a in b, c); +for (a in b); +for (a of b); +typeof a; `, errors: [ { @@ -271,6 +279,10 @@ typeof (a); code: ` const Component = (
) const Component = (

) + `, + output: ` +const Component =
+const Component =

`, options: ['all', { ignoreJSX: 'multi-line' }], errors: [ @@ -298,6 +310,18 @@ const Component = ( prop={true} /> ) + `, + output: ` +const Component =${' '} +
+

+

+ +const Component =${' '} +
+ `, options: ['all', { ignoreJSX: 'single-line' }], errors: [ @@ -317,6 +341,10 @@ const Component = ( code: ` ((function foo() {}))(); var y = (function () {return 1;}); + `, + output: ` +(function foo() {})(); +var y = function () {return 1;}; `, options: ['functions'], errors: [ diff --git a/packages/eslint-plugin/tests/rules/no-implied-eval.test.ts b/packages/eslint-plugin/tests/rules/no-implied-eval.test.ts index 353a6300b453..818514c6b0ba 100644 --- a/packages/eslint-plugin/tests/rules/no-implied-eval.test.ts +++ b/packages/eslint-plugin/tests/rules/no-implied-eval.test.ts @@ -651,6 +651,120 @@ window['execScript'](\`\`); }, ], }, + { + code: ` +global.setTimeout(\`\`, 0); +global['setTimeout'](\`\`, 0); + +global.setInterval(\`\`, 0); +global['setInterval'](\`\`, 0); + +global.setImmediate(\`\`); +global['setImmediate'](\`\`); + +global.execScript(\`\`); +global['execScript'](\`\`); + `, + errors: [ + { + messageId: 'noImpliedEvalError', + line: 2, + column: 19, + }, + { + messageId: 'noImpliedEvalError', + line: 3, + column: 22, + }, + { + messageId: 'noImpliedEvalError', + line: 5, + column: 20, + }, + { + messageId: 'noImpliedEvalError', + line: 6, + column: 23, + }, + { + messageId: 'noImpliedEvalError', + line: 8, + column: 21, + }, + { + messageId: 'noImpliedEvalError', + line: 9, + column: 24, + }, + { + messageId: 'noImpliedEvalError', + line: 11, + column: 19, + }, + { + messageId: 'noImpliedEvalError', + line: 12, + column: 22, + }, + ], + }, + { + code: ` +globalThis.setTimeout(\`\`, 0); +globalThis['setTimeout'](\`\`, 0); + +globalThis.setInterval(\`\`, 0); +globalThis['setInterval'](\`\`, 0); + +globalThis.setImmediate(\`\`); +globalThis['setImmediate'](\`\`); + +globalThis.execScript(\`\`); +globalThis['execScript'](\`\`); + `, + errors: [ + { + messageId: 'noImpliedEvalError', + line: 2, + column: 23, + }, + { + messageId: 'noImpliedEvalError', + line: 3, + column: 26, + }, + { + messageId: 'noImpliedEvalError', + line: 5, + column: 24, + }, + { + messageId: 'noImpliedEvalError', + line: 6, + column: 27, + }, + { + messageId: 'noImpliedEvalError', + line: 8, + column: 25, + }, + { + messageId: 'noImpliedEvalError', + line: 9, + column: 28, + }, + { + messageId: 'noImpliedEvalError', + line: 11, + column: 23, + }, + { + messageId: 'noImpliedEvalError', + line: 12, + column: 26, + }, + ], + }, { code: 'const fn = Function();', errors: [ diff --git a/packages/eslint-plugin/tests/rules/no-invalid-this.test.ts b/packages/eslint-plugin/tests/rules/no-invalid-this.test.ts index f3d339fe63ee..0705ba1e9e84 100644 --- a/packages/eslint-plugin/tests/rules/no-invalid-this.test.ts +++ b/packages/eslint-plugin/tests/rules/no-invalid-this.test.ts @@ -8,10 +8,9 @@ const ruleTester = new RuleTester({ }, }); -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const errors: any = [ - { message: "Unexpected 'this'." }, - { message: "Unexpected 'this'." }, +const errors = [ + { messageId: 'unexpectedThis' as const }, + { messageId: 'unexpectedThis' as const }, ]; ruleTester.run('no-invalid-this', rule, { @@ -416,7 +415,7 @@ function foo() { this.prop; } `, - errors: [{ message: "Unexpected 'this'." }], + errors: [{ messageId: 'unexpectedThis' }], }, // Global. { diff --git a/packages/eslint-plugin/tests/rules/no-unnecessary-condition.test.ts b/packages/eslint-plugin/tests/rules/no-unnecessary-condition.test.ts index 91deb63f58cc..72bf643942fb 100644 --- a/packages/eslint-plugin/tests/rules/no-unnecessary-condition.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unnecessary-condition.test.ts @@ -499,6 +499,13 @@ const x = [{}] as [{ foo: string }]; if (x[0]) { } if (x[0]?.foo) { +} + `, + output: ` +const x = [{}] as [{ foo: string }]; +if (x[0]) { +} +if (x[0].foo) { } `, errors: [ diff --git a/packages/eslint-plugin/tests/rules/no-unnecessary-type-assertion.test.ts b/packages/eslint-plugin/tests/rules/no-unnecessary-type-assertion.test.ts index d6febe39ea54..b197a96afe2a 100644 --- a/packages/eslint-plugin/tests/rules/no-unnecessary-type-assertion.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unnecessary-type-assertion.test.ts @@ -1,6 +1,6 @@ import path from 'path'; import rule from '../../src/rules/no-unnecessary-type-assertion'; -import { RuleTester } from '../RuleTester'; +import { RuleTester, noFormat } from '../RuleTester'; const rootDir = path.resolve(__dirname, '../fixtures/'); const ruleTester = new RuleTester({ @@ -183,6 +183,10 @@ const c = [...a, ...b]; code: ` const foo = 3; const bar = foo!; + `, + output: ` +const foo = 3; +const bar = foo; `, errors: [ { @@ -195,6 +199,9 @@ const bar = foo!; { code: ` const foo = (3 + 5) as number; + `, + output: noFormat` +const foo = (3 + 5); `, errors: [ { @@ -207,6 +214,9 @@ const foo = (3 + 5) as number; { code: ` const foo = (3 + 5); + `, + output: noFormat` +const foo = (3 + 5); `, errors: [ { @@ -220,6 +230,10 @@ const foo = (3 + 5); code: ` type Foo = number; const foo = (3 + 5) as Foo; + `, + output: noFormat` +type Foo = number; +const foo = (3 + 5); `, errors: [ { @@ -233,6 +247,10 @@ const foo = (3 + 5) as Foo; code: ` type Foo = number; const foo = (3 + 5); + `, + output: noFormat` +type Foo = number; +const foo = (3 + 5); `, errors: [ { diff --git a/packages/eslint-plugin/tests/rules/no-unused-vars.test.ts b/packages/eslint-plugin/tests/rules/no-unused-vars.test.ts index 6b0d7f4148bc..73ad95d1f4d2 100644 --- a/packages/eslint-plugin/tests/rules/no-unused-vars.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unused-vars.test.ts @@ -10,14 +10,6 @@ const ruleTester = new RuleTester({ parser: '@typescript-eslint/parser', }); -// the base rule doesn't have messageIds -function error( - messages: { message: string; line: number; column: number }[], - // eslint-disable-next-line @typescript-eslint/no-explicit-any -): any[] { - return messages; -} - ruleTester.run('no-unused-vars', rule, { valid: [ ` @@ -632,13 +624,18 @@ export default class Foo { import { ClassDecoratorFactory } from 'decorators'; export class Foo {} `, - errors: error([ + errors: [ { - message: "'ClassDecoratorFactory' is defined but never used.", + messageId: 'unusedVar', + data: { + varName: 'ClassDecoratorFactory', + action: 'defined', + additional: '', + }, line: 2, column: 10, }, - ]), + ], }, { code: ` @@ -646,13 +643,18 @@ import { Foo, Bar } from 'foo'; function baz() {} baz(); `, - errors: error([ + errors: [ { - message: "'Foo' is defined but never used.", + messageId: 'unusedVar', + data: { + varName: 'Foo', + action: 'defined', + additional: '', + }, line: 2, column: 10, }, - ]), + ], }, { code: ` @@ -660,13 +662,18 @@ import { Nullable } from 'nullable'; const a: string = 'hello'; console.log(a); `, - errors: error([ + errors: [ { - message: "'Nullable' is defined but never used.", + messageId: 'unusedVar', + data: { + varName: 'Nullable', + action: 'defined', + additional: '', + }, line: 2, column: 10, }, - ]), + ], }, { code: ` @@ -675,13 +682,18 @@ import { SomeOther } from 'other'; const a: Nullable = 'hello'; console.log(a); `, - errors: error([ + errors: [ { - message: "'SomeOther' is defined but never used.", + messageId: 'unusedVar', + data: { + varName: 'SomeOther', + action: 'defined', + additional: '', + }, line: 3, column: 10, }, - ]), + ], }, { @@ -695,13 +707,18 @@ class A { } new A(); `, - errors: error([ + errors: [ { - message: "'Another' is defined but never used.", + messageId: 'unusedVar', + data: { + varName: 'Another', + action: 'defined', + additional: '', + }, line: 3, column: 10, }, - ]), + ], }, { code: ` @@ -714,13 +731,18 @@ class A { } new A(); `, - errors: error([ + errors: [ { - message: "'Another' is defined but never used.", + messageId: 'unusedVar', + data: { + varName: 'Another', + action: 'defined', + additional: '', + }, line: 3, column: 10, }, - ]), + ], }, { code: ` @@ -733,13 +755,18 @@ class A { } new A(); `, - errors: error([ + errors: [ { - message: "'Another' is defined but never used.", + messageId: 'unusedVar', + data: { + varName: 'Another', + action: 'defined', + additional: '', + }, line: 3, column: 10, }, - ]), + ], }, { code: ` @@ -749,13 +776,18 @@ interface A { do(a: Nullable); } `, - errors: error([ + errors: [ { - message: "'Another' is defined but never used.", + messageId: 'unusedVar', + data: { + varName: 'Another', + action: 'defined', + additional: '', + }, line: 3, column: 10, }, - ]), + ], }, { code: ` @@ -765,13 +797,18 @@ interface A { other: Nullable; } `, - errors: error([ + errors: [ { - message: "'Another' is defined but never used.", + messageId: 'unusedVar', + data: { + varName: 'Another', + action: 'defined', + additional: '', + }, line: 3, column: 10, }, - ]), + ], }, { code: ` @@ -781,13 +818,18 @@ function foo(a: string) { } foo(); `, - errors: error([ + errors: [ { - message: "'Nullable' is defined but never used.", + messageId: 'unusedVar', + data: { + varName: 'Nullable', + action: 'defined', + additional: '', + }, line: 2, column: 10, }, - ]), + ], }, { code: ` @@ -797,13 +839,18 @@ function foo(): string | null { } foo(); `, - errors: error([ + errors: [ { - message: "'Nullable' is defined but never used.", + messageId: 'unusedVar', + data: { + varName: 'Nullable', + action: 'defined', + additional: '', + }, line: 2, column: 10, }, - ]), + ], }, { code: ` @@ -815,13 +862,18 @@ class A extends Nullable { } new A(); `, - errors: error([ + errors: [ { - message: "'SomeOther' is defined but never used.", + messageId: 'unusedVar', + data: { + varName: 'SomeOther', + action: 'defined', + additional: '', + }, line: 3, column: 10, }, - ]), + ], }, { code: ` @@ -833,13 +885,18 @@ abstract class A extends Nullable { } new A(); `, - errors: error([ + errors: [ { - message: "'SomeOther' is defined but never used.", + messageId: 'unusedVar', + data: { + varName: 'SomeOther', + action: 'defined', + additional: '', + }, line: 3, column: 10, }, - ]), + ], }, { code: ` @@ -848,13 +905,18 @@ enum FormFieldIds { EMAIL = 'email', } `, - errors: error([ + errors: [ { - message: "'FormFieldIds' is defined but never used.", + messageId: 'unusedVar', + data: { + varName: 'FormFieldIds', + action: 'defined', + additional: '', + }, line: 2, column: 6, }, - ]), + ], }, { code: ` @@ -862,13 +924,18 @@ import test from 'test'; import baz from 'baz'; export interface Bar extends baz.test {} `, - errors: error([ + errors: [ { - message: "'test' is defined but never used.", + messageId: 'unusedVar', + data: { + varName: 'test', + action: 'defined', + additional: '', + }, line: 2, column: 8, }, - ]), + ], }, { code: ` @@ -876,13 +943,18 @@ import test from 'test'; import baz from 'baz'; export interface Bar extends baz().test {} `, - errors: error([ + errors: [ { - message: "'test' is defined but never used.", + messageId: 'unusedVar', + data: { + varName: 'test', + action: 'defined', + additional: '', + }, line: 2, column: 8, }, - ]), + ], }, { code: ` @@ -890,13 +962,18 @@ import test from 'test'; import baz from 'baz'; export class Bar implements baz.test {} `, - errors: error([ + errors: [ { - message: "'test' is defined but never used.", + messageId: 'unusedVar', + data: { + varName: 'test', + action: 'defined', + additional: '', + }, line: 2, column: 8, }, - ]), + ], }, { code: ` @@ -904,13 +981,18 @@ import test from 'test'; import baz from 'baz'; export class Bar implements baz().test {} `, - errors: error([ + errors: [ { - message: "'test' is defined but never used.", + messageId: 'unusedVar', + data: { + varName: 'test', + action: 'defined', + additional: '', + }, line: 2, column: 8, }, - ]), + ], }, ], }); diff --git a/packages/eslint-plugin/tests/rules/no-useless-constructor.test.ts b/packages/eslint-plugin/tests/rules/no-useless-constructor.test.ts index 412aab3a1f1d..0730f280dc2f 100644 --- a/packages/eslint-plugin/tests/rules/no-useless-constructor.test.ts +++ b/packages/eslint-plugin/tests/rules/no-useless-constructor.test.ts @@ -10,10 +10,8 @@ const ruleTester = new RuleTester({ parser: '@typescript-eslint/parser', }); -// the base rule doesn't use a message id... -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const error: any = { - message: 'Useless constructor.', +const error = { + messageId: 'noUselessConstructor' as const, type: AST_NODE_TYPES.MethodDefinition, }; diff --git a/packages/eslint-plugin/tests/rules/quotes.test.ts b/packages/eslint-plugin/tests/rules/quotes.test.ts index f7b56a73ba3e..847e27e81f52 100644 --- a/packages/eslint-plugin/tests/rules/quotes.test.ts +++ b/packages/eslint-plugin/tests/rules/quotes.test.ts @@ -15,22 +15,25 @@ const ruleTester = new RuleTester({ }, }); -/** - * the base rule `quotes` doesn't use a message id - */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const useDoubleQuote: any = { - message: 'Strings must use doublequote.', +const useDoubleQuote = { + messageId: 'wrongQuotes' as const, + data: { + description: 'doublequote', + }, }; -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const useSingleQuote: any = { - message: 'Strings must use singlequote.', +const useSingleQuote = { + messageId: 'wrongQuotes' as const, + data: { + description: 'singlequote', + }, }; -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const useBacktick: any = { - message: 'Strings must use backtick.', +const useBacktick = { + messageId: 'wrongQuotes' as const, + data: { + description: 'backtick', + }, }; ruleTester.run('quotes', rule, { diff --git a/packages/eslint-plugin/tests/rules/return-await.test.ts b/packages/eslint-plugin/tests/rules/return-await.test.ts index f3e4169ad9df..5a98d22c917b 100644 --- a/packages/eslint-plugin/tests/rules/return-await.test.ts +++ b/packages/eslint-plugin/tests/rules/return-await.test.ts @@ -592,6 +592,7 @@ ruleTester.run('return-await', rule, { { options: ['always'], code: 'const test = async () => Promise.resolve(1);', + output: 'const test = async () => await Promise.resolve(1);', errors: [ { line: 1, diff --git a/packages/eslint-plugin/tests/rules/semi.test.ts b/packages/eslint-plugin/tests/rules/semi.test.ts index c8a8ff7f4791..d32e557eb587 100644 --- a/packages/eslint-plugin/tests/rules/semi.test.ts +++ b/packages/eslint-plugin/tests/rules/semi.test.ts @@ -1,3 +1,8 @@ +/* eslint-disable eslint-comments/no-use */ +// this rule tests the semis, which prettier will want to fix and break the tests +/* eslint "@typescript-eslint/internal/plugin-test-formatting": ["error", { formatWithPrettier: false }] */ +/* eslint-enable eslint-comments/no-use */ + import { TSESLint } from '@typescript-eslint/experimental-utils'; import rule, { MessageIds, Options } from '../../src/rules/semi'; import { RuleTester } from '../RuleTester'; @@ -17,82 +22,249 @@ const neverOptionWithoutContinuationChars: Options = [ { beforeStatementContinuationChars: 'never' }, ]; -// the base rule doesn't use a message id... -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const missingSemicolon: any = { - message: 'Missing semicolon.', +const missingSemicolon = { + messageId: 'missingSemi' as const, }; -// the base rule doesn't use a message id... -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const extraSemicolon: any = { - message: 'Extra semicolon.', +const extraSemicolon = { + messageId: 'extraSemi' as const, }; ruleTester.run('semi', rule, { valid: [ - // https://github.com/typescript-eslint/typescript-eslint/issues/366 - 'export = Foo;', - 'import f = require("f");', - 'type Foo = {};', - // https://github.com/typescript-eslint/typescript-eslint/issues/409 - ` + { code: 'for (var i;;){}' }, + { code: 'for (var i;;){}', options: neverOption }, + + { + code: 'var foo = 0;export { foo };', + }, + + // https://github.com/eslint/eslint/issues/7782 + { code: 'var a = b;\n/foo/.test(c)', options: neverOption }, + { + code: 'var a = b;\n`foo`', + options: neverOption, + }, + { code: 'var a = b;\n+ c', options: neverOption }, + + { + code: '(function bar() {})\n;(function foo(){})', + options: neverOption, + }, + { code: ";/foo/.test('bar')", options: neverOption }, + { code: ';+5', options: neverOption }, + { code: ';-foo()', options: neverOption }, + { code: 'a++\nb++', options: neverOption }, + { code: 'a++; b++', options: neverOption }, + + // https://github.com/eslint/eslint/issues/9521 + { + code: ` + do; while(a); + [1,2,3].forEach(doSomething) + `, + options: ['never', { beforeStatementContinuationChars: 'any' }], + }, + { + code: ` + do; while(a) + [1,2,3].forEach(doSomething) + `, + options: ['never', { beforeStatementContinuationChars: 'any' }], + }, + { + code: ` + import a from "a"; + [1,2,3].forEach(doSomething) + `, + options: ['never', { beforeStatementContinuationChars: 'always' }], + }, + { + code: ` + var a = 0; export {a}; + [a] = b + `, + options: ['never', { beforeStatementContinuationChars: 'always' }], + }, + { + code: ` + function wrap() { + return; + ({a} = b) + } + `, + options: ['never', { beforeStatementContinuationChars: 'always' }], + parserOptions: { ecmaVersion: 2015 }, + }, + { + code: ` + while (true) { + break; + +i + } + `, + options: ['never', { beforeStatementContinuationChars: 'always' }], + }, + { + code: ` + while (true) { + continue; + [1,2,3].forEach(doSomething) + } + `, + options: ['never', { beforeStatementContinuationChars: 'always' }], + }, + { + code: ` + do; while(a); + [1,2,3].forEach(doSomething) + `, + options: ['never', { beforeStatementContinuationChars: 'always' }], + }, + { + code: ` + const f = () => {}; + [1,2,3].forEach(doSomething) + `, + options: ['never', { beforeStatementContinuationChars: 'always' }], + parserOptions: { ecmaVersion: 2015 }, + }, + { + code: ` + import a from "a" + [1,2,3].forEach(doSomething) + `, + options: neverOptionWithoutContinuationChars, + }, + { + code: ` + var a = 0; export {a} + [a] = b + `, + options: neverOptionWithoutContinuationChars, + }, + { + code: ` + function wrap() { + return + ({a} = b) + } + `, + options: neverOptionWithoutContinuationChars, + parserOptions: { ecmaVersion: 2015 }, + }, + { + code: ` + while (true) { + break + +i + } + `, + options: neverOptionWithoutContinuationChars, + }, + { + code: ` + while (true) { + continue + [1,2,3].forEach(doSomething) + } + `, + options: neverOptionWithoutContinuationChars, + }, + { + code: ` + do; while(a) + [1,2,3].forEach(doSomething) + `, + options: neverOptionWithoutContinuationChars, + }, + { + code: ` + const f = () => {} + [1,2,3].forEach(doSomething) + `, + options: neverOptionWithoutContinuationChars, + parserOptions: { ecmaVersion: 2015 }, + }, + + { + code: 'if (foo) { bar(); }', + options: ['always', { omitLastInOneLineBlock: false }], + }, + { + code: 'if (foo) { bar(); baz(); }', + options: ['always', { omitLastInOneLineBlock: false }], + }, + { + code: 'if (foo) { bar() }', + options: ['always', { omitLastInOneLineBlock: true }], + }, + { + code: 'if (foo) { bar(); baz() }', + options: ['always', { omitLastInOneLineBlock: true }], + }, + ...[ + // https://github.com/typescript-eslint/typescript-eslint/issues/366 + 'export = Foo;', + 'import f = require("f");', + 'type Foo = {};', + // https://github.com/typescript-eslint/typescript-eslint/issues/409 + ` class Class { prop: string; } `, - ` + ` abstract class AbsClass { abstract prop: string; abstract meth(): string; } `, - ` + ` class PanCamera extends FreeCamera { public invertY: boolean = false; } `, - // https://github.com/typescript-eslint/typescript-eslint/issues/123 - 'export default interface test {}', - `declare function declareFn(): string;`, - // ESLint - 'var x = 5;', - 'var x =5, y;', - 'foo();', - 'x = foo();', - 'setTimeout(function() {foo = "bar"; });', - 'setTimeout(function() {foo = "bar";});', - 'for (var a in b){}', - 'if (true) {}\n;[global, extended].forEach(function(){});', - "throw new Error('foo');", - 'debugger;', - '++\nfoo;', - 'for (let thing of {}) {\n console.log(thing);\n}', - 'do{}while(true);', + // https://github.com/typescript-eslint/typescript-eslint/issues/123 + 'export default interface test {}', + `declare function declareFn(): string;`, + // ESLint + 'var x = 5;', + 'var x =5, y;', + 'foo();', + 'x = foo();', + 'setTimeout(function() {foo = "bar"; });', + 'setTimeout(function() {foo = "bar";});', + 'for (var a in b){}', + 'if (true) {}\n;[global, extended].forEach(function(){});', + "throw new Error('foo');", + 'debugger;', + '++\nfoo;', + 'for (let thing of {}) {\n console.log(thing);\n}', + 'do{}while(true);', - // method definitions don't have a semicolon. - 'class A { a() {} b() {} }', - 'var A = class { a() {} b() {} };', - "import theDefault, { named1, named2 } from 'src/mylib';", + // method definitions don't have a semicolon. + 'class A { a() {} b() {} }', + 'var A = class { a() {} b() {} };', + "import theDefault, { named1, named2 } from 'src/mylib';", - // exports, "always" - "export * from 'foo';", - "export { foo } from 'foo';", - 'export var foo;', - 'export function foo () { }', - 'export function* foo () { }', - 'export class Foo { }', - 'export let foo;', - 'export const FOO = 42;', - 'export default function() { }', - 'export default function* () { }', - 'export default class { }', - 'export default foo || bar;', - 'export default (foo) => foo.bar();', - 'export default foo = 42;', - 'export default foo += 42;', - ].reduce[]>( - (acc, code) => { + // exports, "always" + "export * from 'foo';", + "export { foo } from 'foo';", + 'export var foo;', + 'export function foo () { }', + 'export function* foo () { }', + 'export class Foo { }', + 'export let foo;', + 'export const FOO = 42;', + 'export default function() { }', + 'export default function* () { }', + 'export default class { }', + 'export default foo || bar;', + 'export default (foo) => foo.bar();', + 'export default foo = 42;', + 'export default foo += 42;', + ].reduce[]>((acc, code) => { acc.push({ code, options: ['always'], @@ -103,604 +275,509 @@ class PanCamera extends FreeCamera { }); return acc; - }, - [ - { code: 'for (var i;;){}' }, - { code: 'for (var i;;){}', options: neverOption }, - - { - code: 'var foo = 0;export { foo };', - }, - - // https://github.com/eslint/eslint/issues/7782 - { code: 'var a = b;\n/foo/.test(c)', options: neverOption }, - { - code: 'var a = b;\n`foo`', - options: neverOption, - }, - { code: 'var a = b;\n+ c', options: neverOption }, - - { - code: '(function bar() {})\n;(function foo(){})', - options: neverOption, - }, - { code: ";/foo/.test('bar')", options: neverOption }, - { code: ';+5', options: neverOption }, - { code: ';-foo()', options: neverOption }, - { code: 'a++\nb++', options: neverOption }, - { code: 'a++; b++', options: neverOption }, - - // https://github.com/eslint/eslint/issues/9521 - { - code: ` - do; while(a); - [1,2,3].forEach(doSomething) - `, - options: ['never', { beforeStatementContinuationChars: 'any' }], - }, - { - code: ` - do; while(a) - [1,2,3].forEach(doSomething) - `, - options: ['never', { beforeStatementContinuationChars: 'any' }], - }, - { - code: ` - import a from "a"; - [1,2,3].forEach(doSomething) - `, - options: ['never', { beforeStatementContinuationChars: 'always' }], - }, - { - code: ` - var a = 0; export {a}; - [a] = b - `, - options: ['never', { beforeStatementContinuationChars: 'always' }], - }, - { - code: ` - function wrap() { - return; - ({a} = b) - } - `, - options: ['never', { beforeStatementContinuationChars: 'always' }], - parserOptions: { ecmaVersion: 2015 }, - }, - { - code: ` - while (true) { - break; - +i - } - `, - options: ['never', { beforeStatementContinuationChars: 'always' }], - }, - { - code: ` - while (true) { - continue; - [1,2,3].forEach(doSomething) - } - `, - options: ['never', { beforeStatementContinuationChars: 'always' }], - }, - { - code: ` - do; while(a); - [1,2,3].forEach(doSomething) - `, - options: ['never', { beforeStatementContinuationChars: 'always' }], - }, - { - code: ` - const f = () => {}; - [1,2,3].forEach(doSomething) - `, - options: ['never', { beforeStatementContinuationChars: 'always' }], - parserOptions: { ecmaVersion: 2015 }, - }, - { - code: ` - import a from "a" - [1,2,3].forEach(doSomething) - `, - options: neverOptionWithoutContinuationChars, - }, - { - code: ` - var a = 0; export {a} - [a] = b - `, - options: neverOptionWithoutContinuationChars, - }, - { - code: ` - function wrap() { - return - ({a} = b) - } - `, - options: neverOptionWithoutContinuationChars, - parserOptions: { ecmaVersion: 2015 }, - }, - { - code: ` - while (true) { - break - +i - } - `, - options: neverOptionWithoutContinuationChars, - }, - { - code: ` - while (true) { - continue - [1,2,3].forEach(doSomething) - } - `, - options: neverOptionWithoutContinuationChars, - }, - { - code: ` - do; while(a) - [1,2,3].forEach(doSomething) - `, - options: neverOptionWithoutContinuationChars, - }, - { - code: ` - const f = () => {} - [1,2,3].forEach(doSomething) - `, - options: neverOptionWithoutContinuationChars, - parserOptions: { ecmaVersion: 2015 }, - }, - - { - code: 'if (foo) { bar(); }', - options: ['always', { omitLastInOneLineBlock: false }], - }, - { - code: 'if (foo) { bar(); baz(); }', - options: ['always', { omitLastInOneLineBlock: false }], - }, - { - code: 'if (foo) { bar() }', - options: ['always', { omitLastInOneLineBlock: true }], - }, - { - code: 'if (foo) { bar(); baz() }', - options: ['always', { omitLastInOneLineBlock: true }], - }, - ], - ), + }, []), + ], invalid: [ { - code: `declare function declareFn(): string;`, - errors: [ - { - line: 1, - }, - ], + code: 'if (foo) { bar() }', + output: 'if (foo) { bar(); }', + options: ['always', { omitLastInOneLineBlock: false }], + errors: [missingSemicolon], }, - - // https://github.com/typescript-eslint/typescript-eslint/issues/366 { - code: 'export = Foo;', - errors: [ - { - line: 1, - }, - ], + code: 'if (foo) { bar(); baz() }', + output: 'if (foo) { bar(); baz(); }', + options: ['always', { omitLastInOneLineBlock: false }], + errors: [missingSemicolon], }, { - code: 'import f = require("f");', - errors: [ - { - line: 1, - }, - ], + code: 'if (foo) { bar(); }', + output: 'if (foo) { bar() }', + options: ['always', { omitLastInOneLineBlock: true }], + errors: [extraSemicolon], }, { - code: 'type Foo = {};', - errors: [ - { - line: 1, - }, - ], + code: 'if (foo) { bar(); baz(); }', + output: 'if (foo) { bar(); baz() }', + options: ['always', { omitLastInOneLineBlock: true }], + errors: [extraSemicolon], }, - // https://github.com/typescript-eslint/typescript-eslint/issues/409 { code: ` -class Class { - prop: string; -} + import a from "a" + (function() { + // ... + })() `, - errors: [ - { - line: 3, - }, - ], - }, - { - code: ` -abstract class AbsClass { - abstract prop: string; - abstract meth(): string; -} + output: ` + import a from "a"; + (function() { + // ... + })() `, - errors: [ - { - line: 3, - }, - { - line: 4, - }, - ], + options: ['never', { beforeStatementContinuationChars: 'always' }], + errors: [missingSemicolon], }, { code: ` -class PanCamera extends FreeCamera { - public invertY: boolean = false; -} - `, - errors: [ - { - line: 3, - }, - ], + import a from "a" + ;(function() { + // ... + })() + `, + output: ` + import a from "a" + (function() { + // ... + })() + `, + options: neverOptionWithoutContinuationChars, + errors: [extraSemicolon], }, - // // ESLint { - code: "throw new Error('foo');", - output: "throw new Error('foo')", - errors: [ - { - line: 1, - }, - ], + code: 'for (;;){var i;}', + output: 'for (;;){var i}', + options: neverOption, + errors: [extraSemicolon], }, { - code: 'function foo() { return []; }', - output: 'function foo() { return [] }', - errors: [ - { - line: 1, - }, - ], + code: 'for (;;) var i; ', + output: 'for (;;) var i ', + options: neverOption, + errors: [extraSemicolon], }, { - code: 'while(true) { break; }', - output: 'while(true) { break }', - errors: [ - { - line: 1, - }, - ], + code: 'for (var j;;) {var i;}', + output: 'for (var j;;) {var i}', + options: neverOption, + errors: [extraSemicolon], }, + { - code: 'while(true) { continue; }', - output: 'while(true) { continue }', - errors: [ - { - line: 1, - }, - ], + code: 'for (;;){var i}', + output: 'for (;;){var i;}', + errors: [missingSemicolon], }, { - code: 'let x = 5;', - output: 'let x = 5', - errors: [ - { - line: 1, - }, - ], + code: 'for (;;) var i ', + output: 'for (;;) var i; ', + errors: [missingSemicolon], }, { - code: 'var x = 5;', - output: 'var x = 5', - errors: [ - { - line: 1, - }, - ], + code: 'for (var j;;) {var i}', + output: 'for (var j;;) {var i;}', + errors: [missingSemicolon], }, { - code: 'var x = 5, y;', - output: 'var x = 5, y', - errors: [ - { - line: 1, - }, - ], + code: 'var foo = {\n bar: baz\n}', + output: 'var foo = {\n bar: baz\n};', + errors: [missingSemicolon], }, + { - code: 'debugger;', - output: 'debugger', - errors: [ - { - line: 1, - }, - ], + code: 'if (foo) { bar()\n }', + output: 'if (foo) { bar();\n }', + options: ['always', { omitLastInOneLineBlock: true }], + errors: [missingSemicolon], }, { - code: 'foo();', - output: 'foo()', - errors: [ - { - line: 1, - }, - ], + code: 'if (foo) {\n bar() }', + output: 'if (foo) {\n bar(); }', + options: ['always', { omitLastInOneLineBlock: true }], + errors: [missingSemicolon], }, { - code: 'for (var a in b) var i; ', - output: 'for (var a in b) var i ', - errors: [ - { - line: 1, - }, - ], + code: 'if (foo) {\n bar(); baz() }', + output: 'if (foo) {\n bar(); baz(); }', + options: ['always', { omitLastInOneLineBlock: true }], + errors: [missingSemicolon], }, + + // https://github.com/eslint/eslint/issues/9521 { - code: 'var foo = {\n bar: baz\n};', - output: 'var foo = {\n bar: baz\n}', - errors: [ - { - line: 3, - }, - ], + code: ` + import a from "a" + [1,2,3].forEach(doSomething) + `, + output: ` + import a from "a"; + [1,2,3].forEach(doSomething) + `, + options: ['never', { beforeStatementContinuationChars: 'always' }], + + errors: [missingSemicolon], }, { - code: "import theDefault, { named1, named2 } from 'src/mylib';", - output: "import theDefault, { named1, named2 } from 'src/mylib'", - errors: [ - { - line: 1, - }, - ], + code: ` + var a = 0; export {a} + [a] = b + `, + output: ` + var a = 0; export {a}; + [a] = b + `, + options: ['never', { beforeStatementContinuationChars: 'always' }], + + errors: [missingSemicolon], }, { - code: 'do{}while(true);', - output: 'do{}while(true)', - errors: [ - { - line: 1, - }, - ], + code: ` + function wrap() { + return + ({a} = b) + } + `, + output: ` + function wrap() { + return; + ({a} = b) + } + `, + options: ['never', { beforeStatementContinuationChars: 'always' }], + parserOptions: { ecmaVersion: 2015 }, + errors: [missingSemicolon], }, { - code: "import * as utils from './utils';", - output: "import * as utils from './utils'", - errors: [ - { - line: 1, - }, - ], + code: ` + while (true) { + break + +i + } + `, + output: ` + while (true) { + break; + +i + } + `, + options: ['never', { beforeStatementContinuationChars: 'always' }], + errors: [missingSemicolon], }, { - code: "import { square, diag } from 'lib';", - output: "import { square, diag } from 'lib'", - errors: [ - { - line: 1, - }, - ], + code: ` + while (true) { + continue + [1,2,3].forEach(doSomething) + } + `, + output: ` + while (true) { + continue; + [1,2,3].forEach(doSomething) + } + `, + options: ['never', { beforeStatementContinuationChars: 'always' }], + errors: [missingSemicolon], }, { - code: "import { default as foo } from 'lib';", - output: "import { default as foo } from 'lib'", - errors: [ - { - line: 1, - }, - ], + code: ` + do; while(a) + [1,2,3].forEach(doSomething) + `, + output: ` + do; while(a); + [1,2,3].forEach(doSomething) + `, + options: ['never', { beforeStatementContinuationChars: 'always' }], + errors: [missingSemicolon], }, { - code: "import 'src/mylib';", - output: "import 'src/mylib'", - errors: [ - { - line: 1, - }, - ], + code: ` + const f = () => {} + [1,2,3].forEach(doSomething) + `, + output: ` + const f = () => {}; + [1,2,3].forEach(doSomething) + `, + options: ['never', { beforeStatementContinuationChars: 'always' }], + parserOptions: { ecmaVersion: 2015 }, + errors: [missingSemicolon], }, { - code: 'var foo;\nvar bar;', - output: 'var foo\nvar bar', - errors: [ - { - line: 1, - }, - { - line: 2, - }, - ], + code: ` + import a from "a"; + [1,2,3].forEach(doSomething) + `, + output: ` + import a from "a" + [1,2,3].forEach(doSomething) + `, + options: neverOptionWithoutContinuationChars, + + errors: [extraSemicolon], }, + { + code: ` + var a = 0; export {a}; + [a] = b + `, + output: ` + var a = 0; export {a} + [a] = b + `, + options: neverOptionWithoutContinuationChars, - // exports, "never" + errors: [extraSemicolon], + }, { - code: "export * from 'foo';", - output: "export * from 'foo'", - errors: [ - { - line: 1, - }, - ], + code: ` + function wrap() { + return; + ({a} = b) + } + `, + output: ` + function wrap() { + return + ({a} = b) + } + `, + options: neverOptionWithoutContinuationChars, + parserOptions: { ecmaVersion: 2015 }, + errors: [extraSemicolon], }, { - code: "export { foo } from 'foo';", - output: "export { foo } from 'foo'", - errors: [ - { - line: 1, - }, - ], + code: ` + while (true) { + break; + +i + } + `, + output: ` + while (true) { + break + +i + } + `, + options: neverOptionWithoutContinuationChars, + errors: [extraSemicolon], }, { - code: 'var foo = 0;\nexport { foo };', - output: 'var foo = 0\nexport { foo }', - errors: [ - { - line: 1, - }, - { - line: 2, - }, - ], + code: ` + while (true) { + continue; + [1,2,3].forEach(doSomething) + } + `, + output: ` + while (true) { + continue + [1,2,3].forEach(doSomething) + } + `, + options: neverOptionWithoutContinuationChars, + errors: [extraSemicolon], }, { - code: 'export var foo;', - output: 'export var foo', - errors: [ - { - line: 1, - }, - ], + code: ` + do; while(a); + [1,2,3].forEach(doSomething) + `, + output: ` + do; while(a) + [1,2,3].forEach(doSomething) + `, + options: neverOptionWithoutContinuationChars, + errors: [extraSemicolon], }, { - code: 'export let foo;', - output: 'export let foo', - errors: [ - { - line: 1, - }, - ], + code: ` + const f = () => {}; + [1,2,3].forEach(doSomething) + `, + output: ` + const f = () => {} + [1,2,3].forEach(doSomething) + `, + options: neverOptionWithoutContinuationChars, + parserOptions: { ecmaVersion: 2015 }, + errors: [extraSemicolon], }, { - code: 'export const FOO = 42;', - output: 'export const FOO = 42', - errors: [ - { - line: 1, - }, - ], + code: ` + import a from "a" + ;[1,2,3].forEach(doSomething) + `, + output: ` + import a from "a" + [1,2,3].forEach(doSomething) + `, + options: neverOptionWithoutContinuationChars, + + errors: [extraSemicolon], }, { - code: 'export default foo || bar;', - output: 'export default foo || bar', - errors: [ - { - line: 1, - }, - ], + code: ` + var a = 0; export {a} + ;[1,2,3].forEach(doSomething) + `, + output: ` + var a = 0; export {a} + [1,2,3].forEach(doSomething) + `, + options: neverOptionWithoutContinuationChars, + + errors: [extraSemicolon], }, { - code: 'export default (foo) => foo.bar();', - output: 'export default (foo) => foo.bar()', - errors: [ - { - line: 1, - }, - ], + code: ` + function wrap() { + return + ;[1,2,3].forEach(doSomething) + } + `, + output: ` + function wrap() { + return + [1,2,3].forEach(doSomething) + } + `, + options: neverOptionWithoutContinuationChars, + errors: [extraSemicolon], }, { - code: 'export default foo = 42;', - output: 'export default foo = 42', - errors: [ - { - line: 1, - }, - ], + code: ` + while (true) { + break + ;[1,2,3].forEach(doSomething) + } + `, + output: ` + while (true) { + break + [1,2,3].forEach(doSomething) + } + `, + options: neverOptionWithoutContinuationChars, + errors: [extraSemicolon], }, { - code: 'a;\n++b;', - output: 'a\n++b', - errors: [ - { - line: 1, - }, - { - line: 2, - }, - ], + code: ` + while (true) { + continue + ;[1,2,3].forEach(doSomething) + } + `, + output: ` + while (true) { + continue + [1,2,3].forEach(doSomething) + } + `, + options: neverOptionWithoutContinuationChars, + errors: [extraSemicolon], }, - ].reduce[]>( - (acc, test) => { - acc.push({ - code: test.code.replace(/;/g, ''), - options: ['always'], - errors: test.errors.map(e => ({ - ...e, - ...missingSemicolon, - })), - }); - acc.push({ - code: test.code, - options: ['never'], - errors: test.errors.map(e => ({ - ...e, - ...extraSemicolon, - })), - }); - - return acc; + { + code: ` + do; while(a) + ;[1,2,3].forEach(doSomething) + `, + output: ` + do; while(a) + [1,2,3].forEach(doSomething) + `, + options: neverOptionWithoutContinuationChars, + errors: [extraSemicolon], + }, + { + code: ` + const f = () => {} + ;[1,2,3].forEach(doSomething) + `, + output: ` + const f = () => {} + [1,2,3].forEach(doSomething) + `, + options: neverOptionWithoutContinuationChars, + parserOptions: { ecmaVersion: 2015 }, + errors: [extraSemicolon], }, - [ + + ...[ { - code: 'if (foo) { bar() }', - options: ['always', { omitLastInOneLineBlock: false }] as Options, - errors: [missingSemicolon], + code: `declare function declareFn(): string;`, + errors: [ + { + line: 1, + }, + ], }, + + // https://github.com/typescript-eslint/typescript-eslint/issues/366 { - code: 'if (foo) { bar(); baz() }', - options: ['always', { omitLastInOneLineBlock: false }] as Options, - errors: [missingSemicolon], + code: 'export = Foo;', + errors: [ + { + line: 1, + }, + ], }, { - code: 'if (foo) { bar(); }', - options: ['always', { omitLastInOneLineBlock: true }] as Options, - errors: [extraSemicolon], + code: 'import f = require("f");', + errors: [ + { + line: 1, + }, + ], }, { - code: 'if (foo) { bar(); baz(); }', - options: ['always', { omitLastInOneLineBlock: true }] as Options, - errors: [extraSemicolon], + code: 'type Foo = {};', + errors: [ + { + line: 1, + }, + ], }, + // https://github.com/typescript-eslint/typescript-eslint/issues/409 { code: ` - import a from "a" - (function() { - // ... - })() - `, - options: [ - 'never', - { beforeStatementContinuationChars: 'always' }, - ] as Options, - errors: [missingSemicolon], +class Class { + prop: string; +} + `, + errors: [ + { + line: 3, + }, + ], }, { code: ` - import a from "a" - ;(function() { - // ... - })() - `, - options: neverOptionWithoutContinuationChars, - errors: [extraSemicolon], +abstract class AbsClass { + abstract prop: string; + abstract meth(): string; +} + `, + errors: [ + { + line: 3, + }, + { + line: 4, + }, + ], }, - { - code: 'for (;;){var i;}', - output: 'for (;;){var i}', - options: neverOption, + code: ` +class PanCamera extends FreeCamera { + public invertY: boolean = false; +} + `, errors: [ { - line: 1, + line: 3, }, ], }, + + // // ESLint { - code: 'for (;;) var i; ', - output: 'for (;;) var i ', - options: neverOption, + code: "throw new Error('foo');", + output: "throw new Error('foo')", errors: [ { line: 1, @@ -708,378 +785,280 @@ class PanCamera extends FreeCamera { ], }, { - code: 'for (var j;;) {var i;}', - output: 'for (var j;;) {var i}', - options: neverOption, + code: 'function foo() { return []; }', + output: 'function foo() { return [] }', errors: [ { line: 1, }, ], }, - { - code: 'for (;;){var i}', - output: 'for (;;){var i;}', - errors: [missingSemicolon], + code: 'while(true) { break; }', + output: 'while(true) { break }', + errors: [ + { + line: 1, + }, + ], }, { - code: 'for (;;) var i ', - output: 'for (;;) var i; ', - errors: [missingSemicolon], + code: 'while(true) { continue; }', + output: 'while(true) { continue }', + errors: [ + { + line: 1, + }, + ], }, { - code: 'for (var j;;) {var i}', - output: 'for (var j;;) {var i;}', - errors: [missingSemicolon], + code: 'let x = 5;', + output: 'let x = 5', + errors: [ + { + line: 1, + }, + ], }, { - code: 'var foo = {\n bar: baz\n}', - output: 'var foo = {\n bar: baz\n};', - errors: [missingSemicolon], + code: 'var x = 5;', + output: 'var x = 5', + errors: [ + { + line: 1, + }, + ], }, - { - code: 'if (foo) { bar()\n }', - output: 'if (foo) { bar();\n }', - options: ['always', { omitLastInOneLineBlock: true }], - errors: [missingSemicolon], + code: 'var x = 5, y;', + output: 'var x = 5, y', + errors: [ + { + line: 1, + }, + ], }, { - code: 'if (foo) {\n bar() }', - output: 'if (foo) {\n bar(); }', - options: ['always', { omitLastInOneLineBlock: true }], - errors: [missingSemicolon], + code: 'debugger;', + output: 'debugger', + errors: [ + { + line: 1, + }, + ], }, { - code: 'if (foo) {\n bar(); baz() }', - output: 'if (foo) {\n bar(); baz(); }', - options: ['always', { omitLastInOneLineBlock: true }], - errors: [missingSemicolon], + code: 'foo();', + output: 'foo()', + errors: [ + { + line: 1, + }, + ], }, { - code: 'if (foo) { bar(); }', - output: 'if (foo) { bar() }', - options: ['always', { omitLastInOneLineBlock: true }], - errors: [{ message: 'Extra semicolon.' }], + code: 'for (var a in b) var i; ', + output: 'for (var a in b) var i ', + errors: [ + { + line: 1, + }, + ], }, - - // https://github.com/eslint/eslint/issues/9521 { - code: ` - import a from "a" - [1,2,3].forEach(doSomething) - `, - output: ` - import a from "a"; - [1,2,3].forEach(doSomething) - `, - options: ['never', { beforeStatementContinuationChars: 'always' }], - - errors: ['Missing semicolon.'], + code: 'var foo = {\n bar: baz\n};', + output: 'var foo = {\n bar: baz\n}', + errors: [ + { + line: 3, + }, + ], }, { - code: ` - var a = 0; export {a} - [a] = b - `, - output: ` - var a = 0; export {a}; - [a] = b - `, - options: ['never', { beforeStatementContinuationChars: 'always' }], - - errors: ['Missing semicolon.'], + code: "import theDefault, { named1, named2 } from 'src/mylib';", + output: "import theDefault, { named1, named2 } from 'src/mylib'", + errors: [ + { + line: 1, + }, + ], }, { - code: ` - function wrap() { - return - ({a} = b) - } - `, - output: ` - function wrap() { - return; - ({a} = b) - } - `, - options: ['never', { beforeStatementContinuationChars: 'always' }], - parserOptions: { ecmaVersion: 2015 }, - errors: ['Missing semicolon.'], + code: 'do{}while(true);', + output: 'do{}while(true)', + errors: [ + { + line: 1, + }, + ], }, { - code: ` - while (true) { - break - +i - } - `, - output: ` - while (true) { - break; - +i - } - `, - options: ['never', { beforeStatementContinuationChars: 'always' }], - errors: ['Missing semicolon.'], + code: "import * as utils from './utils';", + output: "import * as utils from './utils'", + errors: [ + { + line: 1, + }, + ], }, { - code: ` - while (true) { - continue - [1,2,3].forEach(doSomething) - } - `, - output: ` - while (true) { - continue; - [1,2,3].forEach(doSomething) - } - `, - options: ['never', { beforeStatementContinuationChars: 'always' }], - errors: ['Missing semicolon.'], + code: "import { square, diag } from 'lib';", + output: "import { square, diag } from 'lib'", + errors: [ + { + line: 1, + }, + ], }, { - code: ` - do; while(a) - [1,2,3].forEach(doSomething) - `, - output: ` - do; while(a); - [1,2,3].forEach(doSomething) - `, - options: ['never', { beforeStatementContinuationChars: 'always' }], - errors: ['Missing semicolon.'], + code: "import { default as foo } from 'lib';", + output: "import { default as foo } from 'lib'", + errors: [ + { + line: 1, + }, + ], }, { - code: ` - const f = () => {} - [1,2,3].forEach(doSomething) - `, - output: ` - const f = () => {}; - [1,2,3].forEach(doSomething) - `, - options: ['never', { beforeStatementContinuationChars: 'always' }], - parserOptions: { ecmaVersion: 2015 }, - errors: ['Missing semicolon.'], + code: "import 'src/mylib';", + output: "import 'src/mylib'", + errors: [ + { + line: 1, + }, + ], }, { - code: ` - import a from "a"; - [1,2,3].forEach(doSomething) - `, - output: ` - import a from "a" - [1,2,3].forEach(doSomething) - `, - options: neverOptionWithoutContinuationChars, - - errors: [extraSemicolon], + code: 'var foo;\nvar bar;', + output: 'var foo\nvar bar', + errors: [ + { + line: 1, + }, + { + line: 2, + }, + ], }, - { - code: ` - var a = 0; export {a}; - [a] = b - `, - output: ` - var a = 0; export {a} - [a] = b - `, - options: neverOptionWithoutContinuationChars, - errors: [extraSemicolon], - }, - { - code: ` - function wrap() { - return; - ({a} = b) - } - `, - output: ` - function wrap() { - return - ({a} = b) - } - `, - options: neverOptionWithoutContinuationChars, - parserOptions: { ecmaVersion: 2015 }, - errors: [extraSemicolon], - }, - { - code: ` - while (true) { - break; - +i - } - `, - output: ` - while (true) { - break - +i - } - `, - options: neverOptionWithoutContinuationChars, - errors: [extraSemicolon], - }, + // exports, "never" { - code: ` - while (true) { - continue; - [1,2,3].forEach(doSomething) - } - `, - output: ` - while (true) { - continue - [1,2,3].forEach(doSomething) - } - `, - options: neverOptionWithoutContinuationChars, - errors: [extraSemicolon], + code: "export * from 'foo';", + output: "export * from 'foo'", + errors: [ + { + line: 1, + }, + ], }, { - code: ` - do; while(a); - [1,2,3].forEach(doSomething) - `, - output: ` - do; while(a) - [1,2,3].forEach(doSomething) - `, - options: neverOptionWithoutContinuationChars, - errors: [extraSemicolon], + code: "export { foo } from 'foo';", + output: "export { foo } from 'foo'", + errors: [ + { + line: 1, + }, + ], }, { - code: ` - const f = () => {}; - [1,2,3].forEach(doSomething) - `, - output: ` - const f = () => {} - [1,2,3].forEach(doSomething) - `, - options: neverOptionWithoutContinuationChars, - parserOptions: { ecmaVersion: 2015 }, - errors: [extraSemicolon], + code: 'var foo = 0;\nexport { foo };', + output: 'var foo = 0\nexport { foo }', + errors: [ + { + line: 1, + }, + { + line: 2, + }, + ], }, { - code: ` - import a from "a" - ;[1,2,3].forEach(doSomething) - `, - output: ` - import a from "a" - [1,2,3].forEach(doSomething) - `, - options: neverOptionWithoutContinuationChars, - - errors: [extraSemicolon], + code: 'export var foo;', + output: 'export var foo', + errors: [ + { + line: 1, + }, + ], }, { - code: ` - var a = 0; export {a} - ;[1,2,3].forEach(doSomething) - `, - output: ` - var a = 0; export {a} - [1,2,3].forEach(doSomething) - `, - options: neverOptionWithoutContinuationChars, - - errors: [extraSemicolon], + code: 'export let foo;', + output: 'export let foo', + errors: [ + { + line: 1, + }, + ], }, { - code: ` - function wrap() { - return - ;[1,2,3].forEach(doSomething) - } - `, - output: ` - function wrap() { - return - [1,2,3].forEach(doSomething) - } - `, - options: neverOptionWithoutContinuationChars, - errors: [extraSemicolon], + code: 'export const FOO = 42;', + output: 'export const FOO = 42', + errors: [ + { + line: 1, + }, + ], }, { - code: ` - while (true) { - break - ;[1,2,3].forEach(doSomething) - } - `, - output: ` - while (true) { - break - [1,2,3].forEach(doSomething) - } - `, - options: neverOptionWithoutContinuationChars, - errors: [extraSemicolon], + code: 'export default foo || bar;', + output: 'export default foo || bar', + errors: [ + { + line: 1, + }, + ], }, { - code: ` - while (true) { - continue - ;[1,2,3].forEach(doSomething) - } - `, - output: ` - while (true) { - continue - [1,2,3].forEach(doSomething) - } - `, - options: neverOptionWithoutContinuationChars, - errors: [extraSemicolon], + code: 'export default (foo) => foo.bar();', + output: 'export default (foo) => foo.bar()', + errors: [ + { + line: 1, + }, + ], }, { - code: ` - do; while(a) - ;[1,2,3].forEach(doSomething) - `, - output: ` - do; while(a) - [1,2,3].forEach(doSomething) - `, - options: neverOptionWithoutContinuationChars, - errors: [extraSemicolon], + code: 'export default foo = 42;', + output: 'export default foo = 42', + errors: [ + { + line: 1, + }, + ], }, { - code: ` - const f = () => {} - ;[1,2,3].forEach(doSomething) - `, - output: ` - const f = () => {} - [1,2,3].forEach(doSomething) - `, - options: neverOptionWithoutContinuationChars, - parserOptions: { ecmaVersion: 2015 }, - errors: [extraSemicolon], + code: 'a;\n++b;', + output: 'a\n++b;', + errors: [ + { + line: 1, + }, + { + line: 2, + }, + ], }, + ].reduce[]>((acc, test) => { + acc.push({ + code: test.code.replace(/;/g, ''), + output: test.code, + options: ['always'], + errors: test.errors.map(e => ({ + ...e, + ...missingSemicolon, + })), + }); + acc.push({ + code: test.code, + output: test.output ?? test.code.replace(/;/g, ''), + options: ['never'], + errors: test.errors.map(e => ({ + ...e, + ...extraSemicolon, + })), + }); - // https://github.com/eslint/eslint/issues/7928 - { - code: [ - '/*eslint no-extra-semi: error */', - 'foo();', - ';[0,1,2].forEach(bar)', - ].join('\n'), - output: [ - '/*eslint no-extra-semi: error */', - 'foo()', - ';[0,1,2].forEach(bar)', - ].join('\n'), - options: neverOption, - errors: ['Extra semicolon.', 'Unnecessary semicolon.'], - }, - ], - ), + return acc; + }, []), + ], }); diff --git a/packages/eslint-plugin/tests/rules/space-before-function-paren.test.ts b/packages/eslint-plugin/tests/rules/space-before-function-paren.test.ts index eb515c1617cd..944ea672f1fc 100644 --- a/packages/eslint-plugin/tests/rules/space-before-function-paren.test.ts +++ b/packages/eslint-plugin/tests/rules/space-before-function-paren.test.ts @@ -3,14 +3,8 @@ /* eslint "@typescript-eslint/internal/plugin-test-formatting": ["error", { formatWithPrettier: false }] */ /* eslint-enable eslint-comments/no-use */ -import { - TSESLint, - AST_NODE_TYPES, -} from '@typescript-eslint/experimental-utils'; -import rule, { - MessageIds, - Options, -} from '../../src/rules/space-before-function-paren'; +import { AST_NODE_TYPES } from '@typescript-eslint/experimental-utils'; +import rule from '../../src/rules/space-before-function-paren'; import { RuleTester } from '../RuleTester'; const ruleTester = new RuleTester({ @@ -189,7 +183,7 @@ ruleTester.run('space-before-function-paren', rule, { type: AST_NODE_TYPES.FunctionDeclaration, messageId: 'missing', line: 1, - column: 13, + column: 18, }, ], }, @@ -534,14 +528,14 @@ ruleTester.run('space-before-function-paren', rule, { output: 'async () => 1', options: [{ asyncArrow: 'always' }], parserOptions: { ecmaVersion: 8 }, - errors: ['Missing space before function parentheses.'], + errors: [{ messageId: 'missing' }], }, { code: 'async () => 1', output: 'async() => 1', options: [{ asyncArrow: 'never' }], parserOptions: { ecmaVersion: 8 }, - errors: ['Unexpected space before function parentheses.'], + errors: [{ messageId: 'unexpected' }], }, { code: 'async() => 1', @@ -578,5 +572,5 @@ ruleTester.run('space-before-function-paren', rule, { }, ], }, - ] as TSESLint.InvalidTestCase[], + ], }); diff --git a/packages/eslint-plugin/tools/generate-configs.ts b/packages/eslint-plugin/tools/generate-configs.ts index 6ef602cc8816..6830d266e99f 100644 --- a/packages/eslint-plugin/tools/generate-configs.ts +++ b/packages/eslint-plugin/tools/generate-configs.ts @@ -39,9 +39,10 @@ const BASE_RULES_TO_BE_OVERRIDDEN = new Map( ); const EXTENDS = ['./configs/base', './configs/eslint-recommended']; -const ruleEntries = Object.entries(rules).sort((a, b) => - a[0].localeCompare(b[0]), -); +const ruleEntries: [ + string, + TSESLint.RuleModule, +][] = Object.entries(rules).sort((a, b) => a[0].localeCompare(b[0])); /** * Helper function reduces records to key - value pairs. diff --git a/packages/eslint-plugin/typings/eslint-rules.d.ts b/packages/eslint-plugin/typings/eslint-rules.d.ts index b32a895404d5..c27e620399ee 100644 --- a/packages/eslint-plugin/typings/eslint-rules.d.ts +++ b/packages/eslint-plugin/typings/eslint-rules.d.ts @@ -273,7 +273,11 @@ declare module 'eslint/lib/rules/no-implicit-globals' { import { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils'; const rule: TSESLint.RuleModule< - never, + | 'globalNonLexicalBinding' + | 'globalLexicalBinding' + | 'globalVariableLeak' + | 'assignmentToReadonlyGlobal' + | 'redeclarationOfReadonlyGlobal', [], { Program(node: TSESTree.Program): void; @@ -326,7 +330,7 @@ declare module 'eslint/lib/rules/no-restricted-globals' { import { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils'; const rule: TSESLint.RuleModule< - never, + 'defaultMessage' | 'customMessage', ( | string | { @@ -345,7 +349,7 @@ declare module 'eslint/lib/rules/no-shadow' { import { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils'; const rule: TSESLint.RuleModule< - never, + 'noShadow', [ { builtinGlobals?: boolean; @@ -381,7 +385,7 @@ declare module 'eslint/lib/rules/no-unused-vars' { import { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils'; const rule: TSESLint.RuleModule< - never, + 'unusedVar', ( | 'all' | 'local' @@ -427,7 +431,7 @@ declare module 'eslint/lib/rules/no-use-before-define' { import { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils'; const rule: TSESLint.RuleModule< - never, + 'usedBeforeDefine', ( | 'nofunc' | { @@ -469,7 +473,7 @@ declare module 'eslint/lib/rules/no-useless-constructor' { import { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils'; const rule: TSESLint.RuleModule< - never, + 'noUselessConstructor', [], { MethodDefinition(node: TSESTree.MethodDefinition): void; @@ -535,7 +539,7 @@ declare module 'eslint/lib/rules/semi' { import { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils'; const rule: TSESLint.RuleModule< - never, + 'missingSemi' | 'extraSemi', [ 'always' | 'never', { @@ -565,7 +569,7 @@ declare module 'eslint/lib/rules/quotes' { import { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils'; const rule: TSESLint.RuleModule< - never, + 'wrongQuotes', [ 'single' | 'double' | 'backtick', { @@ -664,7 +668,7 @@ declare module 'eslint/lib/rules/no-invalid-this' { import { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils'; const rule: TSESLint.RuleModule< - never, + 'unexpectedThis', [ { capIsConstructor?: boolean; diff --git a/packages/experimental-utils/src/eslint-utils/RuleTester.ts b/packages/experimental-utils/src/eslint-utils/RuleTester.ts index 07b3a4cf0cf3..ed642c035ba6 100644 --- a/packages/experimental-utils/src/eslint-utils/RuleTester.ts +++ b/packages/experimental-utils/src/eslint-utils/RuleTester.ts @@ -14,6 +14,11 @@ class RuleTester extends TSESLint.RuleTester { constructor(private readonly options: RuleTesterConfig) { super({ ...options, + parserOptions: { + ...options.parserOptions, + warnOnUnsupportedTypeScriptVersion: + options.parserOptions?.warnOnUnsupportedTypeScriptVersion ?? false, + }, parser: require.resolve(options.parser), }); diff --git a/packages/parser/package.json b/packages/parser/package.json index 630a0a61d14f..3131dabaaf94 100644 --- a/packages/parser/package.json +++ b/packages/parser/package.json @@ -39,7 +39,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "peerDependencies": { - "eslint": "^5.0.0 || ^6.0.0" + "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" }, "dependencies": { "@types/eslint-visitor-keys": "^1.0.0", diff --git a/tests/integration/fixtures/markdown/.eslintrc.js b/tests/integration/fixtures/markdown/.eslintrc.js new file mode 100644 index 000000000000..e248633774a0 --- /dev/null +++ b/tests/integration/fixtures/markdown/.eslintrc.js @@ -0,0 +1,25 @@ +module.exports = { + root: true, + // Local version of @typescript-eslint/parser + parser: '@typescript-eslint/parser', + env: { + es6: true, + node: true, + }, + parserOptions: { + sourceType: 'module', + extraFileExtensions: ['.vue'], + ecmaFeatures: { + jsx: true, + }, + }, + plugins: [ + 'markdown', + // Local version of @typescript-eslint/eslint-plugin + '@typescript-eslint', + ], + rules: { + '@typescript-eslint/no-explicit-any': 'error', + 'no-console': 'error', + }, +}; diff --git a/tests/integration/fixtures/markdown/.eslintrc.yml b/tests/integration/fixtures/markdown/.eslintrc.yml deleted file mode 100644 index 92575183cd91..000000000000 --- a/tests/integration/fixtures/markdown/.eslintrc.yml +++ /dev/null @@ -1,23 +0,0 @@ -root: true - -# Local version of @typescript-eslint/parser -parser: '@typescript-eslint/parser' - -env: - es6: true - node: true - -parserOptions: - sourceType: module - extraFileExtensions: ['.vue'] - ecmaFeatures: - jsx: true - -plugins: -- 'markdown' -# Local version of @typescript-eslint/eslint-plugin -- '@typescript-eslint' - -rules: - '@typescript-eslint/no-explicit-any': 'error' - 'no-console': 'error' diff --git a/tests/integration/fixtures/markdown/Dockerfile b/tests/integration/fixtures/markdown/Dockerfile index 3b281e624c87..027ff085a6cf 100644 --- a/tests/integration/fixtures/markdown/Dockerfile +++ b/tests/integration/fixtures/markdown/Dockerfile @@ -1,4 +1,4 @@ -FROM node:carbon +FROM node:erbium # Copy the test.sh into the container. Every other file will be linked, rather # than copied to allow for changes without rebuilds wherever possible diff --git a/tests/integration/fixtures/markdown/test.js.snap b/tests/integration/fixtures/markdown/test.js.snap deleted file mode 100644 index 5f28d2474ea6..000000000000 --- a/tests/integration/fixtures/markdown/test.js.snap +++ /dev/null @@ -1,293 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`it should produce the expected lint ouput 1`] = ` -Array [ - Object { - "errorCount": 10, - "filePath": "/usr/linked/Doc.md", - "fixableErrorCount": 0, - "fixableWarningCount": 0, - "messages": Array [ - Object { - "column": 3, - "endColumn": 14, - "endLine": 8, - "line": 8, - "message": "Unexpected console statement.", - "messageId": "unexpected", - "nodeType": "MemberExpression", - "ruleId": "no-console", - "severity": 2, - }, - Object { - "column": 20, - "endColumn": 23, - "endLine": 26, - "line": 26, - "message": "Unexpected any. Specify a different type.", - "messageId": "unexpectedAny", - "nodeType": "TSAnyKeyword", - "ruleId": "@typescript-eslint/no-explicit-any", - "severity": 2, - "suggestions": Array [ - Object { - "desc": "Use \`unknown\` instead, this will force you to explicitly, and safely assert the type is correct.", - "fix": Object { - "range": Array [ - 51, - 54, - ], - "text": "unknown", - }, - "messageId": "suggestUnknown", - }, - Object { - "desc": "Use \`never\` instead, this is useful when instantiating generic type parameters that you don't need to know the type of.", - "fix": Object { - "range": Array [ - 51, - 54, - ], - "text": "never", - }, - "messageId": "suggestNever", - }, - ], - }, - Object { - "column": 3, - "endColumn": 14, - "endLine": 27, - "line": 27, - "message": "Unexpected console statement.", - "messageId": "unexpected", - "nodeType": "MemberExpression", - "ruleId": "no-console", - "severity": 2, - }, - Object { - "column": 3, - "endColumn": 14, - "endLine": 43, - "line": 43, - "message": "Unexpected console statement.", - "messageId": "unexpected", - "nodeType": "MemberExpression", - "ruleId": "no-console", - "severity": 2, - }, - Object { - "column": 17, - "endColumn": 20, - "endLine": 50, - "line": 50, - "message": "Unexpected any. Specify a different type.", - "messageId": "unexpectedAny", - "nodeType": "TSAnyKeyword", - "ruleId": "@typescript-eslint/no-explicit-any", - "severity": 2, - "suggestions": Array [ - Object { - "desc": "Use \`unknown\` instead, this will force you to explicitly, and safely assert the type is correct.", - "fix": Object { - "range": Array [ - 16, - 19, - ], - "text": "unknown", - }, - "messageId": "suggestUnknown", - }, - Object { - "desc": "Use \`never\` instead, this is useful when instantiating generic type parameters that you don't need to know the type of.", - "fix": Object { - "range": Array [ - 16, - 19, - ], - "text": "never", - }, - "messageId": "suggestNever", - }, - ], - }, - Object { - "column": 3, - "endColumn": 14, - "endLine": 51, - "line": 51, - "message": "Unexpected console statement.", - "messageId": "unexpected", - "nodeType": "MemberExpression", - "ruleId": "no-console", - "severity": 2, - }, - Object { - "column": 17, - "endColumn": 20, - "endLine": 59, - "line": 59, - "message": "Unexpected any. Specify a different type.", - "messageId": "unexpectedAny", - "nodeType": "TSAnyKeyword", - "ruleId": "@typescript-eslint/no-explicit-any", - "severity": 2, - "suggestions": Array [ - Object { - "desc": "Use \`unknown\` instead, this will force you to explicitly, and safely assert the type is correct.", - "fix": Object { - "range": Array [ - 16, - 19, - ], - "text": "unknown", - }, - "messageId": "suggestUnknown", - }, - Object { - "desc": "Use \`never\` instead, this is useful when instantiating generic type parameters that you don't need to know the type of.", - "fix": Object { - "range": Array [ - 16, - 19, - ], - "text": "never", - }, - "messageId": "suggestNever", - }, - ], - }, - Object { - "column": 3, - "endColumn": 14, - "endLine": 60, - "line": 60, - "message": "Unexpected console statement.", - "messageId": "unexpected", - "nodeType": "MemberExpression", - "ruleId": "no-console", - "severity": 2, - }, - Object { - "column": 17, - "endColumn": 20, - "endLine": 68, - "line": 68, - "message": "Unexpected any. Specify a different type.", - "messageId": "unexpectedAny", - "nodeType": "TSAnyKeyword", - "ruleId": "@typescript-eslint/no-explicit-any", - "severity": 2, - "suggestions": Array [ - Object { - "desc": "Use \`unknown\` instead, this will force you to explicitly, and safely assert the type is correct.", - "fix": Object { - "range": Array [ - 16, - 19, - ], - "text": "unknown", - }, - "messageId": "suggestUnknown", - }, - Object { - "desc": "Use \`never\` instead, this is useful when instantiating generic type parameters that you don't need to know the type of.", - "fix": Object { - "range": Array [ - 16, - 19, - ], - "text": "never", - }, - "messageId": "suggestNever", - }, - ], - }, - Object { - "column": 3, - "endColumn": 14, - "endLine": 69, - "line": 69, - "message": "Unexpected console statement.", - "messageId": "unexpected", - "nodeType": "MemberExpression", - "ruleId": "no-console", - "severity": 2, - }, - ], - "source": "Some extra text to verify that the markdown plugin is ignoring anything that is not a code block. - -expected no-console error: -\`\`\`jsx -import { Button } from 'antd'; - -function MyComp() { - console.log('test'); - return ( -
- - - - - -
- ); -} -\`\`\` - -expected no-explicit-any error: -expected no-console error: -\`\`\`jsx -import { Button } from 'antd'; - -function MyComp(): any { - console.log('test'); - return ( -
- - - - - -
- ); -} -\`\`\` - -expected no-console error: -\`\`\`js -function foo() { - console.log('test'); -} -\`\`\` - -expected no-explicit-any error: -expected no-console error: -\`\`\`js -function foo(): any { - console.log('test'); -} -\`\`\` - - -expected no-explicit-any error: -expected no-console error: -\`\`\`javascript -function foo(): any { - console.log('test'); -} -\`\`\` - - -expected no-explicit-any error: -expected no-console error: -\`\`\`node -function foo(): any { - console.log('test'); -} -\`\`\` -", - "warningCount": 0, - }, -] -`; diff --git a/tests/integration/fixtures/markdown/test.sh b/tests/integration/fixtures/markdown/test.sh index 6856a3f7c1b8..356156f60f7f 100755 --- a/tests/integration/fixtures/markdown/test.sh +++ b/tests/integration/fixtures/markdown/test.sh @@ -17,7 +17,7 @@ npm install eslint-plugin-markdown@latest # Run the linting # (the "|| true" helps make sure that we run our tests on failed linting runs as well) -npx eslint --format json --output-file /usr/lint-output.json --config /usr/linked/.eslintrc.yml /usr/linked/**/*.md || true +npx eslint --format json --output-file /usr/lint-output.json --config /usr/linked/.eslintrc.js /usr/linked/**/*.md || true # Run our assertions against the linting output npx jest /usr/test.js --snapshotResolver=/usr/utils/jest-snapshot-resolver.js diff --git a/tests/integration/fixtures/recommended-does-not-require-program/.eslintrc.js b/tests/integration/fixtures/recommended-does-not-require-program/.eslintrc.js new file mode 100644 index 000000000000..85a83dc6e91e --- /dev/null +++ b/tests/integration/fixtures/recommended-does-not-require-program/.eslintrc.js @@ -0,0 +1,18 @@ +// This integration test exists to make sure that the recommended config does +// not require a program to be specified to ensure a fast and simple initial +// setup. Users can add on one of our other configs if they want to opt in to +// more expensive checks. +module.exports = { + root: true, + // Local version of @typescript-eslint/parser + parser: '@typescript-eslint/parser', + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/eslint-recommended', + 'plugin:@typescript-eslint/recommended', + ], + plugins: [ + // Local version of @typescript-eslint/eslint-plugin + '@typescript-eslint', + ], +}; diff --git a/tests/integration/fixtures/recommended-does-not-require-program/.eslintrc.yml b/tests/integration/fixtures/recommended-does-not-require-program/.eslintrc.yml deleted file mode 100644 index 75de006c68de..000000000000 --- a/tests/integration/fixtures/recommended-does-not-require-program/.eslintrc.yml +++ /dev/null @@ -1,17 +0,0 @@ -# This integration test exists to make sure that the recommended config does -# not require a program to be specified to ensure a fast and simple initial -# setup. Users can add on one of our other configs if they want to opt in to -# more expensive checks. -root: true - -# Local version of @typescript-eslint/parser -parser: '@typescript-eslint/parser' - -extends: -- 'eslint:recommended' -- 'plugin:@typescript-eslint/eslint-recommended' -- 'plugin:@typescript-eslint/recommended' - -plugins: -# Local version of @typescript-eslint/eslint-plugin -- '@typescript-eslint' diff --git a/tests/integration/fixtures/recommended-does-not-require-program/Dockerfile b/tests/integration/fixtures/recommended-does-not-require-program/Dockerfile index 3b281e624c87..027ff085a6cf 100644 --- a/tests/integration/fixtures/recommended-does-not-require-program/Dockerfile +++ b/tests/integration/fixtures/recommended-does-not-require-program/Dockerfile @@ -1,4 +1,4 @@ -FROM node:carbon +FROM node:erbium # Copy the test.sh into the container. Every other file will be linked, rather # than copied to allow for changes without rebuilds wherever possible diff --git a/tests/integration/fixtures/recommended-does-not-require-program/test.js.snap b/tests/integration/fixtures/recommended-does-not-require-program/test.js.snap deleted file mode 100644 index 36d059733d53..000000000000 --- a/tests/integration/fixtures/recommended-does-not-require-program/test.js.snap +++ /dev/null @@ -1,44 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`it should produce the expected lint ouput 1`] = ` -Array [ - Object { - "errorCount": 1, - "filePath": "/usr/linked/index.ts", - "fixableErrorCount": 1, - "fixableWarningCount": 0, - "messages": Array [ - Object { - "column": 1, - "endColumn": 15, - "endLine": 1, - "fix": Object { - "range": Array [ - 0, - 3, - ], - "text": "let", - }, - "line": 1, - "message": "Unexpected var, use let or const instead.", - "nodeType": "VariableDeclaration", - "ruleId": "no-var", - "severity": 2, - }, - Object { - "column": 5, - "endColumn": 8, - "endLine": 1, - "line": 1, - "message": "'foo' is assigned a value but never used.", - "nodeType": "Identifier", - "ruleId": "@typescript-eslint/no-unused-vars", - "severity": 1, - }, - ], - "source": "var foo = true -", - "warningCount": 1, - }, -] -`; diff --git a/tests/integration/fixtures/recommended-does-not-require-program/test.sh b/tests/integration/fixtures/recommended-does-not-require-program/test.sh index 4cf1ad5505e6..9abb264733dc 100755 --- a/tests/integration/fixtures/recommended-does-not-require-program/test.sh +++ b/tests/integration/fixtures/recommended-does-not-require-program/test.sh @@ -14,7 +14,7 @@ npm install $(npm pack /usr/eslint-plugin | tail -1) # Run the linting # (the "|| true" helps make sure that we run our tests on failed linting runs as well) -npx eslint --format json --output-file /usr/lint-output.json --config /usr/linked/.eslintrc.yml /usr/linked/**/*.ts || true +npx eslint --format json --output-file /usr/lint-output.json --config /usr/linked/.eslintrc.js /usr/linked/**/*.ts || true # Run our assertions against the linting output npx jest /usr/test.js --snapshotResolver=/usr/utils/jest-snapshot-resolver.js diff --git a/tests/integration/fixtures/typescript-and-tslint-plugins-together/.eslintrc.js b/tests/integration/fixtures/typescript-and-tslint-plugins-together/.eslintrc.js new file mode 100644 index 000000000000..3caad1ed4276 --- /dev/null +++ b/tests/integration/fixtures/typescript-and-tslint-plugins-together/.eslintrc.js @@ -0,0 +1,38 @@ +module.exports = { + "root": true, + // Local version of @typescript-eslint/parser + "parser": "@typescript-eslint/parser", + "plugins": [ + // Local version of @typescript-eslint/eslint-plugin + "@typescript-eslint", + // Local version of @typescript-eslint/eslint-plugin-tslint + "@typescript-eslint/tslint" + ], + "env": { + "es6": true, + "node": true + }, + "extends": [ + "plugin:@typescript-eslint/recommended" + ], + "parserOptions": { + "sourceType": "module", + "ecmaFeatures": { + "jsx": false + }, + "project": "/usr/linked/tsconfig.json" + }, + "rules": { + "@typescript-eslint/tslint/config": [ + "error", + { + "rules": { + "semicolon": [ + true, + "always" + ] + } + } + ] + } +} diff --git a/tests/integration/fixtures/typescript-and-tslint-plugins-together/.eslintrc.yml b/tests/integration/fixtures/typescript-and-tslint-plugins-together/.eslintrc.yml deleted file mode 100644 index 1e7fd8888744..000000000000 --- a/tests/integration/fixtures/typescript-and-tslint-plugins-together/.eslintrc.yml +++ /dev/null @@ -1,25 +0,0 @@ -root: true - -# Local version of @typescript-eslint/parser -parser: '@typescript-eslint/parser' - -plugins: -# Local version of @typescript-eslint/eslint-plugin -- '@typescript-eslint' -# Local version of @typescript-eslint/eslint-plugin-tslint -- '@typescript-eslint/tslint' -env: - es6: true - node: true -extends: -- plugin:@typescript-eslint/recommended -parserOptions: - sourceType: module - ecmaFeatures: - jsx: false - project: /usr/linked/tsconfig.json -rules: - '@typescript-eslint/tslint/config': - - error - - rules: - semicolon: [true, 'always'] diff --git a/tests/integration/fixtures/typescript-and-tslint-plugins-together/Dockerfile b/tests/integration/fixtures/typescript-and-tslint-plugins-together/Dockerfile index 3b281e624c87..027ff085a6cf 100644 --- a/tests/integration/fixtures/typescript-and-tslint-plugins-together/Dockerfile +++ b/tests/integration/fixtures/typescript-and-tslint-plugins-together/Dockerfile @@ -1,4 +1,4 @@ -FROM node:carbon +FROM node:erbium # Copy the test.sh into the container. Every other file will be linked, rather # than copied to allow for changes without rebuilds wherever possible diff --git a/tests/integration/fixtures/typescript-and-tslint-plugins-together/test.js.snap b/tests/integration/fixtures/typescript-and-tslint-plugins-together/test.js.snap index e567daaa2f53..26482bf124b2 100644 --- a/tests/integration/fixtures/typescript-and-tslint-plugins-together/test.js.snap +++ b/tests/integration/fixtures/typescript-and-tslint-plugins-together/test.js.snap @@ -14,6 +14,7 @@ Array [ "endLine": 1, "line": 1, "message": "'noSemi' is assigned a value but never used.", + "messageId": "unusedVar", "nodeType": "Identifier", "ruleId": "@typescript-eslint/no-unused-vars", "severity": 1, @@ -39,6 +40,7 @@ Array [ ], "source": "const noSemi = true ", + "usedDeprecatedRules": Array [], "warningCount": 1, }, ] diff --git a/tests/integration/fixtures/typescript-and-tslint-plugins-together/test.sh b/tests/integration/fixtures/typescript-and-tslint-plugins-together/test.sh index 4746867a40ae..b634d531d5ef 100755 --- a/tests/integration/fixtures/typescript-and-tslint-plugins-together/test.sh +++ b/tests/integration/fixtures/typescript-and-tslint-plugins-together/test.sh @@ -15,7 +15,7 @@ npm install $(npm pack /usr/eslint-plugin | tail -1) # Run the linting # (the "|| true" helps make sure that we run our tests on failed linting runs as well) -npx eslint --format json --output-file /usr/lint-output.json --config /usr/linked/.eslintrc.yml /usr/linked/**/*.ts || true +npx eslint --format json --output-file /usr/lint-output.json --config /usr/linked/.eslintrc.js /usr/linked/**/*.ts || true # Run our assertions against the linting output npx jest /usr/test.js --snapshotResolver=/usr/utils/jest-snapshot-resolver.js diff --git a/tests/integration/fixtures/vue-jsx/.eslintrc.js b/tests/integration/fixtures/vue-jsx/.eslintrc.js new file mode 100644 index 000000000000..c9d88fd01e9f --- /dev/null +++ b/tests/integration/fixtures/vue-jsx/.eslintrc.js @@ -0,0 +1,27 @@ +module.exports = { + root: true, + parser: 'vue-eslint-parser', + env: { + es6: true, + node: true, + }, + extends: [ + 'plugin:vue/essential', + ], + parserOptions: { + // Local version of @typescript-eslint/parser + parser: '@typescript-eslint/parser', + sourceType: 'module', + extraFileExtensions: ['.vue'], + ecmaFeatures: { + jsx: true, + }, + }, + plugins: [ + // Local version of @typescript-eslint/eslint-plugin + '@typescript-eslint', + ], + rules: { + '@typescript-eslint/no-explicit-any': 'error', + }, +}; diff --git a/tests/integration/fixtures/vue-jsx/.eslintrc.yml b/tests/integration/fixtures/vue-jsx/.eslintrc.yml deleted file mode 100644 index ea4319ac718e..000000000000 --- a/tests/integration/fixtures/vue-jsx/.eslintrc.yml +++ /dev/null @@ -1,25 +0,0 @@ -root: true - -parser: 'vue-eslint-parser' - -env: - es6: true - node: true - -extends: - plugin:vue/essential - -parserOptions: - # Local version of @typescript-eslint/parser - parser: '@typescript-eslint/parser' - sourceType: module - extraFileExtensions: ['.vue'] - ecmaFeatures: - jsx: true - -plugins: -# Local version of @typescript-eslint/eslint-plugin -- '@typescript-eslint' - -rules: - '@typescript-eslint/no-explicit-any': 'error' diff --git a/tests/integration/fixtures/vue-jsx/Dockerfile b/tests/integration/fixtures/vue-jsx/Dockerfile index 3b281e624c87..027ff085a6cf 100644 --- a/tests/integration/fixtures/vue-jsx/Dockerfile +++ b/tests/integration/fixtures/vue-jsx/Dockerfile @@ -1,4 +1,4 @@ -FROM node:carbon +FROM node:erbium # Copy the test.sh into the container. Every other file will be linked, rather # than copied to allow for changes without rebuilds wherever possible diff --git a/tests/integration/fixtures/vue-jsx/test.js.snap b/tests/integration/fixtures/vue-jsx/test.js.snap deleted file mode 100644 index e0fbff509d49..000000000000 --- a/tests/integration/fixtures/vue-jsx/test.js.snap +++ /dev/null @@ -1,87 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`it should produce the expected lint ouput 1`] = ` -Array [ - Object { - "errorCount": 1, - "filePath": "/usr/linked/Jsx.vue", - "fixableErrorCount": 0, - "fixableWarningCount": 0, - "messages": Array [ - Object { - "column": 17, - "endColumn": 20, - "endLine": 17, - "line": 17, - "message": "Unexpected any. Specify a different type.", - "messageId": "unexpectedAny", - "nodeType": "TSAnyKeyword", - "ruleId": "@typescript-eslint/no-explicit-any", - "severity": 2, - "suggestions": Array [ - Object { - "desc": "Use \`unknown\` instead, this will force you to explicitly, and safely assert the type is correct.", - "fix": Object { - "range": Array [ - 390, - 393, - ], - "text": "unknown", - }, - "messageId": "suggestUnknown", - }, - Object { - "desc": "Use \`never\` instead, this is useful when instantiating generic type parameters that you don't need to know the type of.", - "fix": Object { - "range": Array [ - 390, - 393, - ], - "text": "never", - }, - "messageId": "suggestNever", - }, - ], - }, - ], - "source": " -", - "warningCount": 0, - }, -] -`; diff --git a/tests/integration/fixtures/vue-jsx/test.sh b/tests/integration/fixtures/vue-jsx/test.sh index 30ec8940d3c0..a484c2625e7f 100755 --- a/tests/integration/fixtures/vue-jsx/test.sh +++ b/tests/integration/fixtures/vue-jsx/test.sh @@ -24,7 +24,7 @@ npm install vue-property-decorator@latest # Run the linting # (the "|| true" helps make sure that we run our tests on failed linting runs as well) -npx eslint --format json --output-file /usr/lint-output.json --config /usr/linked/.eslintrc.yml /usr/linked/**/*.vue || true +npx eslint --format json --output-file /usr/lint-output.json --config /usr/linked/.eslintrc.js /usr/linked/**/*.vue || true # Run our assertions against the linting output npx jest /usr/test.js --snapshotResolver=/usr/utils/jest-snapshot-resolver.js diff --git a/tests/integration/fixtures/vue-sfc/.eslintrc.js b/tests/integration/fixtures/vue-sfc/.eslintrc.js new file mode 100644 index 000000000000..7be44347c59c --- /dev/null +++ b/tests/integration/fixtures/vue-sfc/.eslintrc.js @@ -0,0 +1,25 @@ +module.exports = { + root: true, + parser: 'vue-eslint-parser', + env: { + es6: true, + node: true, + }, + extends: [ + 'plugin:vue/essential', + ], + parserOptions: { + // Local version of @typescript-eslint/parser + parser: '@typescript-eslint/parser', + project: '/usr/linked/tsconfig.json', + sourceType: 'module', + extraFileExtensions: ['.vue'], + }, + plugins: [ + // Local version of @typescript-eslint/eslint-plugin + '@typescript-eslint', + ], + rules: { + '@typescript-eslint/no-explicit-any': 'error', + }, +}; diff --git a/tests/integration/fixtures/vue-sfc/.eslintrc.yml b/tests/integration/fixtures/vue-sfc/.eslintrc.yml deleted file mode 100644 index 7b9b183b59bc..000000000000 --- a/tests/integration/fixtures/vue-sfc/.eslintrc.yml +++ /dev/null @@ -1,24 +0,0 @@ -root: true - -parser: 'vue-eslint-parser' - -env: - es6: true - node: true - -extends: - plugin:vue/essential - -parserOptions: - # Local version of @typescript-eslint/parser - parser: '@typescript-eslint/parser' - project: /usr/linked/tsconfig.json - sourceType: module - extraFileExtensions: ['.vue'] - -plugins: -# Local version of @typescript-eslint/eslint-plugin -- '@typescript-eslint' - -rules: - '@typescript-eslint/no-explicit-any': 'error' diff --git a/tests/integration/fixtures/vue-sfc/Dockerfile b/tests/integration/fixtures/vue-sfc/Dockerfile index 3b281e624c87..027ff085a6cf 100644 --- a/tests/integration/fixtures/vue-sfc/Dockerfile +++ b/tests/integration/fixtures/vue-sfc/Dockerfile @@ -1,4 +1,4 @@ -FROM node:carbon +FROM node:erbium # Copy the test.sh into the container. Every other file will be linked, rather # than copied to allow for changes without rebuilds wherever possible diff --git a/tests/integration/fixtures/vue-sfc/test.js.snap b/tests/integration/fixtures/vue-sfc/test.js.snap deleted file mode 100644 index 37b5cb943cf3..000000000000 --- a/tests/integration/fixtures/vue-sfc/test.js.snap +++ /dev/null @@ -1,95 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`it should produce the expected lint ouput 1`] = ` -Array [ - Object { - "errorCount": 1, - "filePath": "/usr/linked/Hello.vue", - "fixableErrorCount": 0, - "fixableWarningCount": 0, - "messages": Array [ - Object { - "column": 29, - "endColumn": 32, - "endLine": 31, - "line": 31, - "message": "Unexpected any. Specify a different type.", - "messageId": "unexpectedAny", - "nodeType": "TSAnyKeyword", - "ruleId": "@typescript-eslint/no-explicit-any", - "severity": 2, - "suggestions": Array [ - Object { - "desc": "Use \`unknown\` instead, this will force you to explicitly, and safely assert the type is correct.", - "fix": Object { - "range": Array [ - 708, - 711, - ], - "text": "unknown", - }, - "messageId": "suggestUnknown", - }, - Object { - "desc": "Use \`never\` instead, this is useful when instantiating generic type parameters that you don't need to know the type of.", - "fix": Object { - "range": Array [ - 708, - 711, - ], - "text": "never", - }, - "messageId": "suggestNever", - }, - ], - }, - ], - "source": " - - - -", - "warningCount": 0, - }, - Object { - "errorCount": 0, - "filePath": "/usr/linked/World.vue", - "fixableErrorCount": 0, - "fixableWarningCount": 0, - "messages": Array [], - "warningCount": 0, - }, -] -`; diff --git a/tests/integration/fixtures/vue-sfc/test.sh b/tests/integration/fixtures/vue-sfc/test.sh index 30ec8940d3c0..a484c2625e7f 100755 --- a/tests/integration/fixtures/vue-sfc/test.sh +++ b/tests/integration/fixtures/vue-sfc/test.sh @@ -24,7 +24,7 @@ npm install vue-property-decorator@latest # Run the linting # (the "|| true" helps make sure that we run our tests on failed linting runs as well) -npx eslint --format json --output-file /usr/lint-output.json --config /usr/linked/.eslintrc.yml /usr/linked/**/*.vue || true +npx eslint --format json --output-file /usr/lint-output.json --config /usr/linked/.eslintrc.js /usr/linked/**/*.vue || true # Run our assertions against the linting output npx jest /usr/test.js --snapshotResolver=/usr/utils/jest-snapshot-resolver.js diff --git a/tests/integration/utils/jsconfig.json b/tests/integration/utils/jsconfig.json index d53d21eadfbb..984f1f4c0780 100644 --- a/tests/integration/utils/jsconfig.json +++ b/tests/integration/utils/jsconfig.json @@ -1,3 +1,7 @@ { - "exclude": [".eslintrc.js"] + "include": [ + ".eslintrc.js", + "jest-snapshot-resolver.js", + "generate-package-json.js" + ] } diff --git a/yarn.lock b/yarn.lock index 397043be8f60..9ccd008ee131 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2356,7 +2356,7 @@ caseless@~0.12.0: resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= -chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4.1, chalk@^2.4.2: +chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -2809,7 +2809,7 @@ cosmiconfig@^6.0.0: path-type "^4.0.0" yaml "^1.7.2" -cross-spawn@^6.0.0, cross-spawn@^6.0.5: +cross-spawn@^6.0.0: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== @@ -2820,7 +2820,7 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^7.0.0: +cross-spawn@^7.0.0, cross-spawn@^7.0.2: version "7.0.2" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.2.tgz#d0d7dcfa74e89115c7619f4f721a94e1fdb716d6" integrity sha512-PD6G8QG3S4FK/XCGFbEQrDqO2AnMMsy0meR7lerlIOHAAbkuavGU/pOqprrlvfTNjvowivTeBsjebAL0NSoMxw== @@ -3226,7 +3226,7 @@ deep-extend@~0.5.1: resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.5.1.tgz#b894a9dd90d3023fbf1c55a394fb858eb2066f1f" integrity sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w== -deep-is@~0.1.3: +deep-is@^0.1.3, deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= @@ -3583,13 +3583,6 @@ eslint-scope@^5.0.0: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint-utils@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" - integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== - dependencies: - eslint-visitor-keys "^1.1.0" - eslint-utils@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.0.0.tgz#7be1cc70f27a72a76cd14aa698bcabed6890e1cd" @@ -3602,22 +3595,22 @@ 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@^6.7.0: - version "6.8.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb" - integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig== +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== dependencies: "@babel/code-frame" "^7.0.0" ajv "^6.10.0" - chalk "^2.1.0" - cross-spawn "^6.0.5" + chalk "^4.0.0" + cross-spawn "^7.0.2" debug "^4.0.1" doctrine "^3.0.0" eslint-scope "^5.0.0" - eslint-utils "^1.4.3" + eslint-utils "^2.0.0" eslint-visitor-keys "^1.1.0" - espree "^6.1.2" - esquery "^1.0.1" + espree "^7.0.0" + esquery "^1.2.0" esutils "^2.0.2" file-entry-cache "^5.0.1" functional-red-black-tree "^1.0.1" @@ -3630,25 +3623,24 @@ eslint@^6.7.0: is-glob "^4.0.0" js-yaml "^3.13.1" json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" + levn "^0.4.1" lodash "^4.17.14" minimatch "^3.0.4" - mkdirp "^0.5.1" natural-compare "^1.4.0" - optionator "^0.8.3" + optionator "^0.9.1" progress "^2.0.0" - regexpp "^2.0.1" - semver "^6.1.2" - strip-ansi "^5.2.0" - strip-json-comments "^3.0.1" + regexpp "^3.1.0" + semver "^7.2.1" + strip-ansi "^6.0.0" + strip-json-comments "^3.1.0" table "^5.2.3" text-table "^0.2.0" v8-compile-cache "^2.0.3" -espree@^6.1.2: - version "6.2.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a" - integrity sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw== +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== dependencies: acorn "^7.1.1" acorn-jsx "^5.2.0" @@ -3664,7 +3656,7 @@ esprima@^4.0.0, esprima@^4.0.1: resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.0.1: +esquery@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.3.1.tgz#b78b5828aa8e214e29fb74c4d5b752e1c033da57" integrity sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ== @@ -3859,7 +3851,7 @@ fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== -fast-levenshtein@~2.0.6: +fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= @@ -5598,7 +5590,15 @@ leven@^3.1.0: resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== -levn@^0.3.0, levn@~0.3.0: +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= @@ -6569,7 +6569,7 @@ opencollective-postinstall@^2.0.2: resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz#5657f1bede69b6e33a45939b061eb53d3c6c3a89" integrity sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw== -optionator@^0.8.1, optionator@^0.8.3: +optionator@^0.8.1: version "0.8.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== @@ -6581,6 +6581,18 @@ optionator@^0.8.1, optionator@^0.8.3: type-check "~0.3.2" word-wrap "~1.2.3" +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + os-homedir@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" @@ -6958,6 +6970,11 @@ posix-character-classes@^0.1.0: resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" @@ -7292,12 +7309,7 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexpp@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" - integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== - -regexpp@^3.0.0: +regexpp@^3.0.0, regexpp@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== @@ -7574,12 +7586,12 @@ semver-regex@^2.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@6.3.0, semver@6.x, semver@^6.0.0, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: +semver@6.3.0, semver@6.x, semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.3.2: +semver@^7.2.1, semver@^7.3.2: version "7.3.2" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== @@ -8073,7 +8085,7 @@ strip-json-comments@3.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7" integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw== -strip-json-comments@^3.0.1: +strip-json-comments@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.0.tgz#7638d31422129ecf4457440009fba03f9f9ac180" integrity sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w== @@ -8402,6 +8414,13 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" @@ -8722,7 +8741,7 @@ windows-release@^3.1.0: dependencies: execa "^1.0.0" -word-wrap@^1.0.3, word-wrap@~1.2.3: +word-wrap@^1.0.3, word-wrap@^1.2.3, word-wrap@~1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== From 06869c9656fa37936126666845aee40aad546ebd Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Thu, 14 May 2020 01:16:30 -0700 Subject: [PATCH 26/33] feat(experimental-utils): upgrade eslint types for v7 (#2023) --- .cspell.json | 2 + .../eslint-plugin/src/rules/array-type.ts | 2 +- .../indent-new-do-not-use/OffsetStorage.ts | 6 +- .../src/rules/no-unused-expressions.ts | 5 +- .../eslint-plugin/src/rules/no-unused-vars.ts | 5 +- .../src/rules/space-before-function-paren.ts | 2 +- packages/eslint-plugin/src/util/index.ts | 14 +- packages/eslint-plugin/src/util/misc.ts | 28 -- .../rules/no-unused-vars-experimental.test.ts | 9 +- .../src/eslint-utils/InferTypesFromRule.ts | 26 + .../src/eslint-utils/RuleCreator.ts | 16 +- .../src/eslint-utils/RuleTester.ts | 32 +- .../src/eslint-utils/index.ts | 1 + .../src/ts-eslint/CLIEngine.ts | 110 ++++- .../src/ts-eslint/ESLint.ts | 352 ++++++++++++++ .../src/ts-eslint/Linter.ts | 328 ++++++++++--- .../src/ts-eslint/ParserOptions.ts | 5 +- .../experimental-utils/src/ts-eslint/Rule.ts | 37 +- .../src/ts-eslint/RuleTester.ts | 173 +++++-- .../src/ts-eslint/SourceCode.ts | 451 +++++++++++++----- .../experimental-utils/typings/eslint.d.ts | 3 +- packages/parser/tests/lib/basics.ts | 26 +- 22 files changed, 1311 insertions(+), 322 deletions(-) create mode 100644 packages/experimental-utils/src/eslint-utils/InferTypesFromRule.ts create mode 100644 packages/experimental-utils/src/ts-eslint/ESLint.ts diff --git a/.cspell.json b/.cspell.json index 86a9b7af4f9c..2d939d1b4a3c 100644 --- a/.cspell.json +++ b/.cspell.json @@ -40,6 +40,7 @@ "ASTs", "autofix", "autofixers", + "autofixes", "backticks", "bigint", "bivariant", @@ -70,6 +71,7 @@ "performant", "pluggable", "postprocess", + "postprocessor", "Premade", "prettier's", "recurse", diff --git a/packages/eslint-plugin/src/rules/array-type.ts b/packages/eslint-plugin/src/rules/array-type.ts index de3cca753436..a1ee754f2344 100644 --- a/packages/eslint-plugin/src/rules/array-type.ts +++ b/packages/eslint-plugin/src/rules/array-type.ts @@ -147,7 +147,7 @@ export default util.createRule({ } const nextToken = sourceCode.getTokenAfter(prevToken); - if (nextToken && sourceCode.isSpaceBetweenTokens(prevToken, nextToken)) { + if (nextToken && sourceCode.isSpaceBetween(prevToken, nextToken)) { return false; } diff --git a/packages/eslint-plugin/src/rules/indent-new-do-not-use/OffsetStorage.ts b/packages/eslint-plugin/src/rules/indent-new-do-not-use/OffsetStorage.ts index 082ca05129d2..d19334672630 100644 --- a/packages/eslint-plugin/src/rules/indent-new-do-not-use/OffsetStorage.ts +++ b/packages/eslint-plugin/src/rules/indent-new-do-not-use/OffsetStorage.ts @@ -273,9 +273,11 @@ export class OffsetStorage { * Gets the first token that the given token's indentation is dependent on * @returns The token that the given token depends on, or `null` if the given token is at the top level */ + getFirstDependency( + token: Exclude, + ): Exclude | null; getFirstDependency(token: TSESTree.Token): TSESTree.Token | null; - getFirstDependency(token: TokenOrComment): TokenOrComment | null; - getFirstDependency(token: TokenOrComment): TokenOrComment | null { + getFirstDependency(token: TSESTree.Token): TSESTree.Token | null { return this.getOffsetDescriptor(token).from; } } diff --git a/packages/eslint-plugin/src/rules/no-unused-expressions.ts b/packages/eslint-plugin/src/rules/no-unused-expressions.ts index 9aa41a612318..9977f10c140e 100644 --- a/packages/eslint-plugin/src/rules/no-unused-expressions.ts +++ b/packages/eslint-plugin/src/rules/no-unused-expressions.ts @@ -2,7 +2,10 @@ import { AST_NODE_TYPES } from '@typescript-eslint/experimental-utils'; import baseRule from 'eslint/lib/rules/no-unused-expressions'; import * as util from '../util'; -export default util.createRule({ +type MessageIds = util.InferMessageIdsTypeFromRule; +type Options = util.InferOptionsTypeFromRule; + +export default util.createRule({ name: 'no-unused-expressions', meta: { type: 'suggestion', diff --git a/packages/eslint-plugin/src/rules/no-unused-vars.ts b/packages/eslint-plugin/src/rules/no-unused-vars.ts index b939f8214a92..2c3595f3ba27 100644 --- a/packages/eslint-plugin/src/rules/no-unused-vars.ts +++ b/packages/eslint-plugin/src/rules/no-unused-vars.ts @@ -5,7 +5,10 @@ import { import baseRule from 'eslint/lib/rules/no-unused-vars'; import * as util from '../util'; -export default util.createRule({ +type MessageIds = util.InferMessageIdsTypeFromRule; +type Options = util.InferOptionsTypeFromRule; + +export default util.createRule({ name: 'no-unused-vars', meta: { type: 'problem', diff --git a/packages/eslint-plugin/src/rules/space-before-function-paren.ts b/packages/eslint-plugin/src/rules/space-before-function-paren.ts index 41a817938dac..5b7f8fd6e047 100644 --- a/packages/eslint-plugin/src/rules/space-before-function-paren.ts +++ b/packages/eslint-plugin/src/rules/space-before-function-paren.ts @@ -145,7 +145,7 @@ export default util.createRule({ rightToken = sourceCode.getFirstToken(node, util.isOpeningParenToken)!; leftToken = sourceCode.getTokenBefore(rightToken)!; } - const hasSpacing = sourceCode.isSpaceBetweenTokens(leftToken, rightToken); + const hasSpacing = sourceCode.isSpaceBetween(leftToken, rightToken); if (hasSpacing && functionConfig === 'never') { context.report({ diff --git a/packages/eslint-plugin/src/util/index.ts b/packages/eslint-plugin/src/util/index.ts index 2a0d891f5f1f..82828f138932 100644 --- a/packages/eslint-plugin/src/util/index.ts +++ b/packages/eslint-plugin/src/util/index.ts @@ -15,4 +15,16 @@ const { isObjectNotArray, getParserServices, } = ESLintUtils; -export { applyDefault, deepMerge, isObjectNotArray, getParserServices }; +type InferMessageIdsTypeFromRule = ESLintUtils.InferMessageIdsTypeFromRule< + T +>; +type InferOptionsTypeFromRule = ESLintUtils.InferOptionsTypeFromRule; + +export { + applyDefault, + deepMerge, + isObjectNotArray, + getParserServices, + InferMessageIdsTypeFromRule, + InferOptionsTypeFromRule, +}; diff --git a/packages/eslint-plugin/src/util/misc.ts b/packages/eslint-plugin/src/util/misc.ts index e9f50fd2107e..2e6c4711cb0d 100644 --- a/packages/eslint-plugin/src/util/misc.ts +++ b/packages/eslint-plugin/src/util/misc.ts @@ -22,32 +22,6 @@ function upperCaseFirst(str: string): string { return str[0].toUpperCase() + str.slice(1); } -type InferOptionsTypeFromRuleNever = T extends TSESLint.RuleModule< - never, - infer TOptions -> - ? TOptions - : unknown; -/** - * Uses type inference to fetch the TOptions type from the given RuleModule - */ -type InferOptionsTypeFromRule = T extends TSESLint.RuleModule< - string, - infer TOptions -> - ? TOptions - : InferOptionsTypeFromRuleNever; - -/** - * Uses type inference to fetch the TMessageIds type from the given RuleModule - */ -type InferMessageIdsTypeFromRule = T extends TSESLint.RuleModule< - infer TMessageIds, - unknown[] -> - ? TMessageIds - : unknown; - /** Return true if both parameters are equal. */ type Equal = (a: T, b: T) => boolean; @@ -136,8 +110,6 @@ export { getEnumNames, getNameFromIndexSignature, getNameFromMember, - InferMessageIdsTypeFromRule, - InferOptionsTypeFromRule, isDefinitionFile, RequireKeys, upperCaseFirst, diff --git a/packages/eslint-plugin/tests/rules/no-unused-vars-experimental.test.ts b/packages/eslint-plugin/tests/rules/no-unused-vars-experimental.test.ts index 172dfdd793a0..19e36292f03c 100644 --- a/packages/eslint-plugin/tests/rules/no-unused-vars-experimental.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unused-vars-experimental.test.ts @@ -23,12 +23,15 @@ const hasExport = /^export/m; function makeExternalModule< T extends ValidTestCase | InvalidTestCase >(tests: T[]): T[] { - tests.forEach(t => { + return tests.map(t => { if (!hasExport.test(t.code)) { - t.code = `${t.code}\nexport const __externalModule = 1;`; + return { + ...t, + code: `${t.code}\nexport const __externalModule = 1;`, + }; } + return t; }); - return tests; } const DEFAULT_IGNORED_REGEX = new RegExp( diff --git a/packages/experimental-utils/src/eslint-utils/InferTypesFromRule.ts b/packages/experimental-utils/src/eslint-utils/InferTypesFromRule.ts new file mode 100644 index 000000000000..66e5b1153c3a --- /dev/null +++ b/packages/experimental-utils/src/eslint-utils/InferTypesFromRule.ts @@ -0,0 +1,26 @@ +import { RuleModule } from '../ts-eslint'; + +type InferOptionsTypeFromRuleNever = T extends RuleModule< + never, + infer TOptions +> + ? TOptions + : unknown; +/** + * Uses type inference to fetch the TOptions type from the given RuleModule + */ +type InferOptionsTypeFromRule = T extends RuleModule + ? TOptions + : InferOptionsTypeFromRuleNever; + +/** + * Uses type inference to fetch the TMessageIds type from the given RuleModule + */ +type InferMessageIdsTypeFromRule = T extends RuleModule< + infer TMessageIds, + unknown[] +> + ? TMessageIds + : unknown; + +export { InferOptionsTypeFromRule, InferMessageIdsTypeFromRule }; diff --git a/packages/experimental-utils/src/eslint-utils/RuleCreator.ts b/packages/experimental-utils/src/eslint-utils/RuleCreator.ts index 4dede52bd7c6..ca1cfb3302e2 100644 --- a/packages/experimental-utils/src/eslint-utils/RuleCreator.ts +++ b/packages/experimental-utils/src/eslint-utils/RuleCreator.ts @@ -7,7 +7,7 @@ import { } from '../ts-eslint/Rule'; import { applyDefault } from './applyDefault'; -// we'll automatically add the url + tslint description for people. +// we automatically add the url type CreateRuleMetaDocs = Omit; type CreateRuleMeta = { docs: CreateRuleMetaDocs; @@ -25,15 +25,15 @@ function RuleCreator(urlCreator: (ruleName: string) => string) { meta, defaultOptions, create, - }: { + }: Readonly<{ name: string; meta: CreateRuleMeta; - defaultOptions: TOptions; + defaultOptions: Readonly; create: ( - context: RuleContext, - optionsWithDefault: TOptions, + context: Readonly>, + optionsWithDefault: Readonly, ) => TRuleListener; - }): RuleModule { + }>): RuleModule { return { meta: { ...meta, @@ -42,7 +42,9 @@ function RuleCreator(urlCreator: (ruleName: string) => string) { url: urlCreator(name), }, }, - create(context): TRuleListener { + create( + context: Readonly>, + ): TRuleListener { const optionsWithDefault = applyDefault( defaultOptions, context.options, diff --git a/packages/experimental-utils/src/eslint-utils/RuleTester.ts b/packages/experimental-utils/src/eslint-utils/RuleTester.ts index ed642c035ba6..ce5674d9c65c 100644 --- a/packages/experimental-utils/src/eslint-utils/RuleTester.ts +++ b/packages/experimental-utils/src/eslint-utils/RuleTester.ts @@ -1,5 +1,5 @@ -import * as TSESLint from '../ts-eslint'; import * as path from 'path'; +import * as TSESLint from '../ts-eslint'; const parser = '@typescript-eslint/parser'; @@ -8,10 +8,12 @@ type RuleTesterConfig = Omit & { }; class RuleTester extends TSESLint.RuleTester { + readonly #options: RuleTesterConfig; + // as of eslint 6 you have to provide an absolute path to the parser // but that's not as clean to type, this saves us trying to manually enforce // that contributors require.resolve everything - constructor(private readonly options: RuleTesterConfig) { + constructor(options: RuleTesterConfig) { super({ ...options, parserOptions: { @@ -22,6 +24,8 @@ class RuleTester extends TSESLint.RuleTester { parser: require.resolve(options.parser), }); + this.#options = options; + // make sure that the parser doesn't hold onto file handles between tests // on linux (i.e. our CI env), there can be very a limited number of watch handles available afterAll(() => { @@ -49,8 +53,8 @@ class RuleTester extends TSESLint.RuleTester { } return filename; - } else if (this.options.parserOptions) { - return this.getFilename(this.options.parserOptions); + } else if (this.#options.parserOptions) { + return this.getFilename(this.#options.parserOptions); } return 'file.ts'; @@ -62,10 +66,12 @@ class RuleTester extends TSESLint.RuleTester { run>( name: string, rule: TSESLint.RuleModule, - tests: TSESLint.RunTests, + testsReadonly: TSESLint.RunTests, ): void { const errorMessage = `Do not set the parser at the test level unless you want to use a parser other than ${parser}`; + const tests = { ...testsReadonly }; + // standardize the valid tests as objects tests.valid = tests.valid.map(test => { if (typeof test === 'string') { @@ -76,23 +82,31 @@ class RuleTester extends TSESLint.RuleTester { return test; }); - tests.valid.forEach(test => { + tests.valid = tests.valid.map(test => { if (typeof test !== 'string') { if (test.parser === parser) { throw new Error(errorMessage); } if (!test.filename) { - test.filename = this.getFilename(test.parserOptions); + return { + ...test, + filename: this.getFilename(test.parserOptions), + }; } } + return test; }); - tests.invalid.forEach(test => { + tests.invalid = tests.invalid.map(test => { if (test.parser === parser) { throw new Error(errorMessage); } if (!test.filename) { - test.filename = this.getFilename(test.parserOptions); + return { + ...test, + filename: this.getFilename(test.parserOptions), + }; } + return test; }); super.run(name, rule, tests); diff --git a/packages/experimental-utils/src/eslint-utils/index.ts b/packages/experimental-utils/src/eslint-utils/index.ts index 60452e9aca44..bbbe8df2709f 100644 --- a/packages/experimental-utils/src/eslint-utils/index.ts +++ b/packages/experimental-utils/src/eslint-utils/index.ts @@ -1,6 +1,7 @@ export * from './applyDefault'; export * from './batchedSingleLineTests'; export * from './getParserServices'; +export * from './InferTypesFromRule'; export * from './RuleCreator'; export * from './RuleTester'; export * from './deepMerge'; diff --git a/packages/experimental-utils/src/ts-eslint/CLIEngine.ts b/packages/experimental-utils/src/ts-eslint/CLIEngine.ts index 4c640d35c91b..fec56c17b410 100644 --- a/packages/experimental-utils/src/ts-eslint/CLIEngine.ts +++ b/packages/experimental-utils/src/ts-eslint/CLIEngine.ts @@ -2,22 +2,70 @@ import { CLIEngine as ESLintCLIEngine } from 'eslint'; import { Linter } from './Linter'; -import { RuleMetaData, RuleModule, RuleListener } from './Rule'; - -interface CLIEngine { +import { RuleListener, RuleMetaData, RuleModule } from './Rule'; + +declare class CLIEngineBase { + /** + * Creates a new instance of the core CLI engine. + * @param providedOptions The options for this instance. + */ + constructor(options: CLIEngine.Options); + + /** + * Add a plugin by passing its configuration + * @param name Name of the plugin. + * @param pluginObject Plugin configuration object. + */ + addPlugin(name: string, pluginObject: Linter.Plugin): void; + + /** + * Executes the current configuration on an array of file and directory names. + * @param patterns An array of file and directory names. + * @returns The results for all files that were linted. + */ executeOnFiles(patterns: string[]): CLIEngine.LintReport; - resolveFileGlobPatterns(patterns: string[]): string[]; - + /** + * Executes the current configuration on text. + * @param text A string of JavaScript code to lint. + * @param filename An optional string representing the texts filename. + * @param warnIgnored Always warn when a file is ignored + * @returns The results for the linting. + */ + executeOnText( + text: string, + filename?: string, + warnIgnored?: boolean, + ): CLIEngine.LintReport; + + /** + * Returns a configuration object for the given file based on the CLI options. + * This is the same logic used by the ESLint CLI executable to determine configuration for each file it processes. + * @param filePath The path of the file to retrieve a config object for. + * @returns A configuration object for the file. + */ getConfigForFile(filePath: string): Linter.Config; - executeOnText(text: string, filename?: string): CLIEngine.LintReport; - - addPlugin(name: string, pluginObject: unknown): void; + /** + * Returns the formatter representing the given format. + * @param format The name of the format to load or the path to a custom formatter. + * @returns The formatter function. + */ + getFormatter(format?: string): CLIEngine.Formatter; + /** + * Checks if a given path is ignored by ESLint. + * @param filePath The path of the file to check. + * @returns Whether or not the given path is ignored. + */ isPathIgnored(filePath: string): boolean; - getFormatter(format?: string): CLIEngine.Formatter; + /** + * Resolves the patterns passed into `executeOnFiles()` into glob-based patterns for easier handling. + * @param patterns The file patterns passed on the command line. + * @returns The equivalent glob patterns. + */ + resolveFileGlobPatterns(patterns: string[]): string[]; getRules< TMessageIds extends string = string, @@ -25,6 +73,34 @@ interface CLIEngine { // for extending base rules TRuleListener extends RuleListener = RuleListener >(): Map>; + + //////////////////// + // static members // + //////////////////// + + /** + * Returns results that only contains errors. + * @param results The results to filter. + * @returns The filtered results. + */ + static getErrorResults( + results: CLIEngine.LintResult[], + ): CLIEngine.LintResult[]; + + /** + * Returns the formatter representing the given format or null if the `format` is not a string. + * @param format The name of the format to load or the path to a custom formatter. + * @returns The formatter function. + */ + static getFormatter(format?: string): CLIEngine.Formatter; + + /** + * Outputs fixes from the given results to files. + * @param report The report object created by CLIEngine. + */ + static outputFixes(report: CLIEngine.LintReport): void; + + static version: string; } namespace CLIEngine { @@ -93,14 +169,12 @@ namespace CLIEngine { ) => string; } -const CLIEngine = ESLintCLIEngine as { - new (options: CLIEngine.Options): CLIEngine; - - // static methods - getErrorResults(results: CLIEngine.LintResult[]): CLIEngine.LintResult[]; - getFormatter(format?: string): CLIEngine.Formatter; - outputFixes(report: CLIEngine.LintReport): void; - version: string; -}; +/** + * The underlying utility that runs the ESLint command line interface. This object will read the filesystem for + * configuration and file information but will not output any results. Instead, it allows you direct access to the + * important information so you can deal with the output yourself. + * @deprecated use the ESLint class instead + */ +class CLIEngine extends (ESLintCLIEngine as typeof CLIEngineBase) {} export { CLIEngine }; diff --git a/packages/experimental-utils/src/ts-eslint/ESLint.ts b/packages/experimental-utils/src/ts-eslint/ESLint.ts new file mode 100644 index 000000000000..9ced6ed64702 --- /dev/null +++ b/packages/experimental-utils/src/ts-eslint/ESLint.ts @@ -0,0 +1,352 @@ +/* eslint-disable @typescript-eslint/no-namespace */ + +import { ESLint as ESLintESLint } from 'eslint'; +import { Linter } from './Linter'; + +declare class ESLintBase { + /** + * Creates a new instance of the main ESLint API. + * @param options The options for this instance. + */ + constructor(options?: ESLint.ESLintOptions); + + /** + * This method calculates the configuration for a given file, which can be useful for debugging purposes. + * - It resolves and merges extends and overrides settings into the top level configuration. + * - It resolves the parser setting to absolute paths. + * - It normalizes the plugins setting to align short names. (e.g., eslint-plugin-foo → foo) + * - It adds the processor setting if a legacy file extension processor is matched. + * - It doesn't interpret the env setting to the globals and parserOptions settings, so the result object contains + * the env setting as is. + * @param filePath The path to the file whose configuration you would like to calculate. Directory paths are forbidden + * because ESLint cannot handle the overrides setting. + * @returns The promise that will be fulfilled with a configuration object. + */ + calculateConfigForFile(filePath: string): Promise; + /** + * This method checks if a given file is ignored by your configuration. + * @param filePath The path to the file you want to check. + * @returns The promise that will be fulfilled with whether the file is ignored or not. If the file is ignored, then + * it will return true. + */ + isPathIgnored(filePath: string): Promise; + /** + * This method lints the files that match the glob patterns and then returns the results. + * @param patterns The lint target files. This can contain any of file paths, directory paths, and glob patterns. + * @returns The promise that will be fulfilled with an array of LintResult objects. + */ + lintFiles(patterns: string | string[]): Promise; + /** + * This method lints the given source code text and then returns the results. + * + * By default, this method uses the configuration that applies to files in the current working directory (the cwd + * constructor option). If you want to use a different configuration, pass options.filePath, and ESLint will load the + * same configuration that eslint.lintFiles() would use for a file at options.filePath. + * + * If the options.filePath value is configured to be ignored, this method returns an empty array. If the + * options.warnIgnored option is set along with the options.filePath option, this method returns a LintResult object. + * In that case, the result may contain a warning that indicates the file was ignored. + * @param code The source code text to check. + * @param options The options. + * @returns The promise that will be fulfilled with an array of LintResult objects. This is an array (despite there + * being only one lint result) in order to keep the interfaces between this and the eslint.lintFiles() + * method similar. + */ + lintText( + code: string, + options?: ESLint.LintTextOptions, + ): Promise; + /** + * This method loads a formatter. Formatters convert lint results to a human- or machine-readable string. + * @param name TThe path to the file you want to check. + * The following values are allowed: + * - undefined. In this case, loads the "stylish" built-in formatter. + * - A name of built-in formatters. + * - A name of third-party formatters. For examples: + * -- `foo` will load eslint-formatter-foo. + * -- `@foo` will load `@foo/eslint-formatter`. + * -- `@foo/bar` will load `@foo/eslint-formatter-bar`. + * - A path to the file that defines a formatter. The path must contain one or more path separators (/) in order to distinguish if it's a path or not. For example, start with ./. + * @returns The promise that will be fulfilled with a Formatter object. + */ + loadFormatter(name?: string): Promise; + + //////////////////// + // static members // + //////////////////// + + /** + * This method copies the given results and removes warnings. The returned value contains only errors. + * @param results The LintResult objects to filter. + * @returns The filtered LintResult objects. + */ + static getErrorResults(results: ESLint.LintResult): ESLint.LintResult; + /** + * This method writes code modified by ESLint's autofix feature into its respective file. If any of the modified + * files don't exist, this method does nothing. + * @param results The LintResult objects to write. + * @returns The promise that will be fulfilled after all files are written. + */ + static outputFixes(results: ESLint.LintResult): Promise; + /** + * The version text. + */ + static readonly version: string; +} + +namespace ESLint { + export interface ESLintOptions { + /** + * If false is present, ESLint suppresses directive comments in source code. + * If this option is false, it overrides the noInlineConfig setting in your configurations. + */ + allowInlineConfig?: boolean; + /** + * Configuration object, extended by all configurations used with this instance. + * You can use this option to define the default settings that will be used if your configuration files don't + * configure it. + */ + baseConfig?: Linter.Config | null; + /** + * If true is present, the eslint.lintFiles() method caches lint results and uses it if each target file is not + * changed. Please mind that ESLint doesn't clear the cache when you upgrade ESLint plugins. In that case, you have + * to remove the cache file manually. The eslint.lintText() method doesn't use caches even if you pass the + * options.filePath to the method. + */ + cache?: boolean; + /** + * The eslint.lintFiles() method writes caches into this file. + */ + cacheLocation?: string; + /** + * The working directory. This must be an absolute path. + */ + cwd?: string; + /** + * Unless set to false, the eslint.lintFiles() method will throw an error when no target files are found. + */ + errorOnUnmatchedPattern?: boolean; + /** + * If you pass directory paths to the eslint.lintFiles() method, ESLint checks the files in those directories that + * have the given extensions. For example, when passing the src/ directory and extensions is [".js", ".ts"], ESLint + * will lint *.js and *.ts files in src/. If extensions is null, ESLint checks *.js files and files that match + * overrides[].files patterns in your configuration. + * Note: This option only applies when you pass directory paths to the eslint.lintFiles() method. + * If you pass glob patterns, ESLint will lint all files matching the glob pattern regardless of extension. + */ + extensions?: string[] | null; + /** + * If true is present, the eslint.lintFiles() and eslint.lintText() methods work in autofix mode. + * If a predicate function is present, the methods pass each lint message to the function, then use only the + * lint messages for which the function returned true. + */ + fix?: boolean | ((message: LintMessage) => boolean); + /** + * The types of the rules that the eslint.lintFiles() and eslint.lintText() methods use for autofix. + */ + fixTypes?: string[]; + /** + * If false is present, the eslint.lintFiles() method doesn't interpret glob patterns. + */ + globInputPaths?: boolean; + /** + * If false is present, the eslint.lintFiles() method doesn't respect `.eslintignore` files or ignorePatterns in + * your configuration. + */ + ignore?: boolean; + /** + * The path to a file ESLint uses instead of `$CWD/.eslintignore`. + * If a path is present and the file doesn't exist, this constructor will throw an error. + */ + ignorePath?: string; + /** + * Configuration object, overrides all configurations used with this instance. + * You can use this option to define the settings that will be used even if your configuration files configure it. + */ + overrideConfig?: Linter.ConfigOverride | null; + /** + * The path to a configuration file, overrides all configurations used with this instance. + * The options.overrideConfig option is applied after this option is applied. + */ + overrideConfigFile?: string | null; + /** + * The plugin implementations that ESLint uses for the plugins setting of your configuration. + * This is a map-like object. Those keys are plugin IDs and each value is implementation. + */ + plugins?: Record | null; + /** + * The severity to report unused eslint-disable directives. + * If this option is a severity, it overrides the reportUnusedDisableDirectives setting in your configurations. + */ + reportUnusedDisableDirectives?: Linter.SeverityString | null; + /** + * The path to a directory where plugins should be resolved from. + * If null is present, ESLint loads plugins from the location of the configuration file that contains the plugin + * setting. + * If a path is present, ESLint loads all plugins from there. + */ + resolvePluginsRelativeTo?: string | null; + /** + * An array of paths to directories to load custom rules from. + */ + rulePaths?: string[]; + /** + * If false is present, ESLint doesn't load configuration files (.eslintrc.* files). + * Only the configuration of the constructor options is valid. + */ + useEslintrc?: boolean; + } + + export interface DeprecatedRuleInfo { + /** + * The rule ID. + */ + ruleId: string; + /** + * The rule IDs that replace this deprecated rule. + */ + replacedBy: string[]; + } + + /** + * The LintResult value is the information of the linting result of each file. + */ + export interface LintResult { + /** + * The number of errors. This includes fixable errors. + */ + errorCount: number; + /** + * The absolute path to the file of this result. This is the string "" if the file path is unknown (when you + * didn't pass the options.filePath option to the eslint.lintText() method). + */ + filePath: string; + /** + * The number of errors that can be fixed automatically by the fix constructor option. + */ + fixableErrorCount: number; + /** + * The number of warnings that can be fixed automatically by the fix constructor option. + */ + fixableWarningCount: number; + /** + * The array of LintMessage objects. + */ + messages: Linter.LintMessage[]; + /** + * The source code of the file that was linted, with as many fixes applied as possible. + */ + output?: string; + /** + * The original source code text. This property is undefined if any messages didn't exist or the output + * property exists. + */ + source?: string; + /** + * The information about the deprecated rules that were used to check this file. + */ + usedDeprecatedRules: DeprecatedRuleInfo[]; + /** + * The number of warnings. This includes fixable warnings. + */ + warningCount: number; + } + + export interface LintTextOptions { + /** + * The path to the file of the source code text. If omitted, the result.filePath becomes the string "". + */ + filePath?: string; + /** + * If true is present and the options.filePath is a file ESLint should ignore, this method returns a lint result + * contains a warning message. + */ + warnIgnored?: boolean; + } + + /** + * The LintMessage value is the information of each linting error. + */ + export interface LintMessage { + /** + * The 1-based column number of the begin point of this message. + */ + column: number; + /** + * The 1-based column number of the end point of this message. This property is undefined if this message + * is not a range. + */ + endColumn: number | undefined; + /** + * The 1-based line number of the end point of this message. This property is undefined if this + * message is not a range. + */ + endLine: number | undefined; + /** + * The EditInfo object of autofix. This property is undefined if this message is not fixable. + */ + fix: EditInfo | undefined; + /** + * The 1-based line number of the begin point of this message. + */ + line: number; + /** + * The error message + */ + message: string; + /** + * The rule name that generates this lint message. If this message is generated by the ESLint core rather than + * rules, this is null. + */ + ruleId: string | null; + /** + * The severity of this message. 1 means warning and 2 means error. + */ + severity: 1 | 2; + /** + * The list of suggestions. Each suggestion is the pair of a description and an EditInfo object to fix code. API + * users such as editor integrations can choose one of them to fix the problem of this message. This property is + * undefined if this message doesn't have any suggestions. + */ + suggestions: { desc: string; fix: EditInfo }[] | undefined; + } + + /** + * The EditInfo value is information to edit text. + * + * This edit information means replacing the range of the range property by the text property value. It's like + * sourceCodeText.slice(0, edit.range[0]) + edit.text + sourceCodeText.slice(edit.range[1]). Therefore, it's an add + * if the range[0] and range[1] property values are the same value, and it's removal if the text property value is + * empty string. + */ + export interface EditInfo { + /** + * The pair of 0-based indices in source code text to remove. + */ + range: [number, number]; + /** + * The text to add. + */ + text: string; + } + + /** + * The Formatter value is the object to convert the LintResult objects to text. + */ + export interface Formatter { + /** + * The method to convert the LintResult objects to text + */ + format(results: LintResult[]): string; + } +} + +/** + * The ESLint class is the primary class to use in Node.js applications. + * This class depends on the Node.js fs module and the file system, so you cannot use it in browsers. + * + * If you want to lint code on browsers, use the Linter class instead. + */ +class ESLint extends (ESLintESLint as typeof ESLintBase) {} + +export { ESLint }; diff --git a/packages/experimental-utils/src/ts-eslint/Linter.ts b/packages/experimental-utils/src/ts-eslint/Linter.ts index 57b1d23ea6c0..9abefbabe7d5 100644 --- a/packages/experimental-utils/src/ts-eslint/Linter.ts +++ b/packages/experimental-utils/src/ts-eslint/Linter.ts @@ -3,60 +3,111 @@ import { Linter as ESLintLinter } from 'eslint'; import { TSESTree, ParserServices } from '../ts-estree'; import { ParserOptions as TSParserOptions } from './ParserOptions'; -import { RuleModule, RuleFix } from './Rule'; +import { RuleCreateFunction, RuleFix, RuleModule } from './Rule'; import { Scope } from './Scope'; import { SourceCode } from './SourceCode'; -interface Linter { - version: string; +declare class LinterBase { + /** + * Initialize the Linter. + * @param config the config object + */ + constructor(config?: Linter.LinterOptions); + /** + * Define a new parser module + * @param parserId Name of the parser + * @param parserModule The parser object + */ + defineParser(parserId: string, parserModule: Linter.ParserModule): void; + + /** + * Defines a new linting rule. + * @param ruleId A unique rule identifier + * @param ruleModule Function from context to object mapping AST node types to event handlers + */ + defineRule( + ruleId: string, + ruleModule: RuleModule | RuleCreateFunction, + ): void; + + /** + * Defines many new linting rules. + * @param rulesToDefine map from unique rule identifier to rule + */ + defineRules( + rulesToDefine: Record< + string, + RuleModule | RuleCreateFunction + >, + ): void; + + /** + * Gets an object with all loaded rules. + * @returns All loaded rules + */ + getRules(): Map>; + + /** + * Gets the `SourceCode` object representing the parsed source. + * @returns The `SourceCode` object. + */ + getSourceCode(): SourceCode; + + /** + * Verifies the text against the rules specified by the second argument. + * @param textOrSourceCode The text to parse or a SourceCode object. + * @param config An ESLintConfig instance to configure everything. + * @param filenameOrOptions The optional filename of the file being checked. + * If this is not set, the filename will default to '' in the rule context. + * If this is an object, then it has "filename", "allowInlineConfig", and some properties. + * @returns The results as an array of messages or an empty array if no messages. + */ verify( - code: SourceCode | string, - config: Linter.Config, - filename?: string, - ): Linter.LintMessage[]; - verify( - code: SourceCode | string, + textOrSourceCode: SourceCode | string, config: Linter.Config, - options: Linter.LintOptions, + filenameOrOptions?: string | Linter.VerifyOptions, ): Linter.LintMessage[]; - verifyAndFix( - code: string, - config: Linter.Config, - filename?: string, - ): Linter.FixReport; + /** + * Performs multiple autofix passes over the text until as many fixes as possible have been applied. + * @param text The source text to apply fixes to. + * @param config The ESLint config object to use. + * @param options The ESLint options object to use. + * @returns The result of the fix operation as returned from the SourceCodeFixer. + */ verifyAndFix( code: string, config: Linter.Config, options: Linter.FixOptions, ): Linter.FixReport; - getSourceCode(): SourceCode; + /** + * The version from package.json. + */ + readonly version: string; - defineRule( - name: string, - rule: { - meta?: RuleModule['meta']; - create: RuleModule['create']; - }, - ): void; + //////////////////// + // static members // + //////////////////// - defineRules( - rules: Record>, - ): void; - - getRules< - TMessageIds extends string, - TOptions extends readonly unknown[] - >(): Map>; - - defineParser(name: string, parser: Linter.ParserModule): void; + /** + * The version from package.json. + */ + static readonly version: string; } namespace Linter { + export interface LinterOptions { + /** + * path to a directory that should be considered as the current working directory. + */ + cwd?: string; + } + export type Severity = 0 | 1 | 2; - export type RuleLevel = Severity | 'off' | 'warn' | 'error'; + export type SeverityString = 'off' | 'warn' | 'error'; + export type RuleLevel = Severity | SeverityString; export type RuleLevelAndOptions = [RuleLevel, ...unknown[]]; @@ -66,39 +117,116 @@ namespace Linter { // https://github.com/eslint/eslint/blob/v6.8.0/conf/config-schema.js interface BaseConfig { $schema?: string; + /** + * The environment settings. + */ env?: { [name: string]: boolean }; + /** + * The path to other config files or the package name of shareable configs. + */ extends?: string | string[]; + /** + * The global variable settings. + */ globals?: { [name: string]: boolean }; + /** + * The flag that disables directive comments. + */ noInlineConfig?: boolean; + /** + * The override settings per kind of files. + */ overrides?: ConfigOverride[]; + /** + * The path to a parser or the package name of a parser. + */ parser?: string; + /** + * The parser options. + */ parserOptions?: ParserOptions; + /** + * The plugin specifiers. + */ plugins?: string[]; + /** + * The processor specifier. + */ processor?: string; + /** + * The flag to report unused `eslint-disable` comments. + */ reportUnusedDisableDirectives?: boolean; - settings?: { [name: string]: unknown }; + /** + * The rule settings. + */ rules?: RulesRecord; + /** + * The shared settings. + */ + settings?: { [name: string]: unknown }; } export interface ConfigOverride extends BaseConfig { excludedFiles?: string | string[]; files: string | string[]; } - export type RuleOverride = ConfigOverride; // TODO - delete this next major export interface Config extends BaseConfig { + /** + * The glob patterns that ignore to lint. + */ ignorePatterns?: string | string[]; + /** + * The root flag. + */ root?: boolean; } export type ParserOptions = TSParserOptions; - export interface LintOptions { - filename?: string; - preprocess?: (code: string) => string[]; - postprocess?: (problemLists: LintMessage[][]) => LintMessage[]; + export interface VerifyOptions { + /** + * Allow/disallow inline comments' ability to change config once it is set. Defaults to true if not supplied. + * Useful if you want to validate JS without comments overriding rules. + */ allowInlineConfig?: boolean; - reportUnusedDisableDirectives?: boolean; + /** + * if `true` then the linter doesn't make `fix` properties into the lint result. + */ + disableFixes?: boolean; + /** + * the filename of the source code. + */ + filename?: string; + /** + * the predicate function that selects adopt code blocks. + */ + filterCodeBlock?: (filename: string, text: string) => boolean; + /** + * postprocessor for report messages. + * If provided, this should accept an array of the message lists + * for each code block returned from the preprocessor, apply a mapping to + * the messages as appropriate, and return a one-dimensional array of + * messages. + */ + postprocess?: Processor['postprocess']; + /** + * preprocessor for source text. + * If provided, this should accept a string of source text, and return an array of code blocks to lint. + */ + preprocess?: Processor['preprocess']; + /** + * Adds reported errors for unused `eslint-disable` directives. + */ + reportUnusedDisableDirectives?: boolean | SeverityString; + } + + export interface FixOptions extends VerifyOptions { + /** + * Determines whether fixes should be applied. + */ + fix?: boolean; } export interface LintSuggestion { @@ -108,37 +236,75 @@ namespace Linter { } export interface LintMessage { + /** + * The 1-based column number. + */ column: number; - line: number; + /** + * The 1-based column number of the end location. + */ endColumn?: number; + /** + * The 1-based line number of the end location. + */ endLine?: number; - ruleId: string | null; + /** + * If `true` then this is a fatal error. + */ + fatal?: true; + /** + * Information for autofix. + */ + fix?: RuleFix; + /** + * The 1-based line number. + */ + line: number; + /** + * The error message. + */ message: string; messageId?: string; nodeType: string; - fatal?: true; + /** + * The ID of the rule which makes this message. + */ + ruleId: string | null; + /** + * The severity of this message. + */ severity: Severity; - fix?: RuleFix; source: string | null; + /** + * Information for suggestions + */ suggestions?: LintSuggestion[]; } - export interface FixOptions extends LintOptions { - fix?: boolean; - } - export interface FixReport { + /** + * True, if the code was fixed + */ fixed: boolean; + /** + * Fixed code text (might be the same as input if no fixes were applied). + */ output: string; + /** + * Collection of all messages for the given code + */ messages: LintMessage[]; } export type ParserModule = | { - parse(text: string, options?: unknown): TSESTree.Program; + parse(text: string, options?: ParserOptions): TSESTree.Program; } | { - parseForESLint(text: string, options?: unknown): ESLintParseResult; + parseForESLint( + text: string, + options?: ParserOptions, + ): ESLintParseResult; }; export interface ESLintParseResult { @@ -147,10 +313,64 @@ namespace Linter { scopeManager?: Scope.ScopeManager; visitorKeys?: SourceCode.VisitorKeys; } + + export interface Processor { + /** + * The function to extract code blocks. + */ + preprocess?: ( + text: string, + filename: string, + ) => Array; + /** + * The function to merge messages. + */ + postprocess?: ( + messagesList: Linter.LintMessage[][], + filename: string, + ) => Linter.LintMessage[]; + /** + * If `true` then it means the processor supports autofix. + */ + supportsAutofix?: boolean; + } + + export interface Environment { + /** + * The definition of global variables. + */ + globals?: Record; + /** + * The parser options that will be enabled under this environment. + */ + parserOptions?: ParserOptions; + } + + export interface Plugin { + /** + * The definition of plugin configs. + */ + configs?: Record; + /** + * The definition of plugin environments. + */ + environments?: Record; + /** + * The definition of plugin processors. + */ + processors?: Record; + /** + * The definition of plugin rules. + */ + rules?: Record>; + } } -const Linter = ESLintLinter as { - new (): Linter; -}; +/** + * The Linter object does the actual evaluation of the JavaScript code. It doesn't do any filesystem operations, it + * simply parses and reports on the code. In particular, the Linter object does not process configuration objects + * or files. + */ +class Linter extends (ESLintLinter as typeof LinterBase) {} export { Linter }; diff --git a/packages/experimental-utils/src/ts-eslint/ParserOptions.ts b/packages/experimental-utils/src/ts-eslint/ParserOptions.ts index 4a85f2acab52..c3678eb939d3 100644 --- a/packages/experimental-utils/src/ts-eslint/ParserOptions.ts +++ b/packages/experimental-utils/src/ts-eslint/ParserOptions.ts @@ -23,14 +23,13 @@ interface ParserOptions { jsx?: boolean; }; ecmaVersion?: EcmaVersion; + // ts-estree specific + debugLevel?: TSESTreeOptions['debugLevel']; errorOnTypeScriptSyntacticAndSemanticIssues?: boolean; errorOnUnknownASTType?: boolean; extraFileExtensions?: string[]; - // ts-estree specific - debugLevel?: TSESTreeOptions['debugLevel']; filePath?: string; loc?: boolean; - noWatch?: boolean; project?: string | string[]; projectFolderIgnoreList?: (string | RegExp)[]; range?: boolean; diff --git a/packages/experimental-utils/src/ts-eslint/Rule.ts b/packages/experimental-utils/src/ts-eslint/Rule.ts index 12a3bed1f75f..27d3a1d63baf 100644 --- a/packages/experimental-utils/src/ts-eslint/Rule.ts +++ b/packages/experimental-utils/src/ts-eslint/Rule.ts @@ -123,42 +123,44 @@ interface ReportDescriptorBase { /** * The parameters for the message string associated with `messageId`. */ - data?: Record; + readonly data?: Readonly>; /** * The fixer function. */ - fix?: ReportFixFunction | null; + readonly fix?: ReportFixFunction | null; /** * The messageId which is being reported. */ - messageId: TMessageIds; + readonly messageId: TMessageIds; // we disallow this because it's much better to use messageIds for reusable errors that are easily testable - // desc?: string; + // readonly desc?: string; } interface ReportDescriptorWithSuggestion extends ReportDescriptorBase { /** * 6.7's Suggestions API */ - suggest?: Readonly> | null; + readonly suggest?: Readonly> | null; } interface ReportDescriptorNodeOptionalLoc { /** * The Node or AST Token which the report is being attached to */ - node: TSESTree.Node | TSESTree.Comment | TSESTree.Token; + readonly node: TSESTree.Node | TSESTree.Comment | TSESTree.Token; /** * An override of the location of the report */ - loc?: TSESTree.SourceLocation | TSESTree.LineAndColumnData; + readonly loc?: + | Readonly + | Readonly; } interface ReportDescriptorLocOnly { /** * An override of the location of the report */ - loc: TSESTree.SourceLocation | TSESTree.LineAndColumnData; + loc: Readonly | Readonly; } type ReportDescriptor< TMessageIds extends string @@ -178,11 +180,6 @@ interface RuleContext< * This array does not include the rule severity. */ options: TOptions; - /** - * The shared settings from configuration. - * We do not have any shared settings in this plugin. - */ - settings: Record; /** * The name of the parser from configuration. */ @@ -195,6 +192,11 @@ interface RuleContext< * An object containing parser-provided services for rules */ parserServices?: ParserServices; + /** + * The shared settings from configuration. + * We do not have any shared settings in this plugin. + */ + settings: Record; /** * Returns an array of the ancestors of the currently-traversed node, starting at @@ -224,7 +226,7 @@ interface RuleContext< * Returns a SourceCode object that you can use to work with the source that * was passed to ESLint. */ - getSourceCode(): SourceCode; + getSourceCode(): Readonly; /** * Marks a variable with the given name in the current scope as used. @@ -436,14 +438,19 @@ interface RuleModule< * Function which returns an object with methods that ESLint calls to “visit” * nodes while traversing the abstract syntax tree. */ - create(context: RuleContext): TRuleListener; + create(context: Readonly>): TRuleListener; } +type RuleCreateFunction = ( + context: Readonly>, +) => RuleListener; + export { ReportDescriptor, ReportFixFunction, ReportSuggestionArray, RuleContext, + RuleCreateFunction, RuleFix, RuleFixer, RuleFunction, diff --git a/packages/experimental-utils/src/ts-eslint/RuleTester.ts b/packages/experimental-utils/src/ts-eslint/RuleTester.ts index 41dadcb63636..d1e11e4ad776 100644 --- a/packages/experimental-utils/src/ts-eslint/RuleTester.ts +++ b/packages/experimental-utils/src/ts-eslint/RuleTester.ts @@ -4,49 +4,109 @@ import { ParserOptions } from './ParserOptions'; import { RuleModule } from './Rule'; interface ValidTestCase> { - code: string; - options?: TOptions; - filename?: string; - parserOptions?: ParserOptions; - settings?: Record; - parser?: string; - globals?: Record; - env?: { - browser?: boolean; - }; + /** + * Code for the test case. + */ + readonly code: string; + /** + * Environments for the test case. + */ + readonly env?: Readonly>; + /** + * The fake filename for the test case. Useful for rules that make assertion about filenames. + */ + readonly filename?: string; + /** + * The additional global variables. + */ + readonly globals?: Record; + /** + * Options for the test case. + */ + readonly options?: Readonly; + /** + * The absolute path for the parser. + */ + readonly parser?: string; + /** + * Options for the parser. + */ + readonly parserOptions?: Readonly; + /** + * Settings for the test case. + */ + readonly settings?: Readonly>; } interface SuggestionOutput { - messageId: TMessageIds; - data?: Record; + /** + * Reported message ID. + */ + readonly messageId: TMessageIds; + /** + * The data used to fill the message template. + */ + readonly data?: Readonly>; /** * NOTE: Suggestions will be applied as a stand-alone change, without triggering multi-pass fixes. * Each individual error has its own suggestion, so you have to show the correct, _isolated_ output for each suggestion. */ - output: string; + readonly output: string; + // we disallow this because it's much better to use messageIds for reusable errors that are easily testable - // desc?: string; + // readonly desc?: string; } interface InvalidTestCase< TMessageIds extends string, TOptions extends Readonly > extends ValidTestCase { - errors: TestCaseError[]; - output?: string | null; + /** + * Expected errors. + */ + readonly errors: TestCaseError[]; + /** + * The expected code after autofixes are applied. If set to `null`, the test runner will assert that no autofix is suggested. + */ + readonly output?: string | null; } interface TestCaseError { - messageId: TMessageIds; + /** + * The 1-based column number of the reported start location. + */ + readonly column?: number; + /** + * The data used to fill the message template. + */ + readonly data?: Readonly>; + /** + * The 1-based column number of the reported end location. + */ + readonly endColumn?: number; + /** + * The 1-based line number of the reported end location. + */ + readonly endLine?: number; + /** + * The 1-based line number of the reported start location. + */ + readonly line?: number; + /** + * Reported message ID. + */ + readonly messageId: TMessageIds; + /** + * Reported suggestions. + */ + readonly suggestions?: SuggestionOutput[] | null; + /** + * The type of the reported AST node. + */ + readonly type?: AST_NODE_TYPES | AST_TOKEN_TYPES; + // we disallow this because it's much better to use messageIds for reusable errors that are easily testable - // message?: string; - data?: Record; - type?: AST_NODE_TYPES | AST_TOKEN_TYPES; - line?: number; - column?: number; - endLine?: number; - endColumn?: number; - suggestions?: SuggestionOutput[] | null; + // readonly message?: string | RegExp; } interface RunTests< @@ -54,41 +114,56 @@ interface RunTests< TOptions extends Readonly > { // RuleTester.run also accepts strings for valid cases - valid: (ValidTestCase | string)[]; - invalid: InvalidTestCase[]; + readonly valid: (ValidTestCase | string)[]; + readonly invalid: InvalidTestCase[]; } interface RuleTesterConfig { // should be require.resolve(parserPackageName) - parser: string; - parserOptions?: ParserOptions; + readonly parser: string; + readonly parserOptions?: Readonly; } -// the cast on the extends is so that we don't want to have the built type defs to attempt to import eslint -class RuleTester extends (ESLintRuleTester as { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - new (...args: unknown[]): any; -}) { - constructor(config?: RuleTesterConfig) { - super(config); - - // nobody will ever need watching in tests - // so we can give everyone a perf win by disabling watching - if (config?.parserOptions?.project) { - config.parserOptions.noWatch = - typeof config.parserOptions.noWatch === 'boolean' || true; - } - } +declare class RuleTesterBase { + /** + * Creates a new instance of RuleTester. + * @param testerConfig extra configuration for the tester + */ + constructor(testerConfig?: RuleTesterConfig); + /** + * Adds a new rule test to execute. + * @param ruleName The name of the rule to run. + * @param rule The rule to test. + * @param test The collection of tests to run. + */ run>( - name: string, + ruleName: string, rule: RuleModule, tests: RunTests, - ): void { - // this method is only defined here because we lazily type the eslint import with `any` - super.run(name, rule, tests); - } + ): void; + + /** + * If you supply a value to this property, the rule tester will call this instead of using the version defined on + * the global namespace. + * @param text a string describing the rule + * @param callback the test callback + */ + static describe?: (text: string, callback: () => void) => void; + + /** + * If you supply a value to this property, the rule tester will call this instead of using the version defined on + * the global namespace. + * @param text a string describing the test case + * @param callback the test callback + */ + static it?: (text: string, callback: () => void) => void; } +/** + * @deprecated - use RuleTesterSafe instead + */ +class RuleTester extends (ESLintRuleTester as typeof RuleTesterBase) {} + export { InvalidTestCase, SuggestionOutput, diff --git a/packages/experimental-utils/src/ts-eslint/SourceCode.ts b/packages/experimental-utils/src/ts-eslint/SourceCode.ts index 0ea39973a25d..82593bbfc6ae 100644 --- a/packages/experimental-utils/src/ts-eslint/SourceCode.ts +++ b/packages/experimental-utils/src/ts-eslint/SourceCode.ts @@ -4,150 +4,346 @@ import { SourceCode as ESLintSourceCode } from 'eslint'; import { ParserServices, TSESTree } from '../ts-estree'; import { Scope } from './Scope'; -interface SourceCode { - text: string; - ast: SourceCode.Program; - lines: string[]; - hasBOM: boolean; - parserServices: ParserServices; - scopeManager: Scope.ScopeManager; - visitorKeys: SourceCode.VisitorKeys; - tokensAndComments: (TSESTree.Comment | TSESTree.Token)[]; - - getText( - node?: TSESTree.Node, - beforeCount?: number, - afterCount?: number, - ): string; - - getLines(): string[]; - - getAllComments(): TSESTree.Comment[]; - - getComments( - node: TSESTree.Node, - ): { leading: TSESTree.Comment[]; trailing: TSESTree.Comment[] }; - - getJSDocComment(node: TSESTree.Node): TSESTree.Node | TSESTree.Token | null; - - getNodeByRangeIndex(index: number): TSESTree.Node | null; - - isSpaceBetween( - first: TSESTree.Token | TSESTree.Comment | TSESTree.Node, - second: TSESTree.Token | TSESTree.Comment | TSESTree.Node, +declare class TokenStore { + /** + * Checks whether any comments exist or not between the given 2 nodes. + * @param left The node to check. + * @param right The node to check. + * @returns `true` if one or more comments exist. + */ + commentsExistBetween( + left: TSESTree.Node | TSESTree.Token, + right: TSESTree.Node | TSESTree.Token, ): boolean; - /** - * @deprecated in favor of isSpaceBetween() + * Gets all comment tokens directly after the given node or token. + * @param nodeOrToken The AST node or token to check for adjacent comment tokens. + * @returns An array of comments in occurrence order. + */ + getCommentsAfter( + nodeOrToken: TSESTree.Node | TSESTree.Token, + ): TSESTree.Comment[]; + /** + * Gets all comment tokens directly before the given node or token. + * @param nodeOrToken The AST node or token to check for adjacent comment tokens. + * @returns An array of comments in occurrence order. + */ + getCommentsBefore( + nodeOrToken: TSESTree.Node | TSESTree.Token, + ): TSESTree.Comment[]; + /** + * Gets all comment tokens inside the given node. + * @param node The AST node to get the comments for. + * @returns An array of comments in occurrence order. + */ + getCommentsInside(node: TSESTree.Node): TSESTree.Comment[]; + /** + * Gets the first token of the given node. + * @param node The AST node. + * @param option The option object. If this is a number then it's `options.skip`. If this is a function then it's `options.filter`. + * @returns An object representing the token. */ - isSpaceBetweenTokens(first: TSESTree.Token, second: TSESTree.Token): boolean; - - getLocFromIndex(index: number): TSESTree.LineAndColumnData; - - getIndexFromLoc(location: TSESTree.LineAndColumnData): number; - - // Inherited methods from TokenStore - // --------------------------------- - - getTokenByRangeStart( - offset: number, - options?: T, - ): SourceCode.ReturnTypeFromOptions | null; - getFirstToken( node: TSESTree.Node, options?: T, ): SourceCode.ReturnTypeFromOptions | null; - + /** + * Gets the first token between two non-overlapping nodes. + * @param left Node before the desired token range. + * @param right Node after the desired token range. + * @param option The option object. If this is a number then it's `options.skip`. If this is a function then it's `options.filter`. + * @returns An object representing the token. + */ + getFirstTokenBetween( + left: TSESTree.Node | TSESTree.Token | TSESTree.Comment, + right: TSESTree.Node | TSESTree.Token | TSESTree.Comment, + options?: T, + ): SourceCode.ReturnTypeFromOptions | null; + /** + * Gets the first `count` tokens of the given node. + * @param node The AST node. + * @param options The option object. If this is a number then it's `options.count`. If this is a function then it's `options.filter`. + * @returns Tokens. + */ getFirstTokens( node: TSESTree.Node, options?: T, ): SourceCode.ReturnTypeFromOptions[]; - + /** + * Gets the first `count` tokens between two non-overlapping nodes. + * @param left Node before the desired token range. + * @param right Node after the desired token range. + * @param options The option object. If this is a number then it's `options.count`. If this is a function then it's `options.filter`. + * @returns Tokens between left and right. + */ + getFirstTokensBetween( + left: TSESTree.Node | TSESTree.Token | TSESTree.Comment, + right: TSESTree.Node | TSESTree.Token | TSESTree.Comment, + options?: T, + ): SourceCode.ReturnTypeFromOptions[]; + /** + * Gets the last token of the given node. + * @param node The AST node. + * @param option The option object. If this is a number then it's `options.skip`. If this is a function then it's `options.filter`. + * @returns An object representing the token. + */ getLastToken( node: TSESTree.Node, options?: T, ): SourceCode.ReturnTypeFromOptions | null; - + /** + * Gets the last token between two non-overlapping nodes. + * @param left Node before the desired token range. + * @param right Node after the desired token range. + * @param option The option object. If this is a number then it's `options.skip`. If this is a function then it's `options.filter`. + * @returns An object representing the token. + */ + getLastTokenBetween( + left: TSESTree.Node | TSESTree.Token | TSESTree.Comment, + right: TSESTree.Node | TSESTree.Token | TSESTree.Comment, + options?: T, + ): SourceCode.ReturnTypeFromOptions | null; + /** + * Gets the last `count` tokens of the given node. + * @param node The AST node. + * @param options The option object. If this is a number then it's `options.count`. If this is a function then it's `options.filter`. + * @returns Tokens. + */ getLastTokens( node: TSESTree.Node, options?: T, ): SourceCode.ReturnTypeFromOptions[]; - - getTokenBefore( - node: TSESTree.Node | TSESTree.Token | TSESTree.Comment, - options?: T, - ): SourceCode.ReturnTypeFromOptions | null; - - getTokensBefore( - node: TSESTree.Node | TSESTree.Token | TSESTree.Comment, + /** + * Gets the last `count` tokens between two non-overlapping nodes. + * @param left Node before the desired token range. + * @param right Node after the desired token range. + * @param options The option object. If this is a number then it's `options.count`. If this is a function then it's `options.filter`. + * @returns Tokens between left and right. + */ + getLastTokensBetween( + left: TSESTree.Node | TSESTree.Token | TSESTree.Comment, + right: TSESTree.Node | TSESTree.Token | TSESTree.Comment, options?: T, ): SourceCode.ReturnTypeFromOptions[]; - + /** + * Gets the token that follows a given node or token. + * @param node The AST node or token. + * @param option The option object. If this is a number then it's `options.skip`. If this is a function then it's `options.filter`. + * @returns An object representing the token. + */ getTokenAfter( node: TSESTree.Node | TSESTree.Token | TSESTree.Comment, options?: T, ): SourceCode.ReturnTypeFromOptions | null; - - getTokensAfter( + /** + * Gets the token that precedes a given node or token. + * @param node The AST node or token. + * @param options The option object + * @returns An object representing the token. + */ + getTokenBefore( node: TSESTree.Node | TSESTree.Token | TSESTree.Comment, options?: T, - ): SourceCode.ReturnTypeFromOptions[]; - - getFirstTokenBetween( - left: TSESTree.Node | TSESTree.Token | TSESTree.Comment, - right: TSESTree.Node | TSESTree.Token | TSESTree.Comment, + ): SourceCode.ReturnTypeFromOptions | null; + /** + * Gets the token starting at the specified index. + * @param offset Index of the start of the token's range. + * @param option The option object. If this is a number then it's `options.skip`. If this is a function then it's `options.filter`. + * @returns The token starting at index, or null if no such token. + */ + getTokenByRangeStart( + offset: number, options?: T, ): SourceCode.ReturnTypeFromOptions | null; - - getFirstTokensBetween( - left: TSESTree.Node | TSESTree.Token | TSESTree.Comment, - right: TSESTree.Node | TSESTree.Token | TSESTree.Comment, + /** + * Gets all tokens that are related to the given node. + * @param node The AST node. + * @param beforeCount The number of tokens before the node to retrieve. + * @param afterCount The number of tokens after the node to retrieve. + * @returns Array of objects representing tokens. + */ + getTokens( + node: TSESTree.Node, + beforeCount?: number, + afterCount?: number, + ): TSESTree.Token[]; + /** + * Gets all tokens that are related to the given node. + * @param node The AST node. + * @param options The option object. If this is a function then it's `options.filter`. + * @returns Array of objects representing tokens. + */ + getTokens( + node: TSESTree.Node, + options: T, + ): SourceCode.ReturnTypeFromOptions[]; + /** + * Gets the `count` tokens that follows a given node or token. + * @param node The AST node. + * @param options The option object. If this is a number then it's `options.count`. If this is a function then it's `options.filter`. + * @returns Tokens. + */ + getTokensAfter( + node: TSESTree.Node | TSESTree.Token | TSESTree.Comment, options?: T, ): SourceCode.ReturnTypeFromOptions[]; - - getLastTokenBetween( - left: TSESTree.Node | TSESTree.Token | TSESTree.Comment, - right: TSESTree.Node | TSESTree.Token | TSESTree.Comment, + /** + * Gets the `count` tokens that precedes a given node or token. + * @param node The AST node. + * @param options The option object. If this is a number then it's `options.count`. If this is a function then it's `options.filter`. + * @returns Tokens. + */ + getTokensBefore( + node: TSESTree.Node | TSESTree.Token | TSESTree.Comment, options?: T, - ): SourceCode.ReturnTypeFromOptions | null; - - getLastTokensBetween( + ): SourceCode.ReturnTypeFromOptions[]; + /** + * Gets all of the tokens between two non-overlapping nodes. + * @param left Node before the desired token range. + * @param right Node after the desired token range. + * @param options The option object. If this is a function then it's `options.filter`. + * @returns Tokens between left and right. + */ + getTokensBetween( left: TSESTree.Node | TSESTree.Token | TSESTree.Comment, right: TSESTree.Node | TSESTree.Token | TSESTree.Comment, - options?: T, + padding?: T, ): SourceCode.ReturnTypeFromOptions[]; - + /** + * Gets all of the tokens between two non-overlapping nodes. + * @param left Node before the desired token range. + * @param right Node after the desired token range. + * @param padding Number of extra tokens on either side of center. + * @returns Tokens between left and right. + */ getTokensBetween( left: TSESTree.Node | TSESTree.Token | TSESTree.Comment, right: TSESTree.Node | TSESTree.Token | TSESTree.Comment, - padding?: T, + padding?: number, ): SourceCode.ReturnTypeFromOptions[]; +} - getTokens( +declare class SourceCodeBase extends TokenStore { + /** + * Represents parsed source code. + * @param text The source code text. + * @param ast The Program node of the AST representing the code. This AST should be created from the text that BOM was stripped. + */ + constructor(text: string, ast: SourceCode.Program); + /** + * Represents parsed source code. + * @param config The config object. + */ + constructor(config: SourceCode.SourceCodeConfig); + + /** + * The parsed AST for the source code. + */ + ast: SourceCode.Program; + /** + * Retrieves an array containing all comments in the source code. + * @returns An array of comment nodes. + */ + getAllComments(): TSESTree.Comment[]; + /** + * Gets all comments for the given node. + * @param node The AST node to get the comments for. + * @returns An object containing a leading and trailing array of comments indexed by their position. + */ + getComments( node: TSESTree.Node, + ): { leading: TSESTree.Comment[]; trailing: TSESTree.Comment[] }; + /** + * Converts a (line, column) pair into a range index. + * @param loc A line/column location + * @returns The range index of the location in the file. + */ + getIndexFromLoc(location: TSESTree.LineAndColumnData): number; + /** + * Gets the entire source text split into an array of lines. + * @returns The source text as an array of lines. + */ + getLines(): string[]; + /** + * Converts a source text index into a (line, column) pair. + * @param index The index of a character in a file + * @returns A {line, column} location object with a 0-indexed column + */ + getLocFromIndex(index: number): TSESTree.LineAndColumnData; + /** + * Gets the deepest node containing a range index. + * @param index Range index of the desired node. + * @returns The node if found or `null` if not found. + */ + getNodeByRangeIndex(index: number): TSESTree.Node | null; + /** + * Gets the source code for the given node. + * @param node The AST node to get the text for. + * @param beforeCount The number of characters before the node to retrieve. + * @param afterCount The number of characters after the node to retrieve. + * @returns The text representing the AST node. + */ + getText( + node?: TSESTree.Node, beforeCount?: number, afterCount?: number, - ): TSESTree.Token[]; - getTokens( - node: TSESTree.Node, - options: T, - ): SourceCode.ReturnTypeFromOptions[]; - - commentsExistBetween( - left: TSESTree.Node | TSESTree.Token, - right: TSESTree.Node | TSESTree.Token, + ): string; + /** + * The flag to indicate that the source code has Unicode BOM. + */ + hasBOM: boolean; + /** + * Determines if two nodes or tokens have at least one whitespace character + * between them. Order does not matter. Returns false if the given nodes or + * tokens overlap. + * @param first The first node or token to check between. + * @param second The second node or token to check between. + * @returns True if there is a whitespace character between any of the tokens found between the two given nodes or tokens. + */ + isSpaceBetween( + first: TSESTree.Token | TSESTree.Comment | TSESTree.Node, + second: TSESTree.Token | TSESTree.Comment | TSESTree.Node, ): boolean; + /** + * The source code split into lines according to ECMA-262 specification. + * This is done to avoid each rule needing to do so separately. + */ + lines: string[]; + /** + * The indexes in `text` that each line starts + */ + lineStartIndices: number[]; + /** + * The parser services of this source code. + */ + parserServices: ParserServices; + /** + * The scope of this source code. + */ + scopeManager: Scope.ScopeManager | null; + /** + * The original text source code. BOM was stripped from this text. + */ + text: string; + /** + * All of the tokens and comments in the AST. + */ + tokensAndComments: (TSESTree.Comment | TSESTree.Token)[]; + /** + * The visitor keys to traverse AST. + */ + visitorKeys: SourceCode.VisitorKeys; - getCommentsBefore( - nodeOrToken: TSESTree.Node | TSESTree.Token, - ): TSESTree.Comment[]; - - getCommentsAfter( - nodeOrToken: TSESTree.Node | TSESTree.Token, - ): TSESTree.Comment[]; + //////////////////// + // static members // + //////////////////// - getCommentsInside(node: TSESTree.Node): TSESTree.Comment[]; + /** + * Split the source code into multiple lines based on the line delimiters. + * @param text Source code as a string. + * @returns Array of source code lines. + */ + static splitLines(text: string): string[]; } namespace SourceCode { @@ -156,12 +352,27 @@ namespace SourceCode { tokens: TSESTree.Token[]; } - export interface Config { - text: string; + export interface SourceCodeConfig { + /** + * The Program node of the AST representing the code. This AST should be created from the text that BOM was stripped. + */ ast: Program; - parserServices?: ParserServices; - scopeManager?: Scope.ScopeManager; - visitorKeys?: VisitorKeys; + /** + * The parser services. + */ + parserServices: ParserServices | null; + /** + * The scope of this source code. + */ + scopeManager: Scope.ScopeManager | null; + /** + * The source code text. + */ + text: string; + /** + * The visitor keys to traverse AST. + */ + visitorKeys: VisitorKeys | null; } export interface VisitorKeys { @@ -173,15 +384,24 @@ namespace SourceCode { ) => boolean; export type ReturnTypeFromOptions = T extends { includeComments: true } - ? TSESTree.Token | TSESTree.Comment - : TSESTree.Token; + ? TSESTree.Token + : Exclude; export type CursorWithSkipOptions = | number | FilterPredicate | { - includeComments?: boolean; + /** + * The predicate function to choose tokens. + */ filter?: FilterPredicate; + /** + * The flag to iterate comments as well. + */ + includeComments?: boolean; + /** + * The count of tokens the cursor skips. + */ skip?: number; }; @@ -189,18 +409,21 @@ namespace SourceCode { | number | FilterPredicate | { - includeComments?: boolean; + /** + * The predicate function to choose tokens. + */ filter?: FilterPredicate; + /** + * The flag to iterate comments as well. + */ + includeComments?: boolean; + /** + * The maximum count of tokens the cursor iterates. + */ count?: number; }; } -const SourceCode = ESLintSourceCode as { - new (text: string, ast: SourceCode.Program): SourceCode; - new (config: SourceCode.Config): SourceCode; - - // static methods - splitLines(text: string): string[]; -}; +class SourceCode extends (ESLintSourceCode as typeof SourceCodeBase) {} export { SourceCode }; diff --git a/packages/experimental-utils/typings/eslint.d.ts b/packages/experimental-utils/typings/eslint.d.ts index a32b469a977a..71978423a4b7 100644 --- a/packages/experimental-utils/typings/eslint.d.ts +++ b/packages/experimental-utils/typings/eslint.d.ts @@ -10,6 +10,7 @@ declare module 'eslint' { const RuleTester: unknown; const SourceCode: unknown; const CLIEngine: unknown; + const ESLint: unknown; - export { Linter, RuleTester, SourceCode, CLIEngine }; + export { Linter, RuleTester, SourceCode, CLIEngine, ESLint }; } diff --git a/packages/parser/tests/lib/basics.ts b/packages/parser/tests/lib/basics.ts index b1ab1d9a96a8..0db6e6982493 100644 --- a/packages/parser/tests/lib/basics.ts +++ b/packages/parser/tests/lib/basics.ts @@ -39,20 +39,18 @@ export const Price: React.SFC = function Price(props) {} }; linter.defineParser('@typescript-eslint/parser', parser); - linter.defineRule('test', { - create(context) { - return { - TSTypeReference(node): void { - const name = context.getSourceCode().getText(node.typeName); - context.report({ - node, - message: 'called on {{name}}', - data: { name }, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } as any); - }, - }; - }, + linter.defineRule('test', function create(context) { + return { + TSTypeReference(node): void { + const name = context.getSourceCode().getText(node.typeName); + context.report({ + node, + message: 'called on {{name}}', + data: { name }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any); + }, + }; }); const messages = linter.verify(code, config, { filename: 'issue.ts' }); From a35026de2548d33963bbdb96fb8fffc7ab0d8a30 Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Thu, 14 May 2020 02:12:24 -0700 Subject: [PATCH 27/33] chore: provide more granularity in the CI logs (#2024) --- .github/workflows/ci.yml | 111 +++++++++++++++++++++++++++++++++++---- 1 file changed, 102 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 28993958cef9..2abf37cfcf99 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,8 +14,8 @@ env: PRIMARY_NODE_VERSION: 12 jobs: - primary_code_validation_and_tests: - name: Typecheck and tests + typecheck: + name: Typecheck runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 @@ -55,8 +55,75 @@ jobs: - name: Typecheck all packages run: yarn typecheck - - name: Run unit tests + test_on_primary_node_version: + name: Unit tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: echo github.ref + run: echo ${{ github.ref }} + + - name: Use Node.js ${{ env.PRIMARY_NODE_VERSION }} + uses: actions/setup-node@v1 + with: + node-version: ${{ env.PRIMARY_NODE_VERSION }} + + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "::set-output name=dir::$(yarn cache dir)" + + - uses: actions/cache@v1 + id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - name: Install dependencies + run: | + yarn --ignore-engines --frozen-lockfile --ignore-scripts + yarn lerna:init + yarn check:clean-workspace-after-install + + - name: Build + run: | + yarn build + + - name: Run unit tests for typescript-estree + run: yarn test + working-directory: packages/typescript-estree + env: + CI: true + + - name: Run unit tests for experimental-utils + run: yarn test + working-directory: packages/experimental-utils + env: + CI: true + + - name: Run unit tests for parser + run: yarn test + working-directory: packages/parser + env: + CI: true + + - name: Run unit tests for eslint-plugin + run: yarn test + working-directory: packages/eslint-plugin + env: + CI: true + + - name: Run unit tests for eslint-plugin-tslint + run: yarn test + working-directory: packages/eslint-plugin-tslint + env: + CI: true + + - name: Run unit tests for eslint-plugin-internal run: yarn test + working-directory: packages/eslint-plugin-internal env: CI: true @@ -184,16 +251,42 @@ jobs: run: | yarn build - - name: Run unit tests - # the internal plugin is only run locally, so it doesn't have to support older versions - run: yarn test --ignore @typescript-eslint/eslint-plugin-internal + - name: Run unit tests for typescript-estree + run: yarn test + working-directory: packages/typescript-estree + env: + CI: true + + - name: Run unit tests for experimental-utils + run: yarn test + working-directory: packages/experimental-utils + env: + CI: true + + - name: Run unit tests for parser + run: yarn test + working-directory: packages/parser env: CI: true + - name: Run unit tests for eslint-plugin + run: yarn test + working-directory: packages/eslint-plugin + env: + CI: true + + - name: Run unit tests for eslint-plugin-tslint + run: yarn test + working-directory: packages/eslint-plugin-tslint + env: + CI: true + + # eslint-plugin-internal is internal only - so don't care about compat on other versions + publish_canary_version: name: Publish the latest code as a canary version runs-on: ubuntu-latest - needs: [primary_code_validation_and_tests, unit_tests_on_other_node_versions, linting_and_style, integration_tests] + needs: [typecheck, test_on_primary_node_version, unit_tests_on_other_node_versions, linting_and_style, integration_tests] if: github.ref == 'refs/heads/master' steps: - uses: actions/checkout@v2 @@ -238,7 +331,7 @@ jobs: publish_v3_prerelease_version: name: Publish the latest code as a v3 prerelease version runs-on: ubuntu-latest - needs: [primary_code_validation_and_tests, unit_tests_on_other_node_versions, linting_and_style, integration_tests] + needs: [typecheck, test_on_primary_node_version, unit_tests_on_other_node_versions, linting_and_style, integration_tests] if: github.ref == 'refs/heads/v3' steps: - uses: actions/checkout@v2 @@ -275,6 +368,6 @@ jobs: yarn build - name: Publish all packages to npm - run: npx lerna publish --loglevel=verbose --canary --exact --force-publish --yes --dist-tag rc-v3 + run: npx lerna publish premajor --loglevel=verbose --canary --exact --force-publish --yes --dist-tag rc-v3 env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} From f199cbdbbd892b5ba03bfff66f463f3d9c92ee9b Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Fri, 15 May 2020 02:00:21 -0700 Subject: [PATCH 28/33] fix(typescript-estree): remove now defunct `Import` node type --- packages/eslint-plugin/src/rules/no-unsafe-call.ts | 4 ++-- packages/experimental-utils/src/ts-eslint/Rule.ts | 2 +- packages/typescript-estree/src/convert.ts | 5 ----- packages/typescript-estree/src/ts-estree/ts-estree.ts | 6 ------ 4 files changed, 3 insertions(+), 14 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-unsafe-call.ts b/packages/eslint-plugin/src/rules/no-unsafe-call.ts index 43ca4a0140f9..d3f6707e1221 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-call.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-call.ts @@ -42,8 +42,8 @@ export default util.createRule<[], MessageIds>({ } return { - ':matches(CallExpression, OptionalCallExpression) > :not(Import).callee'( - node: Exclude, + ':matches(CallExpression, OptionalCallExpression) > *.callee'( + node: TSESTree.CallExpression['callee'], ): void { checkCall(node, node, 'unsafeCall'); }, diff --git a/packages/experimental-utils/src/ts-eslint/Rule.ts b/packages/experimental-utils/src/ts-eslint/Rule.ts index 27d3a1d63baf..287ea3f43692 100644 --- a/packages/experimental-utils/src/ts-eslint/Rule.ts +++ b/packages/experimental-utils/src/ts-eslint/Rule.ts @@ -281,9 +281,9 @@ interface RuleListener { FunctionExpression?: RuleFunction; Identifier?: RuleFunction; IfStatement?: RuleFunction; - Import?: RuleFunction; ImportDeclaration?: RuleFunction; ImportDefaultSpecifier?: RuleFunction; + ImportExpression?: RuleFunction; ImportNamespaceSpecifier?: RuleFunction; ImportSpecifier?: RuleFunction; JSXAttribute?: RuleFunction; diff --git a/packages/typescript-estree/src/convert.ts b/packages/typescript-estree/src/convert.ts index c2ce21755af7..74f97e526a41 100644 --- a/packages/typescript-estree/src/convert.ts +++ b/packages/typescript-estree/src/convert.ts @@ -1992,11 +1992,6 @@ export class Converter { } } - case SyntaxKind.ImportKeyword: - return this.createNode(node, { - type: AST_NODE_TYPES.Import, - }); - case SyntaxKind.EmptyStatement: return this.createNode(node, { type: AST_NODE_TYPES.EmptyStatement, diff --git a/packages/typescript-estree/src/ts-estree/ts-estree.ts b/packages/typescript-estree/src/ts-estree/ts-estree.ts index bd0b40636194..d57ce09d5313 100644 --- a/packages/typescript-estree/src/ts-estree/ts-estree.ts +++ b/packages/typescript-estree/src/ts-estree/ts-estree.ts @@ -172,7 +172,6 @@ export type Node = | FunctionExpression | Identifier | IfStatement - | Import | ImportDeclaration | ImportDefaultSpecifier | ImportExpression @@ -447,7 +446,6 @@ export type PrimaryExpression = | ClassExpression | FunctionExpression | Identifier - | Import | JSXElement | JSXFragment | JSXOpeningElement @@ -956,10 +954,6 @@ export interface IfStatement extends BaseNode { alternate: Statement | null; } -export interface Import extends BaseNode { - type: AST_NODE_TYPES.Import; -} - export interface ImportDeclaration extends BaseNode { type: AST_NODE_TYPES.ImportDeclaration; source: Literal; From fe59f69381a0915a4f5135e2e88637a5eea246ba Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Fri, 15 May 2020 02:01:34 -0700 Subject: [PATCH 29/33] fix(eslint-plugin): correct parser peerDep version --- packages/eslint-plugin/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index 2fcdcfd86099..b82f612856e5 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -55,7 +55,7 @@ "typescript": "*" }, "peerDependencies": { - "@typescript-eslint/parser": "^2.0.0", + "@typescript-eslint/parser": "^3.0.0", "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" }, "peerDependenciesMeta": { From ae82ea4a85a4ca332ebe6104e96c59dba30411be Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Sun, 17 May 2020 09:45:57 -0700 Subject: [PATCH 30/33] fix(experimental-utils): add back SourceCode.isSpaceBetweenTokens SourceCode.isSpaceBetween only exists in 6.7.0, so isSpaceBetweenTokens is a valid alternative until older versions are dead. --- packages/eslint-plugin/src/rules/array-type.ts | 2 +- .../eslint-plugin/src/rules/comma-spacing.ts | 4 ++-- .../src/rules/space-before-function-paren.ts | 2 +- .../experimental-utils/src/ts-eslint/ESLint.ts | 2 ++ .../src/ts-eslint/RuleTester.ts | 3 --- .../src/ts-eslint/SourceCode.ts | 17 ++++++++++++++++- 6 files changed, 22 insertions(+), 8 deletions(-) diff --git a/packages/eslint-plugin/src/rules/array-type.ts b/packages/eslint-plugin/src/rules/array-type.ts index a1ee754f2344..de3cca753436 100644 --- a/packages/eslint-plugin/src/rules/array-type.ts +++ b/packages/eslint-plugin/src/rules/array-type.ts @@ -147,7 +147,7 @@ export default util.createRule({ } const nextToken = sourceCode.getTokenAfter(prevToken); - if (nextToken && sourceCode.isSpaceBetween(prevToken, nextToken)) { + if (nextToken && sourceCode.isSpaceBetweenTokens(prevToken, nextToken)) { return false; } diff --git a/packages/eslint-plugin/src/rules/comma-spacing.ts b/packages/eslint-plugin/src/rules/comma-spacing.ts index 665eeffd0297..fa5dc1c0ec89 100644 --- a/packages/eslint-plugin/src/rules/comma-spacing.ts +++ b/packages/eslint-plugin/src/rules/comma-spacing.ts @@ -111,7 +111,7 @@ export default createRule({ if ( prevToken && isTokenOnSameLine(prevToken, commaToken) && - spaceBefore !== sourceCode.isSpaceBetween(prevToken, commaToken) + spaceBefore !== sourceCode.isSpaceBetweenTokens(prevToken, commaToken) ) { context.report({ node: commaToken, @@ -140,7 +140,7 @@ export default createRule({ if ( nextToken && isTokenOnSameLine(commaToken, nextToken) && - spaceAfter !== sourceCode.isSpaceBetween(commaToken, nextToken) + spaceAfter !== sourceCode.isSpaceBetweenTokens(commaToken, nextToken) ) { context.report({ node: commaToken, diff --git a/packages/eslint-plugin/src/rules/space-before-function-paren.ts b/packages/eslint-plugin/src/rules/space-before-function-paren.ts index 5b7f8fd6e047..41a817938dac 100644 --- a/packages/eslint-plugin/src/rules/space-before-function-paren.ts +++ b/packages/eslint-plugin/src/rules/space-before-function-paren.ts @@ -145,7 +145,7 @@ export default util.createRule({ rightToken = sourceCode.getFirstToken(node, util.isOpeningParenToken)!; leftToken = sourceCode.getTokenBefore(rightToken)!; } - const hasSpacing = sourceCode.isSpaceBetween(leftToken, rightToken); + const hasSpacing = sourceCode.isSpaceBetweenTokens(leftToken, rightToken); if (hasSpacing && functionConfig === 'never') { context.report({ diff --git a/packages/experimental-utils/src/ts-eslint/ESLint.ts b/packages/experimental-utils/src/ts-eslint/ESLint.ts index 9ced6ed64702..c90978bb1152 100644 --- a/packages/experimental-utils/src/ts-eslint/ESLint.ts +++ b/packages/experimental-utils/src/ts-eslint/ESLint.ts @@ -346,6 +346,8 @@ namespace ESLint { * This class depends on the Node.js fs module and the file system, so you cannot use it in browsers. * * If you want to lint code on browsers, use the Linter class instead. + * + * @since 7.0.0 */ class ESLint extends (ESLintESLint as typeof ESLintBase) {} diff --git a/packages/experimental-utils/src/ts-eslint/RuleTester.ts b/packages/experimental-utils/src/ts-eslint/RuleTester.ts index d1e11e4ad776..b54c1190ad83 100644 --- a/packages/experimental-utils/src/ts-eslint/RuleTester.ts +++ b/packages/experimental-utils/src/ts-eslint/RuleTester.ts @@ -159,9 +159,6 @@ declare class RuleTesterBase { static it?: (text: string, callback: () => void) => void; } -/** - * @deprecated - use RuleTesterSafe instead - */ class RuleTester extends (ESLintRuleTester as typeof RuleTesterBase) {} export { diff --git a/packages/experimental-utils/src/ts-eslint/SourceCode.ts b/packages/experimental-utils/src/ts-eslint/SourceCode.ts index 82593bbfc6ae..888892d825fa 100644 --- a/packages/experimental-utils/src/ts-eslint/SourceCode.ts +++ b/packages/experimental-utils/src/ts-eslint/SourceCode.ts @@ -296,14 +296,29 @@ declare class SourceCodeBase extends TokenStore { * Determines if two nodes or tokens have at least one whitespace character * between them. Order does not matter. Returns false if the given nodes or * tokens overlap. + * This was added in v6.7.0. + * @since 6.7.0 * @param first The first node or token to check between. * @param second The second node or token to check between. * @returns True if there is a whitespace character between any of the tokens found between the two given nodes or tokens. */ - isSpaceBetween( + isSpaceBetween?( first: TSESTree.Token | TSESTree.Comment | TSESTree.Node, second: TSESTree.Token | TSESTree.Comment | TSESTree.Node, ): boolean; + /** + * Determines if two nodes or tokens have at least one whitespace character + * between them. Order does not matter. Returns false if the given nodes or + * tokens overlap. + * For backward compatibility, this method returns true if there are + * `JSXText` tokens that contain whitespace between the two. + * @param first The first node or token to check between. + * @param second The second node or token to check between. + * @returns {boolean} True if there is a whitespace character between + * any of the tokens found between the two given nodes or tokens. + * @deprecated in favor of isSpaceBetween + */ + isSpaceBetweenTokens(first: TSESTree.Token, second: TSESTree.Token): boolean; /** * The source code split into lines according to ECMA-262 specification. * This is done to avoid each rule needing to do so separately. From 52b60852d0ba6bb6abe519c9d3ec1b231793e91d Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Sun, 17 May 2020 10:57:41 -0700 Subject: [PATCH 31/33] feat(eslint-plugin): [prefer-nullish-coalescing][prefer-optional-chain] remove unsafe fixers These fixers are very unsafe and even providing default options for them are a bad idea. This ensures that they are suggestion fixers in all cases, and removes the options that allow them not to be. --- packages/eslint-plugin/README.md | 4 +- .../docs/rules/prefer-nullish-coalescing.md | 8 - .../docs/rules/prefer-optional-chain.md | 15 +- .../src/rules/prefer-nullish-coalescing.ts | 37 +--- .../src/rules/prefer-optional-chain.ts | 63 ++---- .../rules/prefer-nullish-coalescing.test.ts | 174 +++++++++------- .../tests/rules/prefer-optional-chain.test.ts | 185 ++++++++++++++---- 7 files changed, 271 insertions(+), 215 deletions(-) diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md index fe165f2bc9fc..c2d4531eae07 100644 --- a/packages/eslint-plugin/README.md +++ b/packages/eslint-plugin/README.md @@ -146,8 +146,8 @@ Pro Tip: For larger codebases you may want to consider splitting our linting int | [`@typescript-eslint/prefer-function-type`](./docs/rules/prefer-function-type.md) | Use function types instead of interfaces with call signatures | | :wrench: | | | [`@typescript-eslint/prefer-includes`](./docs/rules/prefer-includes.md) | Enforce `includes` method over `indexOf` method | | :wrench: | :thought_balloon: | | [`@typescript-eslint/prefer-namespace-keyword`](./docs/rules/prefer-namespace-keyword.md) | Require the use of the `namespace` keyword instead of the `module` keyword to declare custom TypeScript modules | :heavy_check_mark: | :wrench: | | -| [`@typescript-eslint/prefer-nullish-coalescing`](./docs/rules/prefer-nullish-coalescing.md) | Enforce the usage of the nullish coalescing operator instead of logical chaining | | :wrench: | :thought_balloon: | -| [`@typescript-eslint/prefer-optional-chain`](./docs/rules/prefer-optional-chain.md) | Prefer using concise optional chain expressions instead of chained logical ands | | :wrench: | | +| [`@typescript-eslint/prefer-nullish-coalescing`](./docs/rules/prefer-nullish-coalescing.md) | Enforce the usage of the nullish coalescing operator instead of logical chaining | | | :thought_balloon: | +| [`@typescript-eslint/prefer-optional-chain`](./docs/rules/prefer-optional-chain.md) | Prefer using concise optional chain expressions instead of chained logical ands | | | | | [`@typescript-eslint/prefer-readonly`](./docs/rules/prefer-readonly.md) | Requires that private members are marked as `readonly` if they're never modified outside of the constructor | | :wrench: | :thought_balloon: | | [`@typescript-eslint/prefer-readonly-parameter-types`](./docs/rules/prefer-readonly-parameter-types.md) | Requires that function parameters are typed as readonly to prevent accidental mutation of inputs | | | :thought_balloon: | | [`@typescript-eslint/prefer-reduce-type-parameter`](./docs/rules/prefer-reduce-type-parameter.md) | Prefer using type parameter when calling `Array#reduce` instead of casting | | :wrench: | :thought_balloon: | diff --git a/packages/eslint-plugin/docs/rules/prefer-nullish-coalescing.md b/packages/eslint-plugin/docs/rules/prefer-nullish-coalescing.md index 5b99e5c613f6..bb32c02895be 100644 --- a/packages/eslint-plugin/docs/rules/prefer-nullish-coalescing.md +++ b/packages/eslint-plugin/docs/rules/prefer-nullish-coalescing.md @@ -46,7 +46,6 @@ type Options = [ { ignoreConditionalTests?: boolean; ignoreMixedLogicalExpressions?: boolean; - forceSuggestionFixer?: boolean; }, ]; @@ -54,7 +53,6 @@ const defaultOptions = [ { ignoreConditionalTests: true, ignoreMixedLogicalExpressions: true, - forceSuggestionFixer: false, }, ]; ``` @@ -133,12 +131,6 @@ a ?? (b && c && d); **_NOTE:_** Errors for this specific case will be presented as suggestions (see below), instead of fixes. This is because it is not always safe to automatically convert `||` to `??` within a mixed logical expression, as we cannot tell the intended precedence of the operator. Note that by design, `??` requires parentheses when used with `&&` or `||` in the same expression. -### `forceSuggestionFixer` - -Setting this option to `true` will cause the rule to use ESLint's "suggested fix" mode for all fixes. _This option is provided as to aid in transitioning your codebase onto this rule_. - -Suggestion fixes cannot be automatically applied via the `--fix` CLI command, but can be _manually_ chosen to be applied one at a time via an IDE or similar. This makes it safe to run autofixers on an existing codebase without worrying about potential runtime behavior changes from this rule's fixer. - ## When Not To Use It If you are not using TypeScript 3.7 (or greater), then you will not be able to use this rule, as the operator is not supported. diff --git a/packages/eslint-plugin/docs/rules/prefer-optional-chain.md b/packages/eslint-plugin/docs/rules/prefer-optional-chain.md index be3352a282bb..6505c93959a6 100644 --- a/packages/eslint-plugin/docs/rules/prefer-optional-chain.md +++ b/packages/eslint-plugin/docs/rules/prefer-optional-chain.md @@ -70,20 +70,7 @@ foo?.a?.b?.method?.(); foo?.a?.b?.c?.d?.e; ``` -## Options - -The rule accepts an options object with the following properties: - -```ts -type Options = { - // if true, the rule will only provide suggested fixes instead of automatically modifying code - suggestInsteadOfAutofix?: boolean; -}; - -const defaults = { - suggestInsteadOfAutofix: false, -}; -``` +**Note:** there are a few edge cases where this rule will false positive. Use your best judgement when evaluating reported errors. ## When Not To Use It diff --git a/packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts b/packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts index 3c616ded75d6..fa6c1bb4e216 100644 --- a/packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts +++ b/packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts @@ -10,10 +10,9 @@ export type Options = [ { ignoreConditionalTests?: boolean; ignoreMixedLogicalExpressions?: boolean; - forceSuggestionFixer?: boolean; }, ]; -export type MessageIds = 'preferNullish'; +export type MessageIds = 'preferNullish' | 'suggestNullish'; export default util.createRule({ name: 'prefer-nullish-coalescing', @@ -27,10 +26,10 @@ export default util.createRule({ suggestion: true, requiresTypeChecking: true, }, - fixable: 'code', messages: { preferNullish: 'Prefer using nullish coalescing operator (`??`) instead of a logical or (`||`), as it is a safer operator.', + suggestNullish: 'Fix to nullish coalescing operator (`??`).', }, schema: [ { @@ -54,19 +53,9 @@ export default util.createRule({ { ignoreConditionalTests: true, ignoreMixedLogicalExpressions: true, - forceSuggestionFixer: false, }, ], - create( - context, - [ - { - ignoreConditionalTests, - ignoreMixedLogicalExpressions, - forceSuggestionFixer, - }, - ], - ) { + create(context, [{ ignoreConditionalTests, ignoreMixedLogicalExpressions }]) { const parserServices = util.getParserServices(context); const sourceCode = context.getSourceCode(); const checker = parserServices.program.getTypeChecker(); @@ -119,23 +108,15 @@ export default util.createRule({ yield fixer.replaceText(barBarOperator, '??'); } - const fixer = - isMixedLogical || forceSuggestionFixer - ? // suggestion instead for cases where we aren't sure if the fixer is completely safe - ({ - suggest: [ - { - messageId: 'preferNullish', - fix, - }, - ], - } as const) - : { fix }; - context.report({ node: barBarOperator, messageId: 'preferNullish', - ...fixer, + suggest: [ + { + messageId: 'suggestNullish', + fix, + }, + ], }); }, }; diff --git a/packages/eslint-plugin/src/rules/prefer-optional-chain.ts b/packages/eslint-plugin/src/rules/prefer-optional-chain.ts index 0d5176b6f107..c2d0db90ea77 100644 --- a/packages/eslint-plugin/src/rules/prefer-optional-chain.ts +++ b/packages/eslint-plugin/src/rules/prefer-optional-chain.ts @@ -31,15 +31,7 @@ The AST will look like this: } */ -type Options = [ - { - suggestInsteadOfAutofix?: boolean; - }, -]; - -type MessageIds = 'preferOptionalChain' | 'optionalChainSuggest'; - -export default util.createRule({ +export default util.createRule({ name: 'prefer-optional-chain', meta: { type: 'suggestion', @@ -50,30 +42,15 @@ export default util.createRule({ recommended: false, suggestion: true, }, - fixable: 'code', messages: { preferOptionalChain: "Prefer using an optional chain expression instead, as it's more concise and easier to read.", optionalChainSuggest: 'Change to an optional chain.', }, - schema: [ - { - type: 'object', - properties: { - suggestInsteadOfAutofix: { - type: 'boolean', - }, - }, - additionalProperties: false, - }, - ], + schema: [], }, - defaultOptions: [ - { - suggestInsteadOfAutofix: false, - }, - ], - create(context, [options]) { + defaultOptions: [], + create(context) { const sourceCode = context.getSourceCode(); return { [[ @@ -189,28 +166,18 @@ export default util.createRule({ } ${sourceCode.getText(previous.right.right)}`; } - if (!options.suggestInsteadOfAutofix) { - context.report({ - node: previous, - messageId: 'preferOptionalChain', - fix(fixer) { - return fixer.replaceText(previous, optionallyChainedCode); + context.report({ + node: previous, + messageId: 'preferOptionalChain', + suggest: [ + { + messageId: 'optionalChainSuggest', + fix: (fixer): TSESLint.RuleFix[] => [ + fixer.replaceText(previous, optionallyChainedCode), + ], }, - }); - } else { - context.report({ - node: previous, - messageId: 'preferOptionalChain', - suggest: [ - { - messageId: 'optionalChainSuggest', - fix: (fixer): TSESLint.RuleFix[] => [ - fixer.replaceText(previous, optionallyChainedCode), - ], - }, - ], - }); - } + ], + }); } }, }; diff --git a/packages/eslint-plugin/tests/rules/prefer-nullish-coalescing.test.ts b/packages/eslint-plugin/tests/rules/prefer-nullish-coalescing.test.ts index 40a8916317c0..a984484edd51 100644 --- a/packages/eslint-plugin/tests/rules/prefer-nullish-coalescing.test.ts +++ b/packages/eslint-plugin/tests/rules/prefer-nullish-coalescing.test.ts @@ -144,11 +144,8 @@ a && b || c || d; code: ` declare const x: ${type} | ${nullish}; x || 'foo'; - `, - output: ` -declare const x: ${type} | ${nullish}; -x ?? 'foo'; - `, + `.trimRight(), + output: null, errors: [ { messageId: 'preferNullish', @@ -156,6 +153,15 @@ x ?? 'foo'; column: 3, endLine: 3, endColumn: 5, + suggestions: [ + { + messageId: 'suggestNullish', + output: ` +declare const x: ${type} | ${nullish}; +x ?? 'foo'; + `.trimRight(), + }, + ], }, ], })), @@ -165,11 +171,8 @@ x ?? 'foo'; code: ` declare const x: ${type} | ${nullish}; x || 'foo' ? null : null; - `, - output: ` -declare const x: ${type} | ${nullish}; -x ?? 'foo' ? null : null; - `, + `.trimRight(), + output: null, options: [{ ignoreConditionalTests: false }], errors: [ { @@ -178,6 +181,15 @@ x ?? 'foo' ? null : null; column: 3, endLine: 3, endColumn: 5, + suggestions: [ + { + messageId: 'suggestNullish', + output: ` +declare const x: ${type} | ${nullish}; +x ?? 'foo' ? null : null; + `.trimRight(), + }, + ], }, ], })), @@ -185,11 +197,8 @@ x ?? 'foo' ? null : null; code: ` declare const x: ${type} | ${nullish}; if (x || 'foo') {} - `, - output: ` -declare const x: ${type} | ${nullish}; -if (x ?? 'foo') {} - `, + `.trimRight(), + output: null, options: [{ ignoreConditionalTests: false }], errors: [ { @@ -198,6 +207,15 @@ if (x ?? 'foo') {} column: 7, endLine: 3, endColumn: 9, + suggestions: [ + { + messageId: 'suggestNullish', + output: ` +declare const x: ${type} | ${nullish}; +if (x ?? 'foo') {} + `.trimRight(), + }, + ], }, ], })), @@ -205,11 +223,8 @@ if (x ?? 'foo') {} code: ` declare const x: ${type} | ${nullish}; do {} while (x || 'foo') - `, - output: ` -declare const x: ${type} | ${nullish}; -do {} while (x ?? 'foo') - `, + `.trimRight(), + output: null, options: [{ ignoreConditionalTests: false }], errors: [ { @@ -218,6 +233,15 @@ do {} while (x ?? 'foo') column: 16, endLine: 3, endColumn: 18, + suggestions: [ + { + messageId: 'suggestNullish', + output: ` +declare const x: ${type} | ${nullish}; +do {} while (x ?? 'foo') + `.trimRight(), + }, + ], }, ], })), @@ -225,11 +249,8 @@ do {} while (x ?? 'foo') code: ` declare const x: ${type} | ${nullish}; for (;x || 'foo';) {} - `, - output: ` -declare const x: ${type} | ${nullish}; -for (;x ?? 'foo';) {} - `, + `.trimRight(), + output: null, options: [{ ignoreConditionalTests: false }], errors: [ { @@ -238,6 +259,15 @@ for (;x ?? 'foo';) {} column: 9, endLine: 3, endColumn: 11, + suggestions: [ + { + messageId: 'suggestNullish', + output: ` +declare const x: ${type} | ${nullish}; +for (;x ?? 'foo';) {} + `.trimRight(), + }, + ], }, ], })), @@ -245,11 +275,8 @@ for (;x ?? 'foo';) {} code: ` declare const x: ${type} | ${nullish}; while (x || 'foo') {} - `, - output: ` -declare const x: ${type} | ${nullish}; -while (x ?? 'foo') {} - `, + `.trimRight(), + output: null, options: [{ ignoreConditionalTests: false }], errors: [ { @@ -258,6 +285,15 @@ while (x ?? 'foo') {} column: 10, endLine: 3, endColumn: 12, + suggestions: [ + { + messageId: 'suggestNullish', + output: ` +declare const x: ${type} | ${nullish}; +while (x ?? 'foo') {} + `.trimRight(), + }, + ], }, ], })), @@ -280,7 +316,7 @@ a || b && c; endColumn: 5, suggestions: [ { - messageId: 'preferNullish', + messageId: 'suggestNullish', output: ` declare const a: ${type} | ${nullish}; declare const b: ${type} | ${nullish}; @@ -310,7 +346,7 @@ a || b || c && d; endColumn: 5, suggestions: [ { - messageId: 'preferNullish', + messageId: 'suggestNullish', output: ` declare const a: ${type} | ${nullish}; declare const b: ${type} | ${nullish}; @@ -329,7 +365,7 @@ declare const d: ${type} | ${nullish}; endColumn: 10, suggestions: [ { - messageId: 'preferNullish', + messageId: 'suggestNullish', output: ` declare const a: ${type} | ${nullish}; declare const b: ${type} | ${nullish}; @@ -360,7 +396,7 @@ a && b || c || d; endColumn: 10, suggestions: [ { - messageId: 'preferNullish', + messageId: 'suggestNullish', output: ` declare const a: ${type} | ${nullish}; declare const b: ${type} | ${nullish}; @@ -379,7 +415,7 @@ a && (b ?? c) || d; endColumn: 15, suggestions: [ { - messageId: 'preferNullish', + messageId: 'suggestNullish', output: ` declare const a: ${type} | ${nullish}; declare const b: ${type} | ${nullish}; @@ -398,11 +434,8 @@ a && b || c ?? d; code: ` declare const x: ${type} | ${nullish}; if (() => x || 'foo') {} - `, - output: ` -declare const x: ${type} | ${nullish}; -if (() => x ?? 'foo') {} - `, + `.trimRight(), + output: null, options: [{ ignoreConditionalTests: true }], errors: [ { @@ -411,6 +444,15 @@ if (() => x ?? 'foo') {} column: 13, endLine: 3, endColumn: 15, + suggestions: [ + { + messageId: 'suggestNullish', + output: ` +declare const x: ${type} | ${nullish}; +if (() => x ?? 'foo') {} + `.trimRight(), + }, + ], }, ], })), @@ -418,11 +460,8 @@ if (() => x ?? 'foo') {} code: ` declare const x: ${type} | ${nullish}; if (function werid() { return x || 'foo' }) {} - `, - output: ` -declare const x: ${type} | ${nullish}; -if (function werid() { return x ?? 'foo' }) {} - `, + `.trimRight(), + output: null, options: [{ ignoreConditionalTests: true }], errors: [ { @@ -431,37 +470,18 @@ if (function werid() { return x ?? 'foo' }) {} column: 33, endLine: 3, endColumn: 35, - }, - ], - })), - - // testing the suggestion fixer option - { - code: ` -declare const x: string | null; -x || 'foo'; - `.trimRight(), - output: null, - options: [{ forceSuggestionFixer: true }], - errors: [ - { - messageId: 'preferNullish', - line: 3, - column: 3, - endLine: 3, - endColumn: 5, suggestions: [ { - messageId: 'preferNullish', + messageId: 'suggestNullish', output: ` -declare const x: string | null; -x ?? 'foo'; +declare const x: ${type} | ${nullish}; +if (function werid() { return x ?? 'foo' }) {} `.trimRight(), }, ], }, ], - }, + })), // https://github.com/typescript-eslint/typescript-eslint/issues/1290 ...nullishTypeInvalidTest((nullish, type) => ({ @@ -471,12 +491,7 @@ declare const b: ${type}; declare const c: ${type}; a || b || c; `.trimRight(), - output: ` -declare const a: ${type} | ${nullish}; -declare const b: ${type}; -declare const c: ${type}; -(a ?? b) || c; - `.trimRight(), + output: null, errors: [ { messageId: 'preferNullish', @@ -484,6 +499,17 @@ declare const c: ${type}; column: 3, endLine: 5, endColumn: 5, + suggestions: [ + { + messageId: 'suggestNullish', + output: ` +declare const a: ${type} | ${nullish}; +declare const b: ${type}; +declare const c: ${type}; +(a ?? b) || c; + `.trimRight(), + }, + ], }, ], })), diff --git a/packages/eslint-plugin/tests/rules/prefer-optional-chain.test.ts b/packages/eslint-plugin/tests/rules/prefer-optional-chain.test.ts index c6eb323827a5..fa3404bfe6f1 100644 --- a/packages/eslint-plugin/tests/rules/prefer-optional-chain.test.ts +++ b/packages/eslint-plugin/tests/rules/prefer-optional-chain.test.ts @@ -80,12 +80,6 @@ const baseCases = [ 'foo && foo.bar && foo.bar.baz && foo.bar.baz[buzz] && foo.bar.baz[buzz]()', output: 'foo?.bar?.baz?.[buzz]?.()', }, - // two-for-one - { - code: 'foo && foo.bar && foo.bar.baz || baz && baz.bar && baz.bar.foo', - output: 'foo?.bar?.baz || baz?.bar?.foo', - errors: 2, - }, // (partially) pre-optional chained { code: @@ -104,10 +98,18 @@ const baseCases = [ c => ({ code: c.code.trim(), - output: c.output.trim(), - errors: Array(c.errors ?? 1).fill({ - messageId: 'preferOptionalChain', - }), + output: null, + errors: [ + { + messageId: 'preferOptionalChain', + suggestions: [ + { + messageId: 'optionalChainSuggest', + output: c.output.trim(), + }, + ], + }, + ], } as TSESLint.InvalidTestCase< InferMessageIdsTypeFromRule, InferOptionsTypeFromRule @@ -149,12 +151,32 @@ ruleTester.run('prefer-optional-chain', rule, { ...baseCases.map(c => ({ ...c, code: `${c.code} && bing`, - output: `${c.output} && bing`, + errors: [ + { + ...c.errors[0], + suggestions: [ + { + ...c.errors[0].suggestions![0], + output: `${c.errors[0].suggestions![0].output} && bing`, + }, + ], + }, + ], })), ...baseCases.map(c => ({ ...c, code: `${c.code} && bing.bong`, - output: `${c.output} && bing.bong`, + errors: [ + { + ...c.errors[0], + suggestions: [ + { + ...c.errors[0].suggestions![0], + output: `${c.errors[0].suggestions![0].output} && bing.bong`, + }, + ], + }, + ], })), // strict nullish equality checks x !== null && x.y !== null ...baseCases.map(c => ({ @@ -173,24 +195,61 @@ ruleTester.run('prefer-optional-chain', rule, { ...c, code: c.code.replace(/&&/g, '!= undefined &&'), })), + // two errors + { + code: noFormat`foo && foo.bar && foo.bar.baz || baz && baz.bar && baz.bar.foo`, + output: null, + errors: [ + { + messageId: 'preferOptionalChain', + suggestions: [ + { + messageId: 'optionalChainSuggest', + output: noFormat`foo?.bar?.baz || baz && baz.bar && baz.bar.foo`, + }, + ], + }, + { + messageId: 'preferOptionalChain', + suggestions: [ + { + messageId: 'optionalChainSuggest', + output: noFormat`foo && foo.bar && foo.bar.baz || baz?.bar?.foo`, + }, + ], + }, + ], + }, { // case with inconsistent checks code: 'foo && foo.bar != null && foo.bar.baz !== undefined && foo.bar.baz.buzz;', - output: 'foo?.bar?.baz?.buzz;', + output: null, errors: [ { messageId: 'preferOptionalChain', + suggestions: [ + { + messageId: 'optionalChainSuggest', + output: 'foo?.bar?.baz?.buzz;', + }, + ], }, ], }, // ensure essential whitespace isn't removed { code: 'foo && foo.bar(baz => );', - output: 'foo?.bar(baz => );', + output: null, errors: [ { messageId: 'preferOptionalChain', + suggestions: [ + { + messageId: 'optionalChainSuggest', + output: 'foo?.bar(baz => );', + }, + ], }, ], parserOptions: { @@ -201,93 +260,147 @@ ruleTester.run('prefer-optional-chain', rule, { }, { code: 'foo && foo.bar(baz => typeof baz);', - output: 'foo?.bar(baz => typeof baz);', + output: null, errors: [ { messageId: 'preferOptionalChain', + suggestions: [ + { + messageId: 'optionalChainSuggest', + output: 'foo?.bar(baz => typeof baz);', + }, + ], }, ], }, { code: noFormat`foo && foo["some long string"] && foo["some long string"].baz`, - output: noFormat`foo?.["some long string"]?.baz`, + output: null, errors: [ { messageId: 'preferOptionalChain', + suggestions: [ + { + messageId: 'optionalChainSuggest', + output: noFormat`foo?.["some long string"]?.baz`, + }, + ], }, ], }, { code: noFormat`foo && foo[\`some long string\`] && foo[\`some long string\`].baz`, - output: noFormat`foo?.[\`some long string\`]?.baz`, + output: null, errors: [ { messageId: 'preferOptionalChain', + suggestions: [ + { + messageId: 'optionalChainSuggest', + output: noFormat`foo?.[\`some long string\`]?.baz`, + }, + ], }, ], }, { code: "foo && foo['some long string'] && foo['some long string'].baz;", - output: "foo?.['some long string']?.baz;", + output: null, errors: [ { messageId: 'preferOptionalChain', + suggestions: [ + { + messageId: 'optionalChainSuggest', + output: "foo?.['some long string']?.baz;", + }, + ], }, ], }, // should preserve comments in a call expression { code: noFormat` - foo && foo.bar(/* comment */a, - // comment2 - b, ); - `, - output: noFormat` - foo?.bar(/* comment */a, - // comment2 - b, ); - `, +foo && foo.bar(/* comment */a, + // comment2 + b, ); + `.trimRight(), + output: null, errors: [ { messageId: 'preferOptionalChain', + suggestions: [ + { + messageId: 'optionalChainSuggest', + output: noFormat` +foo?.bar(/* comment */a, + // comment2 + b, ); + `.trimRight(), + }, + ], }, ], }, // ensure binary expressions that are the last expression do not get removed { code: 'foo && foo.bar != null;', - output: 'foo?.bar != null;', + output: null, errors: [ { messageId: 'preferOptionalChain', + suggestions: [ + { + messageId: 'optionalChainSuggest', + output: 'foo?.bar != null;', + }, + ], }, ], }, { code: 'foo && foo.bar != undefined;', - output: 'foo?.bar != undefined;', + output: null, errors: [ { messageId: 'preferOptionalChain', + suggestions: [ + { + messageId: 'optionalChainSuggest', + output: 'foo?.bar != undefined;', + }, + ], }, ], }, { code: 'foo && foo.bar != null && baz;', - output: 'foo?.bar != null && baz;', + output: null, errors: [ { messageId: 'preferOptionalChain', + suggestions: [ + { + messageId: 'optionalChainSuggest', + output: 'foo?.bar != null && baz;', + }, + ], }, ], }, // other weird cases { code: 'foo && foo?.();', - output: 'foo?.();', + output: null, errors: [ { messageId: 'preferOptionalChain', + suggestions: [ + { + messageId: 'optionalChainSuggest', + output: 'foo?.();', + }, + ], }, ], }, @@ -295,11 +408,6 @@ ruleTester.run('prefer-optional-chain', rule, { { code: 'foo && foo.bar != null && foo.bar.baz !== undefined && foo.bar.baz.buzz;', - options: [ - { - suggestInsteadOfAutofix: true, - }, - ], output: null, errors: [ { @@ -317,11 +425,6 @@ ruleTester.run('prefer-optional-chain', rule, { }, { code: 'foo && foo.bar(baz => );', - options: [ - { - suggestInsteadOfAutofix: true, - }, - ], output: null, errors: [ { From 3dfc46dccbbd28eed2d74c7b6cacddf1a0848598 Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Sun, 17 May 2020 16:05:09 -0700 Subject: [PATCH 32/33] feat: add index files to parser and typescript-estree This just creates a clearer entrypoint for contributors, and helps clearly define exactly what is exported from the modules. --- packages/parser/package.json | 4 ++-- packages/parser/src/index.ts | 6 +++++ packages/parser/src/parser.ts | 19 +++------------ packages/parser/tests/lib/parser.ts | 15 +----------- packages/typescript-estree/package.json | 4 ++-- packages/typescript-estree/src/index.ts | 14 +++++++++++ packages/typescript-estree/src/parser.ts | 23 +------------------ packages/typescript-estree/tests/lib/parse.ts | 2 +- .../tests/lib/persistentParse.ts | 2 +- .../tests/lib/semantic-diagnostics-enabled.ts | 2 +- .../tests/lib/semanticInfo.ts | 2 +- .../typescript-estree/tools/test-utils.ts | 2 +- 12 files changed, 34 insertions(+), 61 deletions(-) create mode 100644 packages/parser/src/index.ts create mode 100644 packages/typescript-estree/src/index.ts diff --git a/packages/parser/package.json b/packages/parser/package.json index 3131dabaaf94..21445c36ecee 100644 --- a/packages/parser/package.json +++ b/packages/parser/package.json @@ -2,8 +2,8 @@ "name": "@typescript-eslint/parser", "version": "2.34.0", "description": "An ESLint custom parser which leverages TypeScript ESTree", - "main": "dist/parser.js", - "types": "dist/parser.d.ts", + "main": "dist/index.js", + "types": "dist/index.d.ts", "files": [ "dist", "README.md", diff --git a/packages/parser/src/index.ts b/packages/parser/src/index.ts new file mode 100644 index 000000000000..1795fe1b36f3 --- /dev/null +++ b/packages/parser/src/index.ts @@ -0,0 +1,6 @@ +export { parse, parseForESLint, ParserOptions } from './parser'; +export { ParserServices } from '@typescript-eslint/typescript-estree'; +export { clearCaches } from '@typescript-eslint/typescript-estree'; + +// note - cannot migrate this to an import statement because it will make TSC copy the package.json to the dist folder +export const version: string = require('../package.json').version; diff --git a/packages/parser/src/parser.ts b/packages/parser/src/parser.ts index 00c0fe57d431..b658c96c82de 100644 --- a/packages/parser/src/parser.ts +++ b/packages/parser/src/parser.ts @@ -1,6 +1,5 @@ import { TSESLint } from '@typescript-eslint/experimental-utils'; import { - AST_NODE_TYPES, parseAndGenerateServices, ParserServices, TSESTreeOptions, @@ -11,9 +10,6 @@ import { analyzeScope } from './analyze-scope'; type ParserOptions = TSESLint.ParserOptions; -// note - cannot migrate this to an import statement because it will make TSC copy the package.json to the dist folder -const packageJSON = require('../package.json'); - interface ParseForESLintResult { ast: TSESTree.Program & { range?: [number, number]; @@ -35,22 +31,14 @@ function validateBoolean( return value; } -//------------------------------------------------------------------------------ -// Public -//------------------------------------------------------------------------------ - -export const version = packageJSON.version; - -export const Syntax = Object.freeze(AST_NODE_TYPES); - -export function parse( +function parse( code: string, options?: ParserOptions, ): ParseForESLintResult['ast'] { return parseForESLint(code, options).ast; } -export function parseForESLint( +function parseForESLint( code: string, options?: ParserOptions | null, ): ParseForESLintResult { @@ -98,5 +86,4 @@ export function parseForESLint( return { ast, services, scopeManager, visitorKeys }; } -export { ParserServices, ParserOptions }; -export { clearCaches } from '@typescript-eslint/typescript-estree'; +export { parse, parseForESLint, ParserOptions }; diff --git a/packages/parser/tests/lib/parser.ts b/packages/parser/tests/lib/parser.ts index 3881456d2ffd..442332b3a840 100644 --- a/packages/parser/tests/lib/parser.ts +++ b/packages/parser/tests/lib/parser.ts @@ -1,10 +1,8 @@ import { TSESLint } from '@typescript-eslint/experimental-utils'; import * as typescriptESTree from '@typescript-eslint/typescript-estree'; -import { parse, parseForESLint, Syntax } from '../../src/parser'; +import { parse, parseForESLint } from '../../src/parser'; import * as scope from '../../src/analyze-scope'; -const { AST_NODE_TYPES } = typescriptESTree; - describe('parser', () => { it('parse() should return just the AST from parseForESLint()', () => { const code = 'const valid = true;'; @@ -65,17 +63,6 @@ describe('parser', () => { }); }); - it('Syntax should contain a frozen object of AST_NODE_TYPES', () => { - expect(Syntax).toEqual(AST_NODE_TYPES); - expect( - // intentionally breaking the readonly - // eslint-disable-next-line @typescript-eslint/no-explicit-any - () => ((Syntax as any).ArrayExpression = 'foo'), - ).toThrowErrorMatchingInlineSnapshot( - `"Cannot assign to read only property 'ArrayExpression' of object '#'"`, - ); - }); - it('`warnOnUnsupportedTypeScriptVersion: false` should set `loggerFn: false` on typescript-estree', () => { const code = 'const valid = true;'; const spy = jest.spyOn(typescriptESTree, 'parseAndGenerateServices'); diff --git a/packages/typescript-estree/package.json b/packages/typescript-estree/package.json index 14e3b4d6cacd..0f4827286daa 100644 --- a/packages/typescript-estree/package.json +++ b/packages/typescript-estree/package.json @@ -2,8 +2,8 @@ "name": "@typescript-eslint/typescript-estree", "version": "2.34.0", "description": "A parser that converts TypeScript source code into an ESTree compatible form", - "main": "dist/parser.js", - "types": "dist/parser.d.ts", + "main": "dist/index.js", + "types": "dist/index.d.ts", "files": [ "dist", "README.md", diff --git a/packages/typescript-estree/src/index.ts b/packages/typescript-estree/src/index.ts new file mode 100644 index 000000000000..d7dc009d4b46 --- /dev/null +++ b/packages/typescript-estree/src/index.ts @@ -0,0 +1,14 @@ +export { + AST, + parse, + parseAndGenerateServices, + ParseAndGenerateServicesResult, +} from './parser'; +export { ParserServices, TSESTreeOptions } from './parser-options'; +export { simpleTraverse } from './simple-traverse'; +export { visitorKeys } from './visitor-keys'; +export * from './ts-estree'; +export { clearCaches } from './create-program/createWatchProgram'; + +// note - cannot migrate this to an import statement because it will make TSC copy the package.json to the dist folder +export const version: string = require('../package.json').version; diff --git a/packages/typescript-estree/src/parser.ts b/packages/typescript-estree/src/parser.ts index f4a1d2047c9d..7c2744d32a02 100644 --- a/packages/typescript-estree/src/parser.ts +++ b/packages/typescript-estree/src/parser.ts @@ -323,10 +323,6 @@ function warnAboutTSVersion(): void { } } -//------------------------------------------------------------------------------ -// Parser -//------------------------------------------------------------------------------ - // eslint-disable-next-line @typescript-eslint/no-empty-interface interface EmptyObject {} type AST = TSESTree.Program & @@ -338,12 +334,6 @@ interface ParseAndGenerateServicesResult { services: ParserServices; } -//------------------------------------------------------------------------------ -// Public -//------------------------------------------------------------------------------ - -const version: string = require('../package.json').version; - function parse( code: string, options?: T, @@ -472,15 +462,4 @@ function parseAndGenerateServices( }; } -export { - AST, - parse, - parseAndGenerateServices, - ParseAndGenerateServicesResult, - version, -}; -export { ParserServices, TSESTreeOptions } from './parser-options'; -export { simpleTraverse } from './simple-traverse'; -export { visitorKeys } from './visitor-keys'; -export * from './ts-estree'; -export { clearCaches } from './create-program/createWatchProgram'; +export { AST, parse, parseAndGenerateServices, ParseAndGenerateServicesResult }; diff --git a/packages/typescript-estree/tests/lib/parse.ts b/packages/typescript-estree/tests/lib/parse.ts index 2504a2fe3320..1e8eaa2305f4 100644 --- a/packages/typescript-estree/tests/lib/parse.ts +++ b/packages/typescript-estree/tests/lib/parse.ts @@ -1,6 +1,6 @@ import debug from 'debug'; import { join, resolve } from 'path'; -import * as parser from '../../src/parser'; +import * as parser from '../../src'; import * as astConverter from '../../src/ast-converter'; import { TSESTreeOptions } from '../../src/parser-options'; import * as sharedParserUtils from '../../src/create-program/shared'; diff --git a/packages/typescript-estree/tests/lib/persistentParse.ts b/packages/typescript-estree/tests/lib/persistentParse.ts index 2b45974e6777..d002cd869c09 100644 --- a/packages/typescript-estree/tests/lib/persistentParse.ts +++ b/packages/typescript-estree/tests/lib/persistentParse.ts @@ -1,7 +1,7 @@ import fs from 'fs'; import path from 'path'; import tmp from 'tmp'; -import { clearCaches, parseAndGenerateServices } from '../../src/parser'; +import { clearCaches, parseAndGenerateServices } from '../../src'; const CONTENTS = { foo: 'console.log("foo")', diff --git a/packages/typescript-estree/tests/lib/semantic-diagnostics-enabled.ts b/packages/typescript-estree/tests/lib/semantic-diagnostics-enabled.ts index fc05b04ec58b..150e55792c68 100644 --- a/packages/typescript-estree/tests/lib/semantic-diagnostics-enabled.ts +++ b/packages/typescript-estree/tests/lib/semantic-diagnostics-enabled.ts @@ -1,6 +1,6 @@ import { readFileSync } from 'fs'; import glob from 'glob'; -import * as parser from '../../src/parser'; +import * as parser from '../../src'; import { extname } from 'path'; import { formatSnapshotName, isJSXFileType } from '../../tools/test-utils'; diff --git a/packages/typescript-estree/tests/lib/semanticInfo.ts b/packages/typescript-estree/tests/lib/semanticInfo.ts index ee9f4c9150dc..36726ac1d528 100644 --- a/packages/typescript-estree/tests/lib/semanticInfo.ts +++ b/packages/typescript-estree/tests/lib/semanticInfo.ts @@ -12,7 +12,7 @@ import { clearCaches, parseAndGenerateServices, ParseAndGenerateServicesResult, -} from '../../src/parser'; +} from '../../src'; import { TSESTree } from '../../src/ts-estree'; const FIXTURES_DIR = './tests/fixtures/semanticInfo'; diff --git a/packages/typescript-estree/tools/test-utils.ts b/packages/typescript-estree/tools/test-utils.ts index 2a9b2f11ddfa..1b386be14498 100644 --- a/packages/typescript-estree/tools/test-utils.ts +++ b/packages/typescript-estree/tools/test-utils.ts @@ -1,4 +1,4 @@ -import * as parser from '../src/parser'; +import * as parser from '../src'; import { TSESTreeOptions } from '../src/parser-options'; export function parseCodeAndGenerateServices( From 7e39f5ba32010a4853b11aa6e3af6985c6c6c25e Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Thu, 21 May 2020 09:43:49 -0700 Subject: [PATCH 33/33] v3.0.0 --- CHANGELOG.md | 42 ++++++++++++++++++++ lerna.json | 2 +- packages/eslint-plugin-internal/CHANGELOG.md | 11 +++++ packages/eslint-plugin-internal/package.json | 4 +- packages/eslint-plugin-tslint/CHANGELOG.md | 12 ++++++ packages/eslint-plugin-tslint/package.json | 6 +-- packages/eslint-plugin/CHANGELOG.md | 39 ++++++++++++++++++ packages/eslint-plugin/package.json | 4 +- packages/experimental-utils/CHANGELOG.md | 21 ++++++++++ packages/experimental-utils/package.json | 4 +- packages/parser/CHANGELOG.md | 23 +++++++++++ packages/parser/package.json | 8 ++-- packages/shared-fixtures/CHANGELOG.md | 13 ++++++ packages/shared-fixtures/package.json | 2 +- packages/typescript-estree/CHANGELOG.md | 24 +++++++++++ packages/typescript-estree/package.json | 4 +- 16 files changed, 202 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 230c2a24659f..4ca1bbfb5c89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,48 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [3.0.0](https://github.com/typescript-eslint/typescript-eslint/compare/v2.34.0...v3.0.0) (2020-05-21) + + +### Bug Fixes + +* **eslint-plugin:** [dot-notation] fix typo in schema ([#2040](https://github.com/typescript-eslint/typescript-eslint/issues/2040)) ([242328f](https://github.com/typescript-eslint/typescript-eslint/commit/242328fa749ee4c72af93433a9bef95f329ac62f)) +* **eslint-plugin:** correct parser peerDep version ([fe59f69](https://github.com/typescript-eslint/typescript-eslint/commit/fe59f69381a0915a4f5135e2e88637a5eea246ba)) +* **experimental-utils:** add back SourceCode.isSpaceBetweenTokens ([ae82ea4](https://github.com/typescript-eslint/typescript-eslint/commit/ae82ea4a85a4ca332ebe6104e96c59dba30411be)) +* **typescript-estree:** remove now defunct `Import` node type ([f199cbd](https://github.com/typescript-eslint/typescript-eslint/commit/f199cbdbbd892b5ba03bfff66f463f3d9c92ee9b)) +* **typescript-estree:** use `TSEmptyBodyFunctionExpression` for body-less nodes ([#1289](https://github.com/typescript-eslint/typescript-eslint/issues/1289)) ([82e7163](https://github.com/typescript-eslint/typescript-eslint/commit/82e7163214b56ccde93ba97807b161669a50a60b)) + + +### Features + +* add index files to parser and typescript-estree ([3dfc46d](https://github.com/typescript-eslint/typescript-eslint/commit/3dfc46dccbbd28eed2d74c7b6cacddf1a0848598)) +* **eslint-plugin:** [no-floating-promises] ignore void operator by default ([#2003](https://github.com/typescript-eslint/typescript-eslint/issues/2003)) ([3626a67](https://github.com/typescript-eslint/typescript-eslint/commit/3626a673cf8117cc995245cd86e466e2553e9b0e)) +* **eslint-plugin:** [no-unnecessary-condition] remove `checkArrayPredicates` and always check it ([#1579](https://github.com/typescript-eslint/typescript-eslint/issues/1579)) ([bfd9b60](https://github.com/typescript-eslint/typescript-eslint/commit/bfd9b606d17d30d5694967a1f01e0e1501ba1022)) +* **eslint-plugin:** [no-unnecessary-condition] report when non-nullish is compared to `null`/`undefined` ([#1659](https://github.com/typescript-eslint/typescript-eslint/issues/1659)) ([7fa9060](https://github.com/typescript-eslint/typescript-eslint/commit/7fa906073903c5eb70609c25f1a91ada14dcdc71)) +* **eslint-plugin:** [prefer-nullish-coalescing][prefer-optional-chain] remove unsafe fixers ([52b6085](https://github.com/typescript-eslint/typescript-eslint/commit/52b60852d0ba6bb6abe519c9d3ec1b231793e91d)) +* **eslint-plugin:** [restrict-template-expressions] `allowNumber: true` by default ([#2005](https://github.com/typescript-eslint/typescript-eslint/issues/2005)) ([643ec24](https://github.com/typescript-eslint/typescript-eslint/commit/643ec240bd901295d9e9ea5c43fc20109c33e982)) +* **eslint-plugin:** [restrict-template-expressions] rename `allowNullable` to `allowNullish` ([#2006](https://github.com/typescript-eslint/typescript-eslint/issues/2006)) ([264b017](https://github.com/typescript-eslint/typescript-eslint/commit/264b017c11c2ab132fcbad18b42a9a0fe639386e)) +* **experimental-utils:** upgrade eslint types for v7 ([#2023](https://github.com/typescript-eslint/typescript-eslint/issues/2023)) ([06869c9](https://github.com/typescript-eslint/typescript-eslint/commit/06869c9656fa37936126666845aee40aad546ebd)) +* bump minimum required TS version ([#2004](https://github.com/typescript-eslint/typescript-eslint/issues/2004)) ([7ad4d7c](https://github.com/typescript-eslint/typescript-eslint/commit/7ad4d7c2db088b6f779b9d883a4acad13eee3775)) +* upgrade to ESLint v7 ([#2022](https://github.com/typescript-eslint/typescript-eslint/issues/2022)) ([208de71](https://github.com/typescript-eslint/typescript-eslint/commit/208de71059746bf38e94bd460346ffb2698a3e12)) +* **eslint-plugin:** [ban-types] rework default options ([#848](https://github.com/typescript-eslint/typescript-eslint/issues/848)) ([8e31d5d](https://github.com/typescript-eslint/typescript-eslint/commit/8e31d5dbe9fe5227fdbefcecfd50ce5dd51360c3)) +* **eslint-plugin:** [no-unnecessary-condition] remove option `ignoreRHS` ([#1163](https://github.com/typescript-eslint/typescript-eslint/issues/1163)) ([ee8dd8f](https://github.com/typescript-eslint/typescript-eslint/commit/ee8dd8f8a9e6c25ac426ce9bb71c5f012c51f264)) +* **eslint-plugin:** [strict-boolean-expression] rework options ([#1631](https://github.com/typescript-eslint/typescript-eslint/issues/1631)) ([cd14482](https://github.com/typescript-eslint/typescript-eslint/commit/cd1448240dca11762fcb9c10e18bb6541a840485)) +* **eslint-plugin:** delete deprecated rules ([#2002](https://github.com/typescript-eslint/typescript-eslint/issues/2002)) ([da0aec2](https://github.com/typescript-eslint/typescript-eslint/commit/da0aec2cfa27902aae7c438a2fe91343c822e4ae)) +* **eslint-plugin:** eslint-recommended: disable no-func-assign ([#984](https://github.com/typescript-eslint/typescript-eslint/issues/984)) ([ae9b8a9](https://github.com/typescript-eslint/typescript-eslint/commit/ae9b8a9c73c0328287de956466257d8bbfbdb20f)) +* **eslint-plugin:** eslint-recommended: disable no-obj-calls ([#1000](https://github.com/typescript-eslint/typescript-eslint/issues/1000)) ([b9ca14c](https://github.com/typescript-eslint/typescript-eslint/commit/b9ca14c5f5ec28a3fde1a9b2d2f6a4dc74d903e4)) +* **eslint-plugin:** update `eslint-recommended` set ([#1996](https://github.com/typescript-eslint/typescript-eslint/issues/1996)) ([9a96e18](https://github.com/typescript-eslint/typescript-eslint/commit/9a96e18400e0a0d738d159d9d01faf41d3586249)) +* **eslint-plugin:** update recommended sets ([#2001](https://github.com/typescript-eslint/typescript-eslint/issues/2001)) ([0126b4f](https://github.com/typescript-eslint/typescript-eslint/commit/0126b4f56f9197d561e90b09962ccceb4f88bc41)) +* **typescript-estree:** align nodes with estree 2020 ([#1389](https://github.com/typescript-eslint/typescript-eslint/issues/1389)) ([aff5b62](https://github.com/typescript-eslint/typescript-eslint/commit/aff5b62044f9b93f2087a1d261e9be3f8d6fd54d)) +* **typescript-estree:** align optional fields ([#1429](https://github.com/typescript-eslint/typescript-eslint/issues/1429)) ([0e0010f](https://github.com/typescript-eslint/typescript-eslint/commit/0e0010f82952f9beeeb84136eea00cc5eecc9db6)) +* drop support for node v8 ([#1997](https://github.com/typescript-eslint/typescript-eslint/issues/1997)) ([b6c3b7b](https://github.com/typescript-eslint/typescript-eslint/commit/b6c3b7b84b8d199fa75a46432febd4a364a63217)) +* **typescript-estree:** always return parserServices ([#716](https://github.com/typescript-eslint/typescript-eslint/issues/716)) ([5b23443](https://github.com/typescript-eslint/typescript-eslint/commit/5b23443c48f3f62424db3e742243f3568080b946)) +* **typescript-estree:** handle 3.9's non-null assertion changes ([#2036](https://github.com/typescript-eslint/typescript-eslint/issues/2036)) ([06bec63](https://github.com/typescript-eslint/typescript-eslint/commit/06bec63c56536db070608ab136d2ad57083f0c6a)) + + + + + # [2.34.0](https://github.com/typescript-eslint/typescript-eslint/compare/v2.33.0...v2.34.0) (2020-05-18) diff --git a/lerna.json b/lerna.json index b498274759cd..e3c6d1f33229 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.34.0", + "version": "3.0.0", "npmClient": "yarn", "useWorkspaces": true, "stream": true diff --git a/packages/eslint-plugin-internal/CHANGELOG.md b/packages/eslint-plugin-internal/CHANGELOG.md index 6adb3ced3669..69d260c66425 100644 --- a/packages/eslint-plugin-internal/CHANGELOG.md +++ b/packages/eslint-plugin-internal/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [3.0.0](https://github.com/typescript-eslint/typescript-eslint/compare/v2.34.0...v3.0.0) (2020-05-21) + + +### Features + +* upgrade to ESLint v7 ([#2022](https://github.com/typescript-eslint/typescript-eslint/issues/2022)) ([208de71](https://github.com/typescript-eslint/typescript-eslint/commit/208de71059746bf38e94bd460346ffb2698a3e12)) + + + + + # [2.34.0](https://github.com/typescript-eslint/typescript-eslint/compare/v2.33.0...v2.34.0) (2020-05-18) diff --git a/packages/eslint-plugin-internal/package.json b/packages/eslint-plugin-internal/package.json index 13abe6554f82..70893eabf717 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": "2.34.0", + "version": "3.0.0", "private": true, "main": "dist/index.js", "scripts": { @@ -12,7 +12,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/experimental-utils": "2.34.0", + "@typescript-eslint/experimental-utils": "3.0.0", "prettier": "*" } } diff --git a/packages/eslint-plugin-tslint/CHANGELOG.md b/packages/eslint-plugin-tslint/CHANGELOG.md index 0d49360362f8..b23cc268c611 100644 --- a/packages/eslint-plugin-tslint/CHANGELOG.md +++ b/packages/eslint-plugin-tslint/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.0.0](https://github.com/typescript-eslint/typescript-eslint/compare/v2.34.0...v3.0.0) (2020-05-21) + + +### Features + +* drop support for node v8 ([#1997](https://github.com/typescript-eslint/typescript-eslint/issues/1997)) ([b6c3b7b](https://github.com/typescript-eslint/typescript-eslint/commit/b6c3b7b84b8d199fa75a46432febd4a364a63217)) +* upgrade to ESLint v7 ([#2022](https://github.com/typescript-eslint/typescript-eslint/issues/2022)) ([208de71](https://github.com/typescript-eslint/typescript-eslint/commit/208de71059746bf38e94bd460346ffb2698a3e12)) + + + + + # [2.34.0](https://github.com/typescript-eslint/typescript-eslint/compare/v2.33.0...v2.34.0) (2020-05-18) **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 1f132c9aec23..a03d8dc77350 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": "2.34.0", + "version": "3.0.0", "main": "dist/index.js", "typings": "src/index.ts", "description": "TSLint wrapper plugin for ESLint", @@ -31,7 +31,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/experimental-utils": "2.34.0", + "@typescript-eslint/experimental-utils": "3.0.0", "lodash": "^4.17.15" }, "peerDependencies": { @@ -41,6 +41,6 @@ }, "devDependencies": { "@types/lodash": "^4.14.149", - "@typescript-eslint/parser": "2.34.0" + "@typescript-eslint/parser": "3.0.0" } } diff --git a/packages/eslint-plugin/CHANGELOG.md b/packages/eslint-plugin/CHANGELOG.md index 8b336d6e5df5..8eb54a7b5741 100644 --- a/packages/eslint-plugin/CHANGELOG.md +++ b/packages/eslint-plugin/CHANGELOG.md @@ -3,6 +3,45 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [3.0.0](https://github.com/typescript-eslint/typescript-eslint/compare/v2.34.0...v3.0.0) (2020-05-21) + + +### Bug Fixes + +* **eslint-plugin:** [dot-notation] fix typo in schema ([#2040](https://github.com/typescript-eslint/typescript-eslint/issues/2040)) ([242328f](https://github.com/typescript-eslint/typescript-eslint/commit/242328fa749ee4c72af93433a9bef95f329ac62f)) +* **eslint-plugin:** correct parser peerDep version ([fe59f69](https://github.com/typescript-eslint/typescript-eslint/commit/fe59f69381a0915a4f5135e2e88637a5eea246ba)) +* **experimental-utils:** add back SourceCode.isSpaceBetweenTokens ([ae82ea4](https://github.com/typescript-eslint/typescript-eslint/commit/ae82ea4a85a4ca332ebe6104e96c59dba30411be)) +* **typescript-estree:** remove now defunct `Import` node type ([f199cbd](https://github.com/typescript-eslint/typescript-eslint/commit/f199cbdbbd892b5ba03bfff66f463f3d9c92ee9b)) +* **typescript-estree:** use `TSEmptyBodyFunctionExpression` for body-less nodes ([#1289](https://github.com/typescript-eslint/typescript-eslint/issues/1289)) ([82e7163](https://github.com/typescript-eslint/typescript-eslint/commit/82e7163214b56ccde93ba97807b161669a50a60b)) + + +### Features + +* **eslint-plugin:** [ban-types] rework default options ([#848](https://github.com/typescript-eslint/typescript-eslint/issues/848)) ([8e31d5d](https://github.com/typescript-eslint/typescript-eslint/commit/8e31d5dbe9fe5227fdbefcecfd50ce5dd51360c3)) +* **eslint-plugin:** [no-floating-promises] ignore void operator by default ([#2003](https://github.com/typescript-eslint/typescript-eslint/issues/2003)) ([3626a67](https://github.com/typescript-eslint/typescript-eslint/commit/3626a673cf8117cc995245cd86e466e2553e9b0e)) +* **eslint-plugin:** [prefer-nullish-coalescing][prefer-optional-chain] remove unsafe fixers ([52b6085](https://github.com/typescript-eslint/typescript-eslint/commit/52b60852d0ba6bb6abe519c9d3ec1b231793e91d)) +* **experimental-utils:** upgrade eslint types for v7 ([#2023](https://github.com/typescript-eslint/typescript-eslint/issues/2023)) ([06869c9](https://github.com/typescript-eslint/typescript-eslint/commit/06869c9656fa37936126666845aee40aad546ebd)) +* upgrade to ESLint v7 ([#2022](https://github.com/typescript-eslint/typescript-eslint/issues/2022)) ([208de71](https://github.com/typescript-eslint/typescript-eslint/commit/208de71059746bf38e94bd460346ffb2698a3e12)) +* **eslint-plugin:** [no-unnecessary-condition] remove `checkArrayPredicates` and always check it ([#1579](https://github.com/typescript-eslint/typescript-eslint/issues/1579)) ([bfd9b60](https://github.com/typescript-eslint/typescript-eslint/commit/bfd9b606d17d30d5694967a1f01e0e1501ba1022)) +* **eslint-plugin:** [no-unnecessary-condition] remove option `ignoreRHS` ([#1163](https://github.com/typescript-eslint/typescript-eslint/issues/1163)) ([ee8dd8f](https://github.com/typescript-eslint/typescript-eslint/commit/ee8dd8f8a9e6c25ac426ce9bb71c5f012c51f264)) +* **eslint-plugin:** [no-unnecessary-condition] report when non-nullish is compared to `null`/`undefined` ([#1659](https://github.com/typescript-eslint/typescript-eslint/issues/1659)) ([7fa9060](https://github.com/typescript-eslint/typescript-eslint/commit/7fa906073903c5eb70609c25f1a91ada14dcdc71)) +* **eslint-plugin:** [restrict-template-expressions] `allowNumber: true` by default ([#2005](https://github.com/typescript-eslint/typescript-eslint/issues/2005)) ([643ec24](https://github.com/typescript-eslint/typescript-eslint/commit/643ec240bd901295d9e9ea5c43fc20109c33e982)) +* **eslint-plugin:** [restrict-template-expressions] rename `allowNullable` to `allowNullish` ([#2006](https://github.com/typescript-eslint/typescript-eslint/issues/2006)) ([264b017](https://github.com/typescript-eslint/typescript-eslint/commit/264b017c11c2ab132fcbad18b42a9a0fe639386e)) +* **eslint-plugin:** [strict-boolean-expression] rework options ([#1631](https://github.com/typescript-eslint/typescript-eslint/issues/1631)) ([cd14482](https://github.com/typescript-eslint/typescript-eslint/commit/cd1448240dca11762fcb9c10e18bb6541a840485)) +* **eslint-plugin:** delete deprecated rules ([#2002](https://github.com/typescript-eslint/typescript-eslint/issues/2002)) ([da0aec2](https://github.com/typescript-eslint/typescript-eslint/commit/da0aec2cfa27902aae7c438a2fe91343c822e4ae)) +* **eslint-plugin:** eslint-recommended: disable no-func-assign ([#984](https://github.com/typescript-eslint/typescript-eslint/issues/984)) ([ae9b8a9](https://github.com/typescript-eslint/typescript-eslint/commit/ae9b8a9c73c0328287de956466257d8bbfbdb20f)) +* **eslint-plugin:** eslint-recommended: disable no-obj-calls ([#1000](https://github.com/typescript-eslint/typescript-eslint/issues/1000)) ([b9ca14c](https://github.com/typescript-eslint/typescript-eslint/commit/b9ca14c5f5ec28a3fde1a9b2d2f6a4dc74d903e4)) +* **eslint-plugin:** update `eslint-recommended` set ([#1996](https://github.com/typescript-eslint/typescript-eslint/issues/1996)) ([9a96e18](https://github.com/typescript-eslint/typescript-eslint/commit/9a96e18400e0a0d738d159d9d01faf41d3586249)) +* **eslint-plugin:** update recommended sets ([#2001](https://github.com/typescript-eslint/typescript-eslint/issues/2001)) ([0126b4f](https://github.com/typescript-eslint/typescript-eslint/commit/0126b4f56f9197d561e90b09962ccceb4f88bc41)) +* **typescript-estree:** align nodes with estree 2020 ([#1389](https://github.com/typescript-eslint/typescript-eslint/issues/1389)) ([aff5b62](https://github.com/typescript-eslint/typescript-eslint/commit/aff5b62044f9b93f2087a1d261e9be3f8d6fd54d)) +* drop support for node v8 ([#1997](https://github.com/typescript-eslint/typescript-eslint/issues/1997)) ([b6c3b7b](https://github.com/typescript-eslint/typescript-eslint/commit/b6c3b7b84b8d199fa75a46432febd4a364a63217)) +* **typescript-estree:** always return parserServices ([#716](https://github.com/typescript-eslint/typescript-eslint/issues/716)) ([5b23443](https://github.com/typescript-eslint/typescript-eslint/commit/5b23443c48f3f62424db3e742243f3568080b946)) +* **typescript-estree:** handle 3.9's non-null assertion changes ([#2036](https://github.com/typescript-eslint/typescript-eslint/issues/2036)) ([06bec63](https://github.com/typescript-eslint/typescript-eslint/commit/06bec63c56536db070608ab136d2ad57083f0c6a)) + + + + + # [2.34.0](https://github.com/typescript-eslint/typescript-eslint/compare/v2.33.0...v2.34.0) (2020-05-18) diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index b82f612856e5..c5e199b8d0e5 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/eslint-plugin", - "version": "2.34.0", + "version": "3.0.0", "description": "TypeScript plugin for ESLint", "keywords": [ "eslint", @@ -41,7 +41,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/experimental-utils": "2.34.0", + "@typescript-eslint/experimental-utils": "3.0.0", "functional-red-black-tree": "^1.0.1", "regexpp": "^3.0.0", "semver": "^7.3.2", diff --git a/packages/experimental-utils/CHANGELOG.md b/packages/experimental-utils/CHANGELOG.md index 35689c4465cb..22fd20879645 100644 --- a/packages/experimental-utils/CHANGELOG.md +++ b/packages/experimental-utils/CHANGELOG.md @@ -3,6 +3,27 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [3.0.0](https://github.com/typescript-eslint/typescript-eslint/compare/v2.34.0...v3.0.0) (2020-05-21) + + +### Bug Fixes + +* **experimental-utils:** add back SourceCode.isSpaceBetweenTokens ([ae82ea4](https://github.com/typescript-eslint/typescript-eslint/commit/ae82ea4a85a4ca332ebe6104e96c59dba30411be)) +* **typescript-estree:** remove now defunct `Import` node type ([f199cbd](https://github.com/typescript-eslint/typescript-eslint/commit/f199cbdbbd892b5ba03bfff66f463f3d9c92ee9b)) + + +### Features + +* **experimental-utils:** upgrade eslint types for v7 ([#2023](https://github.com/typescript-eslint/typescript-eslint/issues/2023)) ([06869c9](https://github.com/typescript-eslint/typescript-eslint/commit/06869c9656fa37936126666845aee40aad546ebd)) +* drop support for node v8 ([#1997](https://github.com/typescript-eslint/typescript-eslint/issues/1997)) ([b6c3b7b](https://github.com/typescript-eslint/typescript-eslint/commit/b6c3b7b84b8d199fa75a46432febd4a364a63217)) +* upgrade to ESLint v7 ([#2022](https://github.com/typescript-eslint/typescript-eslint/issues/2022)) ([208de71](https://github.com/typescript-eslint/typescript-eslint/commit/208de71059746bf38e94bd460346ffb2698a3e12)) +* **eslint-plugin:** [ban-types] rework default options ([#848](https://github.com/typescript-eslint/typescript-eslint/issues/848)) ([8e31d5d](https://github.com/typescript-eslint/typescript-eslint/commit/8e31d5dbe9fe5227fdbefcecfd50ce5dd51360c3)) +* **typescript-estree:** always return parserServices ([#716](https://github.com/typescript-eslint/typescript-eslint/issues/716)) ([5b23443](https://github.com/typescript-eslint/typescript-eslint/commit/5b23443c48f3f62424db3e742243f3568080b946)) + + + + + # [2.34.0](https://github.com/typescript-eslint/typescript-eslint/compare/v2.33.0...v2.34.0) (2020-05-18) diff --git a/packages/experimental-utils/package.json b/packages/experimental-utils/package.json index b05dda94129e..17a3255113a7 100644 --- a/packages/experimental-utils/package.json +++ b/packages/experimental-utils/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/experimental-utils", - "version": "2.34.0", + "version": "3.0.0", "description": "(Experimental) Utilities for working with TypeScript + ESLint together", "keywords": [ "eslint", @@ -37,7 +37,7 @@ }, "dependencies": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "2.34.0", + "@typescript-eslint/typescript-estree": "3.0.0", "eslint-scope": "^5.0.0", "eslint-utils": "^2.0.0" }, diff --git a/packages/parser/CHANGELOG.md b/packages/parser/CHANGELOG.md index 60c7c399d3bb..f804624a6b0c 100644 --- a/packages/parser/CHANGELOG.md +++ b/packages/parser/CHANGELOG.md @@ -3,6 +3,29 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [3.0.0](https://github.com/typescript-eslint/typescript-eslint/compare/v2.34.0...v3.0.0) (2020-05-21) + + +### Bug Fixes + +* **typescript-estree:** use `TSEmptyBodyFunctionExpression` for body-less nodes ([#1289](https://github.com/typescript-eslint/typescript-eslint/issues/1289)) ([82e7163](https://github.com/typescript-eslint/typescript-eslint/commit/82e7163214b56ccde93ba97807b161669a50a60b)) + + +### Features + +* add index files to parser and typescript-estree ([3dfc46d](https://github.com/typescript-eslint/typescript-eslint/commit/3dfc46dccbbd28eed2d74c7b6cacddf1a0848598)) +* **experimental-utils:** upgrade eslint types for v7 ([#2023](https://github.com/typescript-eslint/typescript-eslint/issues/2023)) ([06869c9](https://github.com/typescript-eslint/typescript-eslint/commit/06869c9656fa37936126666845aee40aad546ebd)) +* upgrade to ESLint v7 ([#2022](https://github.com/typescript-eslint/typescript-eslint/issues/2022)) ([208de71](https://github.com/typescript-eslint/typescript-eslint/commit/208de71059746bf38e94bd460346ffb2698a3e12)) +* **typescript-estree:** align nodes with estree 2020 ([#1389](https://github.com/typescript-eslint/typescript-eslint/issues/1389)) ([aff5b62](https://github.com/typescript-eslint/typescript-eslint/commit/aff5b62044f9b93f2087a1d261e9be3f8d6fd54d)) +* **typescript-estree:** align optional fields ([#1429](https://github.com/typescript-eslint/typescript-eslint/issues/1429)) ([0e0010f](https://github.com/typescript-eslint/typescript-eslint/commit/0e0010f82952f9beeeb84136eea00cc5eecc9db6)) +* drop support for node v8 ([#1997](https://github.com/typescript-eslint/typescript-eslint/issues/1997)) ([b6c3b7b](https://github.com/typescript-eslint/typescript-eslint/commit/b6c3b7b84b8d199fa75a46432febd4a364a63217)) +* **eslint-plugin:** [ban-types] rework default options ([#848](https://github.com/typescript-eslint/typescript-eslint/issues/848)) ([8e31d5d](https://github.com/typescript-eslint/typescript-eslint/commit/8e31d5dbe9fe5227fdbefcecfd50ce5dd51360c3)) +* **typescript-estree:** handle 3.9's non-null assertion changes ([#2036](https://github.com/typescript-eslint/typescript-eslint/issues/2036)) ([06bec63](https://github.com/typescript-eslint/typescript-eslint/commit/06bec63c56536db070608ab136d2ad57083f0c6a)) + + + + + # [2.34.0](https://github.com/typescript-eslint/typescript-eslint/compare/v2.33.0...v2.34.0) (2020-05-18) **Note:** Version bump only for package @typescript-eslint/parser diff --git a/packages/parser/package.json b/packages/parser/package.json index 21445c36ecee..030c9f291c52 100644 --- a/packages/parser/package.json +++ b/packages/parser/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/parser", - "version": "2.34.0", + "version": "3.0.0", "description": "An ESLint custom parser which leverages TypeScript ESTree", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -43,13 +43,13 @@ }, "dependencies": { "@types/eslint-visitor-keys": "^1.0.0", - "@typescript-eslint/experimental-utils": "2.34.0", - "@typescript-eslint/typescript-estree": "2.34.0", + "@typescript-eslint/experimental-utils": "3.0.0", + "@typescript-eslint/typescript-estree": "3.0.0", "eslint-visitor-keys": "^1.1.0" }, "devDependencies": { "@types/glob": "^7.1.1", - "@typescript-eslint/shared-fixtures": "2.34.0", + "@typescript-eslint/shared-fixtures": "3.0.0", "glob": "*" }, "peerDependenciesMeta": { diff --git a/packages/shared-fixtures/CHANGELOG.md b/packages/shared-fixtures/CHANGELOG.md index 3c9b56119594..772c8d67d50b 100644 --- a/packages/shared-fixtures/CHANGELOG.md +++ b/packages/shared-fixtures/CHANGELOG.md @@ -3,6 +3,19 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [3.0.0](https://github.com/typescript-eslint/typescript-eslint/compare/v2.34.0...v3.0.0) (2020-05-21) + + +### Features + +* **typescript-estree:** align nodes with estree 2020 ([#1389](https://github.com/typescript-eslint/typescript-eslint/issues/1389)) ([aff5b62](https://github.com/typescript-eslint/typescript-eslint/commit/aff5b62044f9b93f2087a1d261e9be3f8d6fd54d)) +* **typescript-estree:** align optional fields ([#1429](https://github.com/typescript-eslint/typescript-eslint/issues/1429)) ([0e0010f](https://github.com/typescript-eslint/typescript-eslint/commit/0e0010f82952f9beeeb84136eea00cc5eecc9db6)) +* **typescript-estree:** handle 3.9's non-null assertion changes ([#2036](https://github.com/typescript-eslint/typescript-eslint/issues/2036)) ([06bec63](https://github.com/typescript-eslint/typescript-eslint/commit/06bec63c56536db070608ab136d2ad57083f0c6a)) + + + + + # [2.34.0](https://github.com/typescript-eslint/typescript-eslint/compare/v2.33.0...v2.34.0) (2020-05-18) **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 1cbdc49e86b6..09e9adfacc26 100644 --- a/packages/shared-fixtures/package.json +++ b/packages/shared-fixtures/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/shared-fixtures", - "version": "2.34.0", + "version": "3.0.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 bc06b6d34f19..4e5b9086492b 100644 --- a/packages/typescript-estree/CHANGELOG.md +++ b/packages/typescript-estree/CHANGELOG.md @@ -3,6 +3,30 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [3.0.0](https://github.com/typescript-eslint/typescript-eslint/compare/v2.34.0...v3.0.0) (2020-05-21) + + +### Bug Fixes + +* **typescript-estree:** remove now defunct `Import` node type ([f199cbd](https://github.com/typescript-eslint/typescript-eslint/commit/f199cbdbbd892b5ba03bfff66f463f3d9c92ee9b)) +* **typescript-estree:** use `TSEmptyBodyFunctionExpression` for body-less nodes ([#1289](https://github.com/typescript-eslint/typescript-eslint/issues/1289)) ([82e7163](https://github.com/typescript-eslint/typescript-eslint/commit/82e7163214b56ccde93ba97807b161669a50a60b)) + + +### Features + +* add index files to parser and typescript-estree ([3dfc46d](https://github.com/typescript-eslint/typescript-eslint/commit/3dfc46dccbbd28eed2d74c7b6cacddf1a0848598)) +* bump minimum required TS version ([#2004](https://github.com/typescript-eslint/typescript-eslint/issues/2004)) ([7ad4d7c](https://github.com/typescript-eslint/typescript-eslint/commit/7ad4d7c2db088b6f779b9d883a4acad13eee3775)) +* **eslint-plugin:** [ban-types] rework default options ([#848](https://github.com/typescript-eslint/typescript-eslint/issues/848)) ([8e31d5d](https://github.com/typescript-eslint/typescript-eslint/commit/8e31d5dbe9fe5227fdbefcecfd50ce5dd51360c3)) +* **typescript-estree:** align nodes with estree 2020 ([#1389](https://github.com/typescript-eslint/typescript-eslint/issues/1389)) ([aff5b62](https://github.com/typescript-eslint/typescript-eslint/commit/aff5b62044f9b93f2087a1d261e9be3f8d6fd54d)) +* **typescript-estree:** align optional fields ([#1429](https://github.com/typescript-eslint/typescript-eslint/issues/1429)) ([0e0010f](https://github.com/typescript-eslint/typescript-eslint/commit/0e0010f82952f9beeeb84136eea00cc5eecc9db6)) +* drop support for node v8 ([#1997](https://github.com/typescript-eslint/typescript-eslint/issues/1997)) ([b6c3b7b](https://github.com/typescript-eslint/typescript-eslint/commit/b6c3b7b84b8d199fa75a46432febd4a364a63217)) +* **typescript-estree:** always return parserServices ([#716](https://github.com/typescript-eslint/typescript-eslint/issues/716)) ([5b23443](https://github.com/typescript-eslint/typescript-eslint/commit/5b23443c48f3f62424db3e742243f3568080b946)) +* **typescript-estree:** handle 3.9's non-null assertion changes ([#2036](https://github.com/typescript-eslint/typescript-eslint/issues/2036)) ([06bec63](https://github.com/typescript-eslint/typescript-eslint/commit/06bec63c56536db070608ab136d2ad57083f0c6a)) + + + + + # [2.34.0](https://github.com/typescript-eslint/typescript-eslint/compare/v2.33.0...v2.34.0) (2020-05-18) diff --git a/packages/typescript-estree/package.json b/packages/typescript-estree/package.json index 0f4827286daa..cfb89a302ccb 100644 --- a/packages/typescript-estree/package.json +++ b/packages/typescript-estree/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/typescript-estree", - "version": "2.34.0", + "version": "3.0.0", "description": "A parser that converts TypeScript source code into an ESTree compatible form", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -58,7 +58,7 @@ "@types/lodash": "^4.14.149", "@types/semver": "^7.1.0", "@types/tmp": "^0.2.0", - "@typescript-eslint/shared-fixtures": "2.34.0", + "@typescript-eslint/shared-fixtures": "3.0.0", "tmp": "^0.2.1", "typescript": "*" },