From 3769f510821e4012baef72dfac42f7c756fa097e Mon Sep 17 00:00:00 2001 From: Anix Date: Mon, 30 Mar 2020 10:42:37 +0000 Subject: [PATCH 1/8] feat(eslint-plugin): new extendedrule 'no-invalid-this' --- packages/eslint-plugin/README.md | 1 + .../docs/rules/no-invalid-this.md | 26 + packages/eslint-plugin/src/configs/all.json | 2 + packages/eslint-plugin/src/rules/index.ts | 2 + .../src/rules/no-invalid-this.ts | 86 ++++ .../tests/rules/no-invalid-this.test.ts | 465 ++++++++++++++++++ .../eslint-plugin/typings/eslint-rules.d.ts | 19 + 7 files changed, 601 insertions(+) create mode 100644 packages/eslint-plugin/docs/rules/no-invalid-this.md create mode 100644 packages/eslint-plugin/src/rules/no-invalid-this.ts create mode 100644 packages/eslint-plugin/tests/rules/no-invalid-this.test.ts diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md index c4507267c6f..4422341af25 100644 --- a/packages/eslint-plugin/README.md +++ b/packages/eslint-plugin/README.md @@ -190,6 +190,7 @@ In these cases, we create what we call an extension rule; a rule within our plug | [`@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-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: | | | diff --git a/packages/eslint-plugin/docs/rules/no-invalid-this.md b/packages/eslint-plugin/docs/rules/no-invalid-this.md new file mode 100644 index 00000000000..34e5fb8e875 --- /dev/null +++ b/packages/eslint-plugin/docs/rules/no-invalid-this.md @@ -0,0 +1,26 @@ +# disallow `this` keywords outside of classes or class-like objects (`no-invalid-this`) + +## Rule Details + +This rule extends the base [`eslint/no-invalid-this`](https://eslint.org/docs/rules/no-invalid-this) rule. +It supports all options and features of the base rule. + +## How to use + +```cjson +{ + // note you must disable the base rule as it can report incorrect errors + "no-invalid-this": "off", + "@typescript-eslint/no-invalid-this": ["error"] +} +``` + +## Options + +See [`eslint/no-invalid-this` options](https://eslint.org/docs/rules/no-invalid-this#options). + +## When Not To Use It + +When you are indifferent as to how your variables are initialized. + +Taken with ❤️ [from ESLint core](https://github.com/eslint/eslint/blob/master/docs/rules/no-invalid-this.md) diff --git a/packages/eslint-plugin/src/configs/all.json b/packages/eslint-plugin/src/configs/all.json index 99e6060d670..ba09260ca56 100644 --- a/packages/eslint-plugin/src/configs/all.json +++ b/packages/eslint-plugin/src/configs/all.json @@ -50,6 +50,8 @@ "@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", "no-magic-numbers": "off", "@typescript-eslint/no-magic-numbers": "error", "@typescript-eslint/no-misused-new": "error", diff --git a/packages/eslint-plugin/src/rules/index.ts b/packages/eslint-plugin/src/rules/index.ts index cbc3b8c68f9..9bf9967029d 100644 --- a/packages/eslint-plugin/src/rules/index.ts +++ b/packages/eslint-plugin/src/rules/index.ts @@ -40,6 +40,7 @@ import noFloatingPromises from './no-floating-promises'; import noForInArray from './no-for-in-array'; import noImpliedEval from './no-implied-eval'; import noInferrableTypes from './no-inferrable-types'; +import noInvalidThis from './no-invalid-this'; import noMagicNumbers from './no-magic-numbers'; import noMisusedNew from './no-misused-new'; import noMisusedPromises from './no-misused-promises'; @@ -142,6 +143,7 @@ export default { 'no-for-in-array': noForInArray, 'no-implied-eval': noImpliedEval, 'no-inferrable-types': noInferrableTypes, + 'no-invalid-this': noInvalidThis, 'no-magic-numbers': noMagicNumbers, 'no-misused-new': noMisusedNew, 'no-misused-promises': noMisusedPromises, diff --git a/packages/eslint-plugin/src/rules/no-invalid-this.ts b/packages/eslint-plugin/src/rules/no-invalid-this.ts new file mode 100644 index 00000000000..d192931b72c --- /dev/null +++ b/packages/eslint-plugin/src/rules/no-invalid-this.ts @@ -0,0 +1,86 @@ +import { TSESTree } from '@typescript-eslint/experimental-utils'; +import baseRule from 'eslint/lib/rules/no-invalid-this'; +import { + InferOptionsTypeFromRule, + InferMessageIdsTypeFromRule, + createRule, + deepMerge, +} from '../util'; + +export type Options = InferOptionsTypeFromRule; +export type MessageIds = InferMessageIdsTypeFromRule; + +const schema = deepMerge( + Array.isArray(baseRule.meta.schema) + ? baseRule.meta.schema[0] + : baseRule.meta.schema, + { + properties: { + capIsConstructor: { + type: 'boolean', + default: true, + }, + }, + }, +); + +export default createRule({ + name: 'no-invalid-this', + meta: { + type: 'suggestion', + docs: { + description: + 'disallow `this` keywords outside of classes or class-like objects', + category: 'Best Practices', + recommended: false, + extendsBaseRule: true, + }, + messages: baseRule.meta.messages, + schema: [schema], + }, + defaultOptions: [{ capIsConstructor: true }], + create(context) { + const rules = baseRule.create(context); + let argList: Array = []; + + return { + ...rules, + FunctionDeclaration(node: TSESTree.FunctionDeclaration): void { + const names = node?.params.map( + (param: TSESTree.Parameter) => param?.name, + ); + argList.push(names); + // baseRule's work + rules.FunctionDeclaration(node); + }, + 'FunctionDeclaration:exit'(node: TSESTree.FunctionDeclaration): void { + argList.pop(); + // baseRule's work + rules['FunctionDeclaration:exit'](node); + }, + FunctionExpression(node: TSESTree.FunctionExpression): void { + const names = node?.params.map( + (param: TSESTree.Parameter) => param?.name, + ); + argList.push(names); + // baseRule's work + rules.FunctionExpression(node); + }, + 'FunctionExpression:exit'(node: TSESTree.FunctionExpression): void { + argList.pop(); + // baseRule's work + rules['FunctionExpression:exit'](node); + }, + ThisExpression(node: TSESTree.ThisExpression) { + const lastFnArg = argList[argList.length - 1]; + + if (lastFnArg?.some((name: string) => name === 'this')) { + return; + } + + // baseRule's work + rules.ThisExpression(node); + }, + }; + }, +}); diff --git a/packages/eslint-plugin/tests/rules/no-invalid-this.test.ts b/packages/eslint-plugin/tests/rules/no-invalid-this.test.ts new file mode 100644 index 00000000000..0070fefb1be --- /dev/null +++ b/packages/eslint-plugin/tests/rules/no-invalid-this.test.ts @@ -0,0 +1,465 @@ +import { AST_NODE_TYPES } from '@typescript-eslint/experimental-utils'; +import rule from '../../src/rules/no-invalid-this'; +import { RuleTester, getFixturesRootDir } from '../RuleTester'; + +const rootPath = getFixturesRootDir(); + +const ruleTester = new RuleTester({ + parser: '@typescript-eslint/parser', + parserOptions: { + sourceType: 'module', + tsconfigRootDir: rootPath, + project: './tsconfig.json', + }, +}); + +const error = { + messageId: 'unexpectedThis', +}; + +ruleTester.run('no-invalid-this', rule, { + valid: [ + `describe('foo', () => { + it('does something', function(this: Mocha.Context) { + this.timeout(100); + // done + }); + });`, + ` + interface SomeType { prop: string } + function foo(this: SomeType) { + this.prop; + }`, + `function foo(this: prop){ + this.propMethod() + }`, + ' z(function(x,this: context ) { console.log(x, this) });', + // https://github.com/eslint/eslint/issues/3287 + + 'function foo() { /** @this Obj*/ return function bar() { console.log(this); z(x => console.log(x, this)); }; }', + + // https://github.com/eslint/eslint/issues/6824 + + 'var Ctor = function() { console.log(this); z(x => console.log(x, this)); }', + // Constructors. + { + code: + 'function Foo() { console.log(this); z(x => console.log(x, this)); }', + }, + { + code: + 'function Foo() { console.log(this); z(x => console.log(x, this)); }', + + options: [{}], // test the default value in schema + }, + { + code: + 'function Foo() { console.log(this); z(x => console.log(x, this)); }', + + options: [{ capIsConstructor: true }], // test explicitly set option to the default value + }, + { + code: + 'var Foo = function Foo() { console.log(this); z(x => console.log(x, this)); };', + }, + { + code: + 'class A {constructor() { console.log(this); z(x => console.log(x, this)); }};', + }, + + // On a property. + { + code: + 'var obj = {foo: function() { console.log(this); z(x => console.log(x, this)); }};', + }, + { + code: + 'var obj = {foo() { console.log(this); z(x => console.log(x, this)); }};', + }, + { + code: + 'var obj = {foo: foo || function() { console.log(this); z(x => console.log(x, this)); }};', + }, + { + code: + 'var obj = {foo: hasNative ? foo : function() { console.log(this); z(x => console.log(x, this)); }};', + }, + { + code: + 'var obj = {foo: (function() { return function() { console.log(this); z(x => console.log(x, this)); }; })()};', + }, + { + code: + 'Object.defineProperty(obj, "foo", {value: function() { console.log(this); z(x => console.log(x, this)); }})', + }, + { + code: + 'Object.defineProperties(obj, {foo: {value: function() { console.log(this); z(x => console.log(x, this)); }}})', + }, + + // Assigns to a property. + { + code: + 'obj.foo = function() { console.log(this); z(x => console.log(x, this)); };', + }, + { + code: + 'obj.foo = foo || function() { console.log(this); z(x => console.log(x, this)); };', + }, + { + code: + 'obj.foo = foo ? bar : function() { console.log(this); z(x => console.log(x, this)); };', + }, + { + code: + 'obj.foo = (function() { return function() { console.log(this); z(x => console.log(x, this)); }; })();', + }, + { + code: + 'obj.foo = (() => function() { console.log(this); z(x => console.log(x, this)); })();', + }, + + // Bind/Call/Apply + '(function() { console.log(this); z(x => console.log(x, this)); }).call(obj);', + 'var foo = function() { console.log(this); z(x => console.log(x, this)); }.bind(obj);', + 'Reflect.apply(function() { console.log(this); z(x => console.log(x, this)); }, obj, []);', + '(function() { console.log(this); z(x => console.log(x, this)); }).apply(obj);', + + // Class Instance Methods. + 'class A {foo() { console.log(this); z(x => console.log(x, this)); }};', + + // Array methods. + + 'Array.from([], function() { console.log(this); z(x => console.log(x, this)); }, obj);', + + 'foo.every(function() { console.log(this); z(x => console.log(x, this)); }, obj);', + + 'foo.filter(function() { console.log(this); z(x => console.log(x, this)); }, obj);', + + 'foo.find(function() { console.log(this); z(x => console.log(x, this)); }, obj);', + + 'foo.findIndex(function() { console.log(this); z(x => console.log(x, this)); }, obj);', + + 'foo.forEach(function() { console.log(this); z(x => console.log(x, this)); }, obj);', + + 'foo.map(function() { console.log(this); z(x => console.log(x, this)); }, obj);', + + 'foo.some(function() { console.log(this); z(x => console.log(x, this)); }, obj);', + + // @this tag. + + '/** @this Obj */ function foo() { console.log(this); z(x => console.log(x, this)); }', + + 'foo(/* @this Obj */ function() { console.log(this); z(x => console.log(x, this)); });', + + '/**\n * @returns {void}\n * @this Obj\n */\nfunction foo() { console.log(this); z(x => console.log(x, this)); }', + + 'Ctor = function() { console.log(this); z(x => console.log(x, this)); }', + + 'function foo(Ctor = function() { console.log(this); z(x => console.log(x, this)); }) {}', + + '[obj.method = function() { console.log(this); z(x => console.log(x, this)); }] = a', + + // Static + + 'class A {static foo() { console.log(this); z(x => console.log(x, this)); }};', + ], + + invalid: [ + { + code: ` + interface SomeType { prop: string } + function foo() { + this.prop; + }`, + errors: [error], + }, + // Global. + { + code: 'console.log(this); z(x => console.log(x, this));', + + errors: [error, error], + }, + { + code: 'console.log(this); z(x => console.log(x, this));', + parserOptions: { + ecmaFeatures: { globalReturn: true }, + }, + errors: [error, error], + }, + + // IIFE. + { + code: + '(function() { console.log(this); z(x => console.log(x, this)); })();', + + errors: [error, error], + }, + + // Just functions. + { + code: + 'function foo() { console.log(this); z(x => console.log(x, this)); }', + + errors: [error, error], + }, + { + code: + 'function foo() { console.log(this); z(x => console.log(x, this)); }', + + options: [{ capIsConstructor: false }], // test that the option doesn't reverse the logic and mistakenly allows lowercase functions + errors: [error, error], + }, + { + code: + 'function Foo() { console.log(this); z(x => console.log(x, this)); }', + + options: [{ capIsConstructor: false }], + errors: [error, error], + }, + { + code: + 'function foo() { "use strict"; console.log(this); z(x => console.log(x, this)); }', + + errors: [error, error], + }, + { + code: + 'function Foo() { "use strict"; console.log(this); z(x => console.log(x, this)); }', + + options: [{ capIsConstructor: false }], + errors: [error, error], + }, + { + code: + 'return function() { console.log(this); z(x => console.log(x, this)); };', + parserOptions: { + ecmaFeatures: { globalReturn: true }, + }, + errors: [error, error], + }, + { + code: + 'var foo = (function() { console.log(this); z(x => console.log(x, this)); }).bar(obj);', + + errors: [error, error], + }, + + // Functions in methods. + { + code: + 'var obj = {foo: function() { function foo() { console.log(this); z(x => console.log(x, this)); } foo(); }};', + + errors: [error, error], + }, + { + code: + 'var obj = {foo() { function foo() { console.log(this); z(x => console.log(x, this)); } foo(); }};', + + errors: [error, error], + }, + { + code: + 'var obj = {foo: function() { return function() { console.log(this); z(x => console.log(x, this)); }; }};', + + errors: [error, error], + }, + { + code: + 'var obj = {foo: function() { "use strict"; return function() { console.log(this); z(x => console.log(x, this)); }; }};', + + errors: [error, error], + }, + { + code: + 'obj.foo = function() { return function() { console.log(this); z(x => console.log(x, this)); }; };', + + errors: [error, error], + }, + { + code: + 'obj.foo = function() { "use strict"; return function() { console.log(this); z(x => console.log(x, this)); }; };', + + errors: [error, error], + }, + { + code: + 'class A { foo() { return function() { console.log(this); z(x => console.log(x, this)); }; } }', + + errors: [error, error], + }, + + // Class Static methods. + + { + code: + 'obj.foo = (function() { return () => { console.log(this); z(x => console.log(x, this)); }; })();', + + errors: [error, error], + }, + { + code: + 'obj.foo = (() => () => { console.log(this); z(x => console.log(x, this)); })();', + + errors: [error, error], + }, + // Bind/Call/Apply + + { + code: + 'var foo = function() { console.log(this); z(x => console.log(x, this)); }.bind(null);', + + errors: [error, error], + }, + + { + code: + '(function() { console.log(this); z(x => console.log(x, this)); }).call(undefined);', + + errors: [error, error], + }, + + { + code: + '(function() { console.log(this); z(x => console.log(x, this)); }).apply(void 0);', + + errors: [error, error], + }, + + // Array methods. + { + code: + 'Array.from([], function() { console.log(this); z(x => console.log(x, this)); });', + + errors: [error, error], + }, + { + code: + 'foo.every(function() { console.log(this); z(x => console.log(x, this)); });', + + errors: [error, error], + }, + { + code: + 'foo.filter(function() { console.log(this); z(x => console.log(x, this)); });', + + errors: [error, error], + }, + { + code: + 'foo.find(function() { console.log(this); z(x => console.log(x, this)); });', + + errors: [error, error], + }, + { + code: + 'foo.findIndex(function() { console.log(this); z(x => console.log(x, this)); });', + + errors: [error, error], + }, + { + code: + 'foo.forEach(function() { console.log(this); z(x => console.log(x, this)); });', + + errors: [error, error], + }, + { + code: + 'foo.map(function() { console.log(this); z(x => console.log(x, this)); });', + + errors: [error, error], + }, + { + code: + 'foo.some(function() { console.log(this); z(x => console.log(x, this)); });', + + errors: [error, error], + }, + + { + code: + 'foo.forEach(function() { console.log(this); z(x => console.log(x, this)); }, null);', + + errors: [error, error], + }, + + // @this tag. + + { + code: + '/** @returns {void} */ function foo() { console.log(this); z(x => console.log(x, this)); }', + + errors: [error, error], + }, + { + code: + '/** @this Obj */ foo(function() { console.log(this); z(x => console.log(x, this)); });', + + errors: [error, error], + }, + + // https://github.com/eslint/eslint/issues/3254 + { + code: + 'function foo() { console.log(this); z(x => console.log(x, this)); }', + + errors: [error, error], + }, + + { + code: + 'var Ctor = function() { console.log(this); z(x => console.log(x, this)); }', + + options: [{ capIsConstructor: false }], + errors: [error, error], + }, + { + code: + 'var func = function() { console.log(this); z(x => console.log(x, this)); }', + + errors: [error, error], + }, + { + code: + 'var func = function() { console.log(this); z(x => console.log(x, this)); }', + + options: [{ capIsConstructor: false }], + errors: [error, error], + }, + + { + code: + 'Ctor = function() { console.log(this); z(x => console.log(x, this)); }', + + options: [{ capIsConstructor: false }], + errors: [error, error], + }, + { + code: + 'func = function() { console.log(this); z(x => console.log(x, this)); }', + + errors: [error, error], + }, + { + code: + 'func = function() { console.log(this); z(x => console.log(x, this)); }', + + options: [{ capIsConstructor: false }], + errors: [error, error], + }, + + { + code: + 'function foo(func = function() { console.log(this); z(x => console.log(x, this)); }) {}', + + errors: [error, error], + }, + + { + code: + '[func = function() { console.log(this); z(x => console.log(x, this)); }] = a', + + errors: [error, error], + }, + ], +}); diff --git a/packages/eslint-plugin/typings/eslint-rules.d.ts b/packages/eslint-plugin/typings/eslint-rules.d.ts index eb2d1cd9c60..b91f4407cdf 100644 --- a/packages/eslint-plugin/typings/eslint-rules.d.ts +++ b/packages/eslint-plugin/typings/eslint-rules.d.ts @@ -640,3 +640,22 @@ declare module 'eslint/lib/rules/init-declarations' { >; export = rule; } + +declare module 'eslint/lib/rules/no-invalid-this' { + import { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils'; + + const rule: TSESLint.RuleModule< + 'unexpectedThis', + [{ capIsConstructor?: boolean }?], + { + Program(node: TSESTree.Program): void; + 'Program:exit'(node: TSESTree.Program): void; + FunctionDeclaration(node: TSESTree.FunctionDeclaration): void; + 'FunctionDeclaration:exit'(node: TSESTree.FunctionDeclaration): void; + FunctionExpression(node: TSESTree.FunctionExpression): void; + 'FunctionExpression:exit'(node: TSESTree.FunctionExpression): void; + ThisExpression(node: TSESTree.ThisExpression): void; + } + >; + export = rule; +} From 43b2f4f3a29f3e7a4f6d6e2ef086a76d088174d7 Mon Sep 17 00:00:00 2001 From: Anix Date: Wed, 1 Apr 2020 17:15:55 +0000 Subject: [PATCH 2/8] chore: type refactoring and formatting --- packages/eslint-plugin/typings/eslint-rules.d.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/eslint-plugin/typings/eslint-rules.d.ts b/packages/eslint-plugin/typings/eslint-rules.d.ts index b91f4407cdf..761923aae52 100644 --- a/packages/eslint-plugin/typings/eslint-rules.d.ts +++ b/packages/eslint-plugin/typings/eslint-rules.d.ts @@ -646,7 +646,11 @@ declare module 'eslint/lib/rules/no-invalid-this' { const rule: TSESLint.RuleModule< 'unexpectedThis', - [{ capIsConstructor?: boolean }?], + [ + { + capIsConstructor?: boolean; + }?, + ], { Program(node: TSESTree.Program): void; 'Program:exit'(node: TSESTree.Program): void; From fd1f83778ff33e2a9ea2c97cff1134f711e564a8 Mon Sep 17 00:00:00 2001 From: Anix Date: Thu, 2 Apr 2020 08:15:51 +0000 Subject: [PATCH 3/8] chore: typecheck fixes --- .../src/rules/no-invalid-this.ts | 4 +- .../tests/rules/no-invalid-this.test.ts | 389 +++++++++++++++--- 2 files changed, 343 insertions(+), 50 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-invalid-this.ts b/packages/eslint-plugin/src/rules/no-invalid-this.ts index d192931b72c..83fee8232f6 100644 --- a/packages/eslint-plugin/src/rules/no-invalid-this.ts +++ b/packages/eslint-plugin/src/rules/no-invalid-this.ts @@ -47,7 +47,7 @@ export default createRule({ ...rules, FunctionDeclaration(node: TSESTree.FunctionDeclaration): void { const names = node?.params.map( - (param: TSESTree.Parameter) => param?.name, + (param: TSESTree.Identifier) => param?.name, ); argList.push(names); // baseRule's work @@ -60,7 +60,7 @@ export default createRule({ }, FunctionExpression(node: TSESTree.FunctionExpression): void { const names = node?.params.map( - (param: TSESTree.Parameter) => param?.name, + (param: TSESTree.Identifier) => param.name, ); argList.push(names); // baseRule's work 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 0070fefb1be..42a681d119b 100644 --- a/packages/eslint-plugin/tests/rules/no-invalid-this.test.ts +++ b/packages/eslint-plugin/tests/rules/no-invalid-this.test.ts @@ -1,4 +1,3 @@ -import { AST_NODE_TYPES } from '@typescript-eslint/experimental-utils'; import rule from '../../src/rules/no-invalid-this'; import { RuleTester, getFixturesRootDir } from '../RuleTester'; @@ -13,10 +12,6 @@ const ruleTester = new RuleTester({ }, }); -const error = { - messageId: 'unexpectedThis', -}; - ruleTester.run('no-invalid-this', rule, { valid: [ `describe('foo', () => { @@ -172,20 +167,38 @@ ruleTester.run('no-invalid-this', rule, { function foo() { this.prop; }`, - errors: [error], + errors: [ + { + messageId: 'unexpectedThis', + }, + ], }, // Global. { code: 'console.log(this); z(x => console.log(x, this));', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: 'console.log(this); z(x => console.log(x, this));', parserOptions: { ecmaFeatures: { globalReturn: true }, }, - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, // IIFE. @@ -193,7 +206,14 @@ ruleTester.run('no-invalid-this', rule, { code: '(function() { console.log(this); z(x => console.log(x, this)); })();', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, // Just functions. @@ -201,34 +221,69 @@ ruleTester.run('no-invalid-this', rule, { code: 'function foo() { console.log(this); z(x => console.log(x, this)); }', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: 'function foo() { console.log(this); z(x => console.log(x, this)); }', options: [{ capIsConstructor: false }], // test that the option doesn't reverse the logic and mistakenly allows lowercase functions - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: 'function Foo() { console.log(this); z(x => console.log(x, this)); }', options: [{ capIsConstructor: false }], - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: 'function foo() { "use strict"; console.log(this); z(x => console.log(x, this)); }', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: 'function Foo() { "use strict"; console.log(this); z(x => console.log(x, this)); }', options: [{ capIsConstructor: false }], - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: @@ -236,13 +291,27 @@ ruleTester.run('no-invalid-this', rule, { parserOptions: { ecmaFeatures: { globalReturn: true }, }, - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: 'var foo = (function() { console.log(this); z(x => console.log(x, this)); }).bar(obj);', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, // Functions in methods. @@ -250,43 +319,92 @@ ruleTester.run('no-invalid-this', rule, { code: 'var obj = {foo: function() { function foo() { console.log(this); z(x => console.log(x, this)); } foo(); }};', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: 'var obj = {foo() { function foo() { console.log(this); z(x => console.log(x, this)); } foo(); }};', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: 'var obj = {foo: function() { return function() { console.log(this); z(x => console.log(x, this)); }; }};', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: 'var obj = {foo: function() { "use strict"; return function() { console.log(this); z(x => console.log(x, this)); }; }};', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: 'obj.foo = function() { return function() { console.log(this); z(x => console.log(x, this)); }; };', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: 'obj.foo = function() { "use strict"; return function() { console.log(this); z(x => console.log(x, this)); }; };', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: 'class A { foo() { return function() { console.log(this); z(x => console.log(x, this)); }; } }', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, // Class Static methods. @@ -295,13 +413,27 @@ ruleTester.run('no-invalid-this', rule, { code: 'obj.foo = (function() { return () => { console.log(this); z(x => console.log(x, this)); }; })();', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: 'obj.foo = (() => () => { console.log(this); z(x => console.log(x, this)); })();', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, // Bind/Call/Apply @@ -309,21 +441,42 @@ ruleTester.run('no-invalid-this', rule, { code: 'var foo = function() { console.log(this); z(x => console.log(x, this)); }.bind(null);', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: '(function() { console.log(this); z(x => console.log(x, this)); }).call(undefined);', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: '(function() { console.log(this); z(x => console.log(x, this)); }).apply(void 0);', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, // Array methods. @@ -331,56 +484,119 @@ ruleTester.run('no-invalid-this', rule, { code: 'Array.from([], function() { console.log(this); z(x => console.log(x, this)); });', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: 'foo.every(function() { console.log(this); z(x => console.log(x, this)); });', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: 'foo.filter(function() { console.log(this); z(x => console.log(x, this)); });', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: 'foo.find(function() { console.log(this); z(x => console.log(x, this)); });', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: 'foo.findIndex(function() { console.log(this); z(x => console.log(x, this)); });', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: 'foo.forEach(function() { console.log(this); z(x => console.log(x, this)); });', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: 'foo.map(function() { console.log(this); z(x => console.log(x, this)); });', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: 'foo.some(function() { console.log(this); z(x => console.log(x, this)); });', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: 'foo.forEach(function() { console.log(this); z(x => console.log(x, this)); }, null);', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, // @this tag. @@ -389,13 +605,27 @@ ruleTester.run('no-invalid-this', rule, { code: '/** @returns {void} */ function foo() { console.log(this); z(x => console.log(x, this)); }', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: '/** @this Obj */ foo(function() { console.log(this); z(x => console.log(x, this)); });', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, // https://github.com/eslint/eslint/issues/3254 @@ -403,7 +633,14 @@ ruleTester.run('no-invalid-this', rule, { code: 'function foo() { console.log(this); z(x => console.log(x, this)); }', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { @@ -411,20 +648,41 @@ ruleTester.run('no-invalid-this', rule, { 'var Ctor = function() { console.log(this); z(x => console.log(x, this)); }', options: [{ capIsConstructor: false }], - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: 'var func = function() { console.log(this); z(x => console.log(x, this)); }', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: 'var func = function() { console.log(this); z(x => console.log(x, this)); }', options: [{ capIsConstructor: false }], - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { @@ -432,34 +690,69 @@ ruleTester.run('no-invalid-this', rule, { 'Ctor = function() { console.log(this); z(x => console.log(x, this)); }', options: [{ capIsConstructor: false }], - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: 'func = function() { console.log(this); z(x => console.log(x, this)); }', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: 'func = function() { console.log(this); z(x => console.log(x, this)); }', options: [{ capIsConstructor: false }], - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: 'function foo(func = function() { console.log(this); z(x => console.log(x, this)); }) {}', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, { code: '[func = function() { console.log(this); z(x => console.log(x, this)); }] = a', - errors: [error, error], + errors: [ + { + messageId: 'unexpectedThis', + }, + { + messageId: 'unexpectedThis', + }, + ], }, ], }); From 85b650b3c1d3140a17d4ff9a7d95553e8e85c5b3 Mon Sep 17 00:00:00 2001 From: Anix Date: Mon, 27 Apr 2020 11:20:21 +0000 Subject: [PATCH 4/8] chore: suggestion applied --- .../docs/rules/no-invalid-this.md | 2 +- .../src/rules/no-invalid-this.ts | 44 +- .../tests/rules/no-invalid-this.test.ts | 764 ++++++++++++++---- 3 files changed, 616 insertions(+), 194 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/no-invalid-this.md b/packages/eslint-plugin/docs/rules/no-invalid-this.md index 34e5fb8e875..ac9dc30122c 100644 --- a/packages/eslint-plugin/docs/rules/no-invalid-this.md +++ b/packages/eslint-plugin/docs/rules/no-invalid-this.md @@ -3,7 +3,7 @@ ## Rule Details This rule extends the base [`eslint/no-invalid-this`](https://eslint.org/docs/rules/no-invalid-this) rule. -It supports all options and features of the base rule. +It adds support for TypeScript's `this` parameters. ## How to use diff --git a/packages/eslint-plugin/src/rules/no-invalid-this.ts b/packages/eslint-plugin/src/rules/no-invalid-this.ts index 83fee8232f6..3aaddf6c865 100644 --- a/packages/eslint-plugin/src/rules/no-invalid-this.ts +++ b/packages/eslint-plugin/src/rules/no-invalid-this.ts @@ -1,29 +1,17 @@ -import { TSESTree } from '@typescript-eslint/experimental-utils'; +import { + TSESTree, + AST_NODE_TYPES, +} from '@typescript-eslint/experimental-utils'; import baseRule from 'eslint/lib/rules/no-invalid-this'; import { InferOptionsTypeFromRule, InferMessageIdsTypeFromRule, createRule, - deepMerge, } from '../util'; export type Options = InferOptionsTypeFromRule; export type MessageIds = InferMessageIdsTypeFromRule; -const schema = deepMerge( - Array.isArray(baseRule.meta.schema) - ? baseRule.meta.schema[0] - : baseRule.meta.schema, - { - properties: { - capIsConstructor: { - type: 'boolean', - default: true, - }, - }, - }, -); - export default createRule({ name: 'no-invalid-this', meta: { @@ -36,20 +24,22 @@ export default createRule({ extendsBaseRule: true, }, messages: baseRule.meta.messages, - schema: [schema], + schema: baseRule.meta.schema, }, defaultOptions: [{ capIsConstructor: true }], create(context) { const rules = baseRule.create(context); - let argList: Array = []; + const argList: Array = []; return { ...rules, FunctionDeclaration(node: TSESTree.FunctionDeclaration): void { - const names = node?.params.map( - (param: TSESTree.Identifier) => param?.name, + argList.push( + node?.params.some( + (param: TSESTree.Identifier) => + param.type === AST_NODE_TYPES.Identifier && param.name === 'this', + ), ); - argList.push(names); // baseRule's work rules.FunctionDeclaration(node); }, @@ -59,10 +49,12 @@ export default createRule({ rules['FunctionDeclaration:exit'](node); }, FunctionExpression(node: TSESTree.FunctionExpression): void { - const names = node?.params.map( - (param: TSESTree.Identifier) => param.name, + argList.push( + node?.params.some( + (param: TSESTree.Identifier) => + param.type === AST_NODE_TYPES.Identifier && param.name === 'this', + ), ); - argList.push(names); // baseRule's work rules.FunctionExpression(node); }, @@ -71,10 +63,10 @@ export default createRule({ // baseRule's work rules['FunctionExpression:exit'](node); }, - ThisExpression(node: TSESTree.ThisExpression) { + ThisExpression(node: TSESTree.ThisExpression): void { const lastFnArg = argList[argList.length - 1]; - if (lastFnArg?.some((name: string) => name === 'this')) { + if (lastFnArg) { return; } 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 42a681d119b..8bb7f3f9396 100644 --- a/packages/eslint-plugin/tests/rules/no-invalid-this.test.ts +++ b/packages/eslint-plugin/tests/rules/no-invalid-this.test.ts @@ -14,159 +14,406 @@ const ruleTester = new RuleTester({ ruleTester.run('no-invalid-this', rule, { valid: [ - `describe('foo', () => { - it('does something', function(this: Mocha.Context) { - this.timeout(100); - // done - }); - });`, ` - interface SomeType { prop: string } +describe('foo', () => { + it('does something', function(this: Mocha.Context) { + this.timeout(100); + // done + }); +}); + `, + ` + interface SomeType { + prop: string; + } function foo(this: SomeType) { this.prop; - }`, - `function foo(this: prop){ - this.propMethod() - }`, - ' z(function(x,this: context ) { console.log(x, this) });', + } + `, + ` +function foo(this: prop) { + this.propMethod(); +} + `, + ` +z(function(x, this: context) { + console.log(x, this); +}); + `, // https://github.com/eslint/eslint/issues/3287 - 'function foo() { /** @this Obj*/ return function bar() { console.log(this); z(x => console.log(x, this)); }; }', + ` +function foo() { + /** @this Obj*/ return function bar() { + console.log(this); + z(x => console.log(x, this)); + }; +} + `, // https://github.com/eslint/eslint/issues/6824 - 'var Ctor = function() { console.log(this); z(x => console.log(x, this)); }', + ` +var Ctor = function() { + console.log(this); + z(x => console.log(x, this)); +}; + `, // Constructors. { - code: - 'function Foo() { console.log(this); z(x => console.log(x, this)); }', + code: ` +function Foo() { + console.log(this); + z(x => console.log(x, this)); +} + `, }, { - code: - 'function Foo() { console.log(this); z(x => console.log(x, this)); }', + code: ` +function Foo() { + console.log(this); + z(x => console.log(x, this)); +} + `, options: [{}], // test the default value in schema }, { - code: - 'function Foo() { console.log(this); z(x => console.log(x, this)); }', + code: ` +function Foo() { + console.log(this); + z(x => console.log(x, this)); +} + `, options: [{ capIsConstructor: true }], // test explicitly set option to the default value }, { - code: - 'var Foo = function Foo() { console.log(this); z(x => console.log(x, this)); };', + code: ` +var Foo = function Foo() { + console.log(this); + z(x => console.log(x, this)); +}; + `, }, { - code: - 'class A {constructor() { console.log(this); z(x => console.log(x, this)); }};', + code: ` +class A { + constructor() { + console.log(this); + z(x => console.log(x, this)); + } +} + `, }, // On a property. { - code: - 'var obj = {foo: function() { console.log(this); z(x => console.log(x, this)); }};', + code: ` +var obj = { + foo: function() { + console.log(this); + z(x => console.log(x, this)); + }, +}; + `, }, { - code: - 'var obj = {foo() { console.log(this); z(x => console.log(x, this)); }};', + code: ` +var obj = { + foo() { + console.log(this); + z(x => console.log(x, this)); + }, +}; + `, }, { - code: - 'var obj = {foo: foo || function() { console.log(this); z(x => console.log(x, this)); }};', + code: ` +var obj = { + foo: + foo || + function() { + console.log(this); + z(x => console.log(x, this)); + }, +}; + `, }, { - code: - 'var obj = {foo: hasNative ? foo : function() { console.log(this); z(x => console.log(x, this)); }};', + code: ` +var obj = { + foo: hasNative + ? foo + : function() { + console.log(this); + z(x => console.log(x, this)); + }, +}; + `, }, { - code: - 'var obj = {foo: (function() { return function() { console.log(this); z(x => console.log(x, this)); }; })()};', + code: ` +var obj = { + foo: (function() { + return function() { + console.log(this); + z(x => console.log(x, this)); + }; + })(), +}; + `, }, { - code: - 'Object.defineProperty(obj, "foo", {value: function() { console.log(this); z(x => console.log(x, this)); }})', + code: ` +Object.defineProperty(obj, 'foo', { + value: function() { + console.log(this); + z(x => console.log(x, this)); + }, +}); + `, }, { - code: - 'Object.defineProperties(obj, {foo: {value: function() { console.log(this); z(x => console.log(x, this)); }}})', + code: ` +Object.defineProperties(obj, { + foo: { + value: function() { + console.log(this); + z(x => console.log(x, this)); + }, + }, +}); + `, }, // Assigns to a property. { - code: - 'obj.foo = function() { console.log(this); z(x => console.log(x, this)); };', + code: ` +obj.foo = function() { + console.log(this); + z(x => console.log(x, this)); +}; + `, }, { - code: - 'obj.foo = foo || function() { console.log(this); z(x => console.log(x, this)); };', + code: ` +obj.foo = + foo || + function() { + console.log(this); + z(x => console.log(x, this)); + }; + `, }, { - code: - 'obj.foo = foo ? bar : function() { console.log(this); z(x => console.log(x, this)); };', + code: ` +obj.foo = foo + ? bar + : function() { + console.log(this); + z(x => console.log(x, this)); + }; + `, }, { - code: - 'obj.foo = (function() { return function() { console.log(this); z(x => console.log(x, this)); }; })();', + code: ` +obj.foo = (function() { + return function() { + console.log(this); + z(x => console.log(x, this)); + }; +})(); + `, }, { - code: - 'obj.foo = (() => function() { console.log(this); z(x => console.log(x, this)); })();', + code: ` +obj.foo = (() => + function() { + console.log(this); + z(x => console.log(x, this)); + })(); + `, }, // Bind/Call/Apply - '(function() { console.log(this); z(x => console.log(x, this)); }).call(obj);', - 'var foo = function() { console.log(this); z(x => console.log(x, this)); }.bind(obj);', - 'Reflect.apply(function() { console.log(this); z(x => console.log(x, this)); }, obj, []);', - '(function() { console.log(this); z(x => console.log(x, this)); }).apply(obj);', + ` +(function() { + console.log(this); + z(x => console.log(x, this)); +}.call(obj)); + `, + ` +var foo = function() { + console.log(this); + z(x => console.log(x, this)); +}.bind(obj); + `, + ` +Reflect.apply( + function() { + console.log(this); + z(x => console.log(x, this)); + }, + obj, + [], +); + `, + ` +(function() { + console.log(this); + z(x => console.log(x, this)); +}.apply(obj)); + `, // Class Instance Methods. - 'class A {foo() { console.log(this); z(x => console.log(x, this)); }};', + ` +class A { + foo() { + console.log(this); + z(x => console.log(x, this)); + } +} + `, // Array methods. - 'Array.from([], function() { console.log(this); z(x => console.log(x, this)); }, obj);', + ` +Array.from( + [], + function() { + console.log(this); + z(x => console.log(x, this)); + }, + obj, +); + `, - 'foo.every(function() { console.log(this); z(x => console.log(x, this)); }, obj);', + ` +foo.every(function() { + console.log(this); + z(x => console.log(x, this)); +}, obj); + `, - 'foo.filter(function() { console.log(this); z(x => console.log(x, this)); }, obj);', + ` +foo.filter(function() { + console.log(this); + z(x => console.log(x, this)); +}, obj); + `, - 'foo.find(function() { console.log(this); z(x => console.log(x, this)); }, obj);', + ` +foo.find(function() { + console.log(this); + z(x => console.log(x, this)); +}, obj); + `, - 'foo.findIndex(function() { console.log(this); z(x => console.log(x, this)); }, obj);', + ` +foo.findIndex(function() { + console.log(this); + z(x => console.log(x, this)); +}, obj); + `, - 'foo.forEach(function() { console.log(this); z(x => console.log(x, this)); }, obj);', + ` +foo.forEach(function() { + console.log(this); + z(x => console.log(x, this)); +}, obj); + `, - 'foo.map(function() { console.log(this); z(x => console.log(x, this)); }, obj);', + ` +foo.map(function() { + console.log(this); + z(x => console.log(x, this)); +}, obj); + `, - 'foo.some(function() { console.log(this); z(x => console.log(x, this)); }, obj);', + ` +foo.some(function() { + console.log(this); + z(x => console.log(x, this)); +}, obj); + `, // @this tag. - '/** @this Obj */ function foo() { console.log(this); z(x => console.log(x, this)); }', + ` +/** @this Obj */ function foo() { + console.log(this); + z(x => console.log(x, this)); +} + `, - 'foo(/* @this Obj */ function() { console.log(this); z(x => console.log(x, this)); });', + ` +foo( + /* @this Obj */ function() { + console.log(this); + z(x => console.log(x, this)); + }, +); + `, - '/**\n * @returns {void}\n * @this Obj\n */\nfunction foo() { console.log(this); z(x => console.log(x, this)); }', + ` +/** + * @returns {void} + * @this Obj + */ +function foo() { + console.log(this); + z(x => console.log(x, this)); +} + `, - 'Ctor = function() { console.log(this); z(x => console.log(x, this)); }', + ` +Ctor = function() { + console.log(this); + z(x => console.log(x, this)); +}; + `, - 'function foo(Ctor = function() { console.log(this); z(x => console.log(x, this)); }) {}', + ` +function foo( + Ctor = function() { + console.log(this); + z(x => console.log(x, this)); + }, +) {} + `, - '[obj.method = function() { console.log(this); z(x => console.log(x, this)); }] = a', + ` +[ + obj.method = function() { + console.log(this); + z(x => console.log(x, this)); + }, +] = a; + `, // Static - 'class A {static foo() { console.log(this); z(x => console.log(x, this)); }};', + ` +class A { + static foo() { + console.log(this); + z(x => console.log(x, this)); + } +} + `, ], invalid: [ { code: ` - interface SomeType { prop: string } - function foo() { - this.prop; - }`, +interface SomeType { + prop: string; +} +function foo() { + this.prop; +} + `, errors: [ { messageId: 'unexpectedThis', @@ -175,7 +422,10 @@ ruleTester.run('no-invalid-this', rule, { }, // Global. { - code: 'console.log(this); z(x => console.log(x, this));', + code: ` +console.log(this); +z(x => console.log(x, this)); + `, errors: [ { @@ -187,7 +437,10 @@ ruleTester.run('no-invalid-this', rule, { ], }, { - code: 'console.log(this); z(x => console.log(x, this));', + code: ` +console.log(this); +z(x => console.log(x, this)); + `, parserOptions: { ecmaFeatures: { globalReturn: true }, }, @@ -203,8 +456,12 @@ ruleTester.run('no-invalid-this', rule, { // IIFE. { - code: - '(function() { console.log(this); z(x => console.log(x, this)); })();', + code: ` +(function() { + console.log(this); + z(x => console.log(x, this)); +})(); + `, errors: [ { @@ -218,8 +475,12 @@ ruleTester.run('no-invalid-this', rule, { // Just functions. { - code: - 'function foo() { console.log(this); z(x => console.log(x, this)); }', + code: ` +function foo() { + console.log(this); + z(x => console.log(x, this)); +} + `, errors: [ { @@ -231,8 +492,12 @@ ruleTester.run('no-invalid-this', rule, { ], }, { - code: - 'function foo() { console.log(this); z(x => console.log(x, this)); }', + code: ` +function foo() { + console.log(this); + z(x => console.log(x, this)); +} + `, options: [{ capIsConstructor: false }], // test that the option doesn't reverse the logic and mistakenly allows lowercase functions errors: [ @@ -245,8 +510,12 @@ ruleTester.run('no-invalid-this', rule, { ], }, { - code: - 'function Foo() { console.log(this); z(x => console.log(x, this)); }', + code: ` +function Foo() { + console.log(this); + z(x => console.log(x, this)); +} + `, options: [{ capIsConstructor: false }], errors: [ @@ -259,8 +528,13 @@ ruleTester.run('no-invalid-this', rule, { ], }, { - code: - 'function foo() { "use strict"; console.log(this); z(x => console.log(x, this)); }', + code: ` +function foo() { + 'use strict'; + console.log(this); + z(x => console.log(x, this)); +} + `, errors: [ { @@ -272,8 +546,13 @@ ruleTester.run('no-invalid-this', rule, { ], }, { - code: - 'function Foo() { "use strict"; console.log(this); z(x => console.log(x, this)); }', + code: ` +function Foo() { + 'use strict'; + console.log(this); + z(x => console.log(x, this)); +} + `, options: [{ capIsConstructor: false }], errors: [ @@ -286,8 +565,12 @@ ruleTester.run('no-invalid-this', rule, { ], }, { - code: - 'return function() { console.log(this); z(x => console.log(x, this)); };', + code: ` +return function() { + console.log(this); + z(x => console.log(x, this)); +}; + `, parserOptions: { ecmaFeatures: { globalReturn: true }, }, @@ -301,8 +584,12 @@ ruleTester.run('no-invalid-this', rule, { ], }, { - code: - 'var foo = (function() { console.log(this); z(x => console.log(x, this)); }).bar(obj);', + code: ` +var foo = function() { + console.log(this); + z(x => console.log(x, this)); +}.bar(obj); + `, errors: [ { @@ -316,8 +603,17 @@ ruleTester.run('no-invalid-this', rule, { // Functions in methods. { - code: - 'var obj = {foo: function() { function foo() { console.log(this); z(x => console.log(x, this)); } foo(); }};', + code: ` +var obj = { + foo: function() { + function foo() { + console.log(this); + z(x => console.log(x, this)); + } + foo(); + }, +}; + `, errors: [ { @@ -329,8 +625,17 @@ ruleTester.run('no-invalid-this', rule, { ], }, { - code: - 'var obj = {foo() { function foo() { console.log(this); z(x => console.log(x, this)); } foo(); }};', + code: ` +var obj = { + foo() { + function foo() { + console.log(this); + z(x => console.log(x, this)); + } + foo(); + }, +}; + `, errors: [ { @@ -342,8 +647,16 @@ ruleTester.run('no-invalid-this', rule, { ], }, { - code: - 'var obj = {foo: function() { return function() { console.log(this); z(x => console.log(x, this)); }; }};', + code: ` +var obj = { + foo: function() { + return function() { + console.log(this); + z(x => console.log(x, this)); + }; + }, +}; + `, errors: [ { @@ -355,8 +668,17 @@ ruleTester.run('no-invalid-this', rule, { ], }, { - code: - 'var obj = {foo: function() { "use strict"; return function() { console.log(this); z(x => console.log(x, this)); }; }};', + code: ` +var obj = { + foo: function() { + 'use strict'; + return function() { + console.log(this); + z(x => console.log(x, this)); + }; + }, +}; + `, errors: [ { @@ -368,8 +690,14 @@ ruleTester.run('no-invalid-this', rule, { ], }, { - code: - 'obj.foo = function() { return function() { console.log(this); z(x => console.log(x, this)); }; };', + code: ` +obj.foo = function() { + return function() { + console.log(this); + z(x => console.log(x, this)); + }; +}; + `, errors: [ { @@ -381,8 +709,15 @@ ruleTester.run('no-invalid-this', rule, { ], }, { - code: - 'obj.foo = function() { "use strict"; return function() { console.log(this); z(x => console.log(x, this)); }; };', + code: ` +obj.foo = function() { + 'use strict'; + return function() { + console.log(this); + z(x => console.log(x, this)); + }; +}; + `, errors: [ { @@ -394,8 +729,16 @@ ruleTester.run('no-invalid-this', rule, { ], }, { - code: - 'class A { foo() { return function() { console.log(this); z(x => console.log(x, this)); }; } }', + code: ` +class A { + foo() { + return function() { + console.log(this); + z(x => console.log(x, this)); + }; + } +} + `, errors: [ { @@ -410,8 +753,14 @@ ruleTester.run('no-invalid-this', rule, { // Class Static methods. { - code: - 'obj.foo = (function() { return () => { console.log(this); z(x => console.log(x, this)); }; })();', + code: ` +obj.foo = (function() { + return () => { + console.log(this); + z(x => console.log(x, this)); + }; +})(); + `, errors: [ { @@ -423,8 +772,12 @@ ruleTester.run('no-invalid-this', rule, { ], }, { - code: - 'obj.foo = (() => () => { console.log(this); z(x => console.log(x, this)); })();', + code: ` +obj.foo = (() => () => { + console.log(this); + z(x => console.log(x, this)); +})(); + `, errors: [ { @@ -438,8 +791,12 @@ ruleTester.run('no-invalid-this', rule, { // Bind/Call/Apply { - code: - 'var foo = function() { console.log(this); z(x => console.log(x, this)); }.bind(null);', + code: ` +var foo = function() { + console.log(this); + z(x => console.log(x, this)); +}.bind(null); + `, errors: [ { @@ -452,8 +809,12 @@ ruleTester.run('no-invalid-this', rule, { }, { - code: - '(function() { console.log(this); z(x => console.log(x, this)); }).call(undefined);', + code: ` +(function() { + console.log(this); + z(x => console.log(x, this)); +}.call(undefined)); + `, errors: [ { @@ -466,8 +827,12 @@ ruleTester.run('no-invalid-this', rule, { }, { - code: - '(function() { console.log(this); z(x => console.log(x, this)); }).apply(void 0);', + code: ` +(function() { + console.log(this); + z(x => console.log(x, this)); +}.apply(void 0)); + `, errors: [ { @@ -481,8 +846,12 @@ ruleTester.run('no-invalid-this', rule, { // Array methods. { - code: - 'Array.from([], function() { console.log(this); z(x => console.log(x, this)); });', + code: ` +Array.from([], function() { + console.log(this); + z(x => console.log(x, this)); +}); + `, errors: [ { @@ -494,8 +863,12 @@ ruleTester.run('no-invalid-this', rule, { ], }, { - code: - 'foo.every(function() { console.log(this); z(x => console.log(x, this)); });', + code: ` +foo.every(function() { + console.log(this); + z(x => console.log(x, this)); +}); + `, errors: [ { @@ -507,8 +880,12 @@ ruleTester.run('no-invalid-this', rule, { ], }, { - code: - 'foo.filter(function() { console.log(this); z(x => console.log(x, this)); });', + code: ` +foo.filter(function() { + console.log(this); + z(x => console.log(x, this)); +}); + `, errors: [ { @@ -520,8 +897,12 @@ ruleTester.run('no-invalid-this', rule, { ], }, { - code: - 'foo.find(function() { console.log(this); z(x => console.log(x, this)); });', + code: ` +foo.find(function() { + console.log(this); + z(x => console.log(x, this)); +}); + `, errors: [ { @@ -533,8 +914,12 @@ ruleTester.run('no-invalid-this', rule, { ], }, { - code: - 'foo.findIndex(function() { console.log(this); z(x => console.log(x, this)); });', + code: ` +foo.findIndex(function() { + console.log(this); + z(x => console.log(x, this)); +}); + `, errors: [ { @@ -546,8 +931,12 @@ ruleTester.run('no-invalid-this', rule, { ], }, { - code: - 'foo.forEach(function() { console.log(this); z(x => console.log(x, this)); });', + code: ` +foo.forEach(function() { + console.log(this); + z(x => console.log(x, this)); +}); + `, errors: [ { @@ -559,8 +948,12 @@ ruleTester.run('no-invalid-this', rule, { ], }, { - code: - 'foo.map(function() { console.log(this); z(x => console.log(x, this)); });', + code: ` +foo.map(function() { + console.log(this); + z(x => console.log(x, this)); +}); + `, errors: [ { @@ -572,8 +965,12 @@ ruleTester.run('no-invalid-this', rule, { ], }, { - code: - 'foo.some(function() { console.log(this); z(x => console.log(x, this)); });', + code: ` +foo.some(function() { + console.log(this); + z(x => console.log(x, this)); +}); + `, errors: [ { @@ -586,8 +983,12 @@ ruleTester.run('no-invalid-this', rule, { }, { - code: - 'foo.forEach(function() { console.log(this); z(x => console.log(x, this)); }, null);', + code: ` +foo.forEach(function() { + console.log(this); + z(x => console.log(x, this)); +}, null); + `, errors: [ { @@ -602,21 +1003,12 @@ ruleTester.run('no-invalid-this', rule, { // @this tag. { - code: - '/** @returns {void} */ function foo() { console.log(this); z(x => console.log(x, this)); }', - - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], - }, - { - code: - '/** @this Obj */ foo(function() { console.log(this); z(x => console.log(x, this)); });', + code: ` +/** @returns {void} */ function foo() { + console.log(this); + z(x => console.log(x, this)); +} + `, errors: [ { @@ -627,11 +1019,13 @@ ruleTester.run('no-invalid-this', rule, { }, ], }, - - // https://github.com/eslint/eslint/issues/3254 { - code: - 'function foo() { console.log(this); z(x => console.log(x, this)); }', + code: ` +/** @this Obj */ foo(function() { + console.log(this); + z(x => console.log(x, this)); +}); + `, errors: [ { @@ -644,8 +1038,12 @@ ruleTester.run('no-invalid-this', rule, { }, { - code: - 'var Ctor = function() { console.log(this); z(x => console.log(x, this)); }', + code: ` +var Ctor = function() { + console.log(this); + z(x => console.log(x, this)); +}; + `, options: [{ capIsConstructor: false }], errors: [ @@ -658,8 +1056,12 @@ ruleTester.run('no-invalid-this', rule, { ], }, { - code: - 'var func = function() { console.log(this); z(x => console.log(x, this)); }', + code: ` +var func = function() { + console.log(this); + z(x => console.log(x, this)); +}; + `, errors: [ { @@ -671,8 +1073,12 @@ ruleTester.run('no-invalid-this', rule, { ], }, { - code: - 'var func = function() { console.log(this); z(x => console.log(x, this)); }', + code: ` +var func = function() { + console.log(this); + z(x => console.log(x, this)); +}; + `, options: [{ capIsConstructor: false }], errors: [ @@ -686,8 +1092,12 @@ ruleTester.run('no-invalid-this', rule, { }, { - code: - 'Ctor = function() { console.log(this); z(x => console.log(x, this)); }', + code: ` +Ctor = function() { + console.log(this); + z(x => console.log(x, this)); +}; + `, options: [{ capIsConstructor: false }], errors: [ @@ -700,8 +1110,12 @@ ruleTester.run('no-invalid-this', rule, { ], }, { - code: - 'func = function() { console.log(this); z(x => console.log(x, this)); }', + code: ` +func = function() { + console.log(this); + z(x => console.log(x, this)); +}; + `, errors: [ { @@ -713,8 +1127,12 @@ ruleTester.run('no-invalid-this', rule, { ], }, { - code: - 'func = function() { console.log(this); z(x => console.log(x, this)); }', + code: ` +func = function() { + console.log(this); + z(x => console.log(x, this)); +}; + `, options: [{ capIsConstructor: false }], errors: [ @@ -728,8 +1146,14 @@ ruleTester.run('no-invalid-this', rule, { }, { - code: - 'function foo(func = function() { console.log(this); z(x => console.log(x, this)); }) {}', + code: ` +function foo( + func = function() { + console.log(this); + z(x => console.log(x, this)); + }, +) {} + `, errors: [ { @@ -742,8 +1166,14 @@ ruleTester.run('no-invalid-this', rule, { }, { - code: - '[func = function() { console.log(this); z(x => console.log(x, this)); }] = a', + code: ` +[ + func = function() { + console.log(this); + z(x => console.log(x, this)); + }, +] = a; + `, errors: [ { From 291173436a4411059b348c34912dc976b8672e0a Mon Sep 17 00:00:00 2001 From: Anix Date: Tue, 28 Apr 2020 00:08:02 +0530 Subject: [PATCH 5/8] chore: apply suggestions from code review Co-Authored-By: Brad Zacher --- packages/eslint-plugin/src/rules/no-invalid-this.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-invalid-this.ts b/packages/eslint-plugin/src/rules/no-invalid-this.ts index 3aaddf6c865..7a89cb22d5a 100644 --- a/packages/eslint-plugin/src/rules/no-invalid-this.ts +++ b/packages/eslint-plugin/src/rules/no-invalid-this.ts @@ -35,7 +35,7 @@ export default createRule({ ...rules, FunctionDeclaration(node: TSESTree.FunctionDeclaration): void { argList.push( - node?.params.some( + node.params.some( (param: TSESTree.Identifier) => param.type === AST_NODE_TYPES.Identifier && param.name === 'this', ), @@ -50,7 +50,7 @@ export default createRule({ }, FunctionExpression(node: TSESTree.FunctionExpression): void { argList.push( - node?.params.some( + node.params.some( (param: TSESTree.Identifier) => param.type === AST_NODE_TYPES.Identifier && param.name === 'this', ), @@ -66,7 +66,7 @@ export default createRule({ ThisExpression(node: TSESTree.ThisExpression): void { const lastFnArg = argList[argList.length - 1]; - if (lastFnArg) { + if (lastFnArg.length > 0) { return; } From 69c6558049f2131053179f640ed53af318edc441 Mon Sep 17 00:00:00 2001 From: Anix Date: Wed, 29 Apr 2020 05:36:35 +0000 Subject: [PATCH 6/8] chore: typefixes and arglist type change --- packages/eslint-plugin/src/rules/no-invalid-this.ts | 8 ++++---- .../eslint-plugin/tests/rules/no-invalid-this.test.ts | 6 +----- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-invalid-this.ts b/packages/eslint-plugin/src/rules/no-invalid-this.ts index 7a89cb22d5a..ddd55ef85ac 100644 --- a/packages/eslint-plugin/src/rules/no-invalid-this.ts +++ b/packages/eslint-plugin/src/rules/no-invalid-this.ts @@ -29,14 +29,14 @@ export default createRule({ defaultOptions: [{ capIsConstructor: true }], create(context) { const rules = baseRule.create(context); - const argList: Array = []; + const argList: boolean[] = []; return { ...rules, FunctionDeclaration(node: TSESTree.FunctionDeclaration): void { argList.push( node.params.some( - (param: TSESTree.Identifier) => + param => param.type === AST_NODE_TYPES.Identifier && param.name === 'this', ), ); @@ -51,7 +51,7 @@ export default createRule({ FunctionExpression(node: TSESTree.FunctionExpression): void { argList.push( node.params.some( - (param: TSESTree.Identifier) => + param => param.type === AST_NODE_TYPES.Identifier && param.name === 'this', ), ); @@ -66,7 +66,7 @@ export default createRule({ ThisExpression(node: TSESTree.ThisExpression): void { const lastFnArg = argList[argList.length - 1]; - if (lastFnArg.length > 0) { + if (lastFnArg) { return; } 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 4d6d259a3f0..5a4808e7222 100644 --- a/packages/eslint-plugin/tests/rules/no-invalid-this.test.ts +++ b/packages/eslint-plugin/tests/rules/no-invalid-this.test.ts @@ -1,14 +1,10 @@ import rule from '../../src/rules/no-invalid-this'; -import { RuleTester, getFixturesRootDir } from '../RuleTester'; - -const rootPath = getFixturesRootDir(); +import { RuleTester } from '../RuleTester'; const ruleTester = new RuleTester({ parser: '@typescript-eslint/parser', parserOptions: { sourceType: 'module', - tsconfigRootDir: rootPath, - project: './tsconfig.json', }, }); From 03d0e3bc7f83eb95103ddd3fcdc3156184fdd133 Mon Sep 17 00:00:00 2001 From: Anix Date: Fri, 1 May 2020 13:37:49 +0000 Subject: [PATCH 7/8] chore: fix typecheck --- .../src/rules/no-invalid-this.ts | 2 +- .../tests/rules/no-invalid-this.test.ts | 380 +++--------------- .../eslint-plugin/typings/eslint-rules.d.ts | 2 +- 3 files changed, 49 insertions(+), 335 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-invalid-this.ts b/packages/eslint-plugin/src/rules/no-invalid-this.ts index ddd55ef85ac..186d3378846 100644 --- a/packages/eslint-plugin/src/rules/no-invalid-this.ts +++ b/packages/eslint-plugin/src/rules/no-invalid-this.ts @@ -5,8 +5,8 @@ import { import baseRule from 'eslint/lib/rules/no-invalid-this'; import { InferOptionsTypeFromRule, - InferMessageIdsTypeFromRule, createRule, + InferMessageIdsTypeFromRule, } from '../util'; export type Options = InferOptionsTypeFromRule; 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 5a4808e7222..b04f6f135e1 100644 --- a/packages/eslint-plugin/tests/rules/no-invalid-this.test.ts +++ b/packages/eslint-plugin/tests/rules/no-invalid-this.test.ts @@ -8,6 +8,11 @@ const ruleTester = new RuleTester({ }, }); +const errors: any = [ + { message: "Unexpected 'this'." }, + { message: "Unexpected 'this'." }, +]; + ruleTester.run('no-invalid-this', rule, { valid: [ ` @@ -410,11 +415,7 @@ function foo() { this.prop; } `, - errors: [ - { - messageId: 'unexpectedThis', - }, - ], + errors: [{ message: "Unexpected 'this'." }], }, // Global. { @@ -423,14 +424,7 @@ console.log(this); z(x => console.log(x, this)); `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { code: ` @@ -440,14 +434,7 @@ z(x => console.log(x, this)); parserOptions: { ecmaFeatures: { globalReturn: true }, }, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, // IIFE. @@ -459,14 +446,7 @@ z(x => console.log(x, this)); })(); `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, // Just functions. @@ -478,14 +458,7 @@ function foo() { } `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { code: ` @@ -496,14 +469,7 @@ function foo() { `, options: [{ capIsConstructor: false }], // test that the option doesn't reverse the logic and mistakenly allows lowercase functions - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { code: ` @@ -514,14 +480,7 @@ function Foo() { `, options: [{ capIsConstructor: false }], - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { code: ` @@ -532,14 +491,7 @@ function foo() { } `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { code: ` @@ -551,14 +503,7 @@ function Foo() { `, options: [{ capIsConstructor: false }], - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { code: ` @@ -570,14 +515,7 @@ return function() { parserOptions: { ecmaFeatures: { globalReturn: true }, }, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { code: ` @@ -587,14 +525,7 @@ var foo = function() { }.bar(obj); `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, // Functions in methods. @@ -611,14 +542,7 @@ var obj = { }; `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { code: ` @@ -633,14 +557,7 @@ var obj = { }; `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { code: ` @@ -654,14 +571,7 @@ var obj = { }; `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { code: ` @@ -676,14 +586,7 @@ var obj = { }; `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { code: ` @@ -695,14 +598,7 @@ obj.foo = function() { }; `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { code: ` @@ -715,14 +611,7 @@ obj.foo = function() { }; `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { code: ` @@ -736,14 +625,7 @@ class A { } `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, // Class Static methods. @@ -758,14 +640,7 @@ obj.foo = (function() { })(); `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { code: ` @@ -775,14 +650,7 @@ obj.foo = (() => () => { })(); `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, // Bind/Call/Apply @@ -794,14 +662,7 @@ var foo = function() { }.bind(null); `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { @@ -812,14 +673,7 @@ var foo = function() { }.call(undefined)); `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { @@ -830,14 +684,7 @@ var foo = function() { }.apply(void 0)); `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, // Array methods. @@ -849,14 +696,7 @@ Array.from([], function() { }); `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { code: ` @@ -866,14 +706,7 @@ foo.every(function() { }); `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { code: ` @@ -883,14 +716,7 @@ foo.filter(function() { }); `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { code: ` @@ -900,14 +726,7 @@ foo.find(function() { }); `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { code: ` @@ -917,14 +736,7 @@ foo.findIndex(function() { }); `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { code: ` @@ -934,14 +746,7 @@ foo.forEach(function() { }); `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { code: ` @@ -951,14 +756,7 @@ foo.map(function() { }); `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { code: ` @@ -968,14 +766,7 @@ foo.some(function() { }); `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { @@ -986,14 +777,7 @@ foo.forEach(function() { }, null); `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, // @this tag. @@ -1006,14 +790,7 @@ foo.forEach(function() { } `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { code: ` @@ -1023,14 +800,7 @@ foo.forEach(function() { }); `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { @@ -1042,14 +812,7 @@ var Ctor = function() { `, options: [{ capIsConstructor: false }], - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { code: ` @@ -1059,14 +822,7 @@ var func = function() { }; `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { code: ` @@ -1077,14 +833,7 @@ var func = function() { `, options: [{ capIsConstructor: false }], - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { @@ -1096,14 +845,7 @@ Ctor = function() { `, options: [{ capIsConstructor: false }], - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { code: ` @@ -1113,14 +855,7 @@ func = function() { }; `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { code: ` @@ -1131,14 +866,7 @@ func = function() { `, options: [{ capIsConstructor: false }], - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { @@ -1151,14 +879,7 @@ function foo( ) {} `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, { @@ -1171,14 +892,7 @@ function foo( ] = a; `, - errors: [ - { - messageId: 'unexpectedThis', - }, - { - messageId: 'unexpectedThis', - }, - ], + errors, }, ], }); diff --git a/packages/eslint-plugin/typings/eslint-rules.d.ts b/packages/eslint-plugin/typings/eslint-rules.d.ts index 49b37bab9b7..b4ec293e4f5 100644 --- a/packages/eslint-plugin/typings/eslint-rules.d.ts +++ b/packages/eslint-plugin/typings/eslint-rules.d.ts @@ -645,7 +645,7 @@ declare module 'eslint/lib/rules/no-invalid-this' { import { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils'; const rule: TSESLint.RuleModule< - 'unexpectedThis', + never, [ { capIsConstructor?: boolean; From 37fb4d29109cfa8993d9ec5c77ad965c3477fb48 Mon Sep 17 00:00:00 2001 From: Anix Date: Fri, 1 May 2020 14:24:51 +0000 Subject: [PATCH 8/8] chore: linting fix --- packages/eslint-plugin/tests/rules/no-invalid-this.test.ts | 1 + 1 file changed, 1 insertion(+) 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 b04f6f135e1..93701a2dc32 100644 --- a/packages/eslint-plugin/tests/rules/no-invalid-this.test.ts +++ b/packages/eslint-plugin/tests/rules/no-invalid-this.test.ts @@ -8,6 +8,7 @@ const ruleTester = new RuleTester({ }, }); +// eslint-disable-next-line @typescript-eslint/no-explicit-any const errors: any = [ { message: "Unexpected 'this'." }, { message: "Unexpected 'this'." },