diff --git a/lib/rules/no-this-in-sfc.js b/lib/rules/no-this-in-sfc.js index 3883a36d69..8d715e7bae 100644 --- a/lib/rules/no-this-in-sfc.js +++ b/lib/rules/no-this-in-sfc.js @@ -29,11 +29,11 @@ module.exports = { create: Components.detect((context, components, utils) => ({ MemberExpression(node) { - const component = components.get(utils.getParentStatelessComponent()); - if (!component) { - return; - } if (node.object.type === 'ThisExpression') { + const component = components.get(utils.getParentStatelessComponent()); + if (!component) { + return; + } context.report({ node: node, message: ERROR_MESSAGE diff --git a/lib/util/Components.js b/lib/util/Components.js index 5961eaae60..8ed7bbd2c3 100644 --- a/lib/util/Components.js +++ b/lib/util/Components.js @@ -469,7 +469,13 @@ function componentRule(rule, context) { const node = scope.block; const isClass = node.type === 'ClassExpression'; const isFunction = /Function/.test(node.type); // Functions - const isMethod = node.parent && node.parent.type === 'MethodDefinition'; // Classes methods + const isArrowFunction = node.type === 'ArrowFunctionExpression'; + let functionScope = scope; + if (isArrowFunction) { + functionScope = utils.getParentFunctionScope(scope); + } + const methodNode = functionScope && functionScope.block.parent; + const isMethod = methodNode && methodNode.type === 'MethodDefinition'; // Classes methods const isArgument = node.parent && node.parent.type === 'CallExpression'; // Arguments (callback, etc.) // Attribute Expressions inside JSX Elements () const isJSXExpressionContainer = node.parent && node.parent.type === 'JSXExpressionContainer'; @@ -486,6 +492,23 @@ function componentRule(rule, context) { return null; }, + /** + * Get a parent scope created by a FunctionExpression or FunctionDeclaration + * @param {Scope} scope The child scope + * @returns {Scope} A parent function scope + */ + getParentFunctionScope(scope) { + scope = scope.upper; + while (scope) { + const type = scope.block.type; + if (type === 'FunctionExpression' || type === 'FunctionDeclaration') { + return scope; + } + scope = scope.upper; + } + return null; + }, + /** * Get the related component from a node * diff --git a/tests/lib/rules/no-this-in-sfc.js b/tests/lib/rules/no-this-in-sfc.js index 026b44dc1a..63a849f840 100644 --- a/tests/lib/rules/no-this-in-sfc.js +++ b/tests/lib/rules/no-this-in-sfc.js @@ -99,6 +99,26 @@ ruleTester.run('no-this-in-sfc', rule, { code: 'const Foo = (props) => props.foo ? {props.bar} : null;' }, { code: 'const Foo = ({ foo, bar }) => foo ? {bar} : null;' + }, { + code: ` + class Foo { + bar() { + () => { + this.something(); + return null; + }; + } + }` + }, { + code: ` + class Foo { + bar() { + () => () => { + this.something(); + return null; + }; + } + }` }], invalid: [{ code: ` @@ -165,5 +185,25 @@ ruleTester.run('no-this-in-sfc', rule, { return
{this.props.foo}
; }`, errors: [{message: ERROR_MESSAGE}, {message: ERROR_MESSAGE}] + }, { + code: ` + () => { + this.something(); + return null; + }`, + errors: [{message: ERROR_MESSAGE}] + }, { + code: ` + class Foo { + bar() { + function Bar(){ + return () => { + this.something(); + return null; + } + } + } + }`, + errors: [{message: ERROR_MESSAGE}] }] });