Skip to content

Commit a93080e

Browse files
authored
Merge pull request #1989 from sergei-startsev/fix-1967-no-this-in-sfc
Fix `no-this-in-sfc` rule behavior for arrow functions inside a class field
2 parents 60b5642 + e0d5821 commit a93080e

File tree

3 files changed

+68
-5
lines changed

3 files changed

+68
-5
lines changed

lib/rules/no-this-in-sfc.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ module.exports = {
2929

3030
create: Components.detect((context, components, utils) => ({
3131
MemberExpression(node) {
32-
const component = components.get(utils.getParentStatelessComponent());
33-
if (!component) {
34-
return;
35-
}
3632
if (node.object.type === 'ThisExpression') {
33+
const component = components.get(utils.getParentStatelessComponent());
34+
if (!component) {
35+
return;
36+
}
3737
context.report({
3838
node: node,
3939
message: ERROR_MESSAGE

lib/util/Components.js

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,13 @@ function componentRule(rule, context) {
469469
const node = scope.block;
470470
const isClass = node.type === 'ClassExpression';
471471
const isFunction = /Function/.test(node.type); // Functions
472-
const isMethod = node.parent && node.parent.type === 'MethodDefinition'; // Classes methods
472+
const isArrowFunction = node.type === 'ArrowFunctionExpression';
473+
let functionScope = scope;
474+
if (isArrowFunction) {
475+
functionScope = utils.getParentFunctionScope(scope);
476+
}
477+
const methodNode = functionScope && functionScope.block.parent;
478+
const isMethod = methodNode && methodNode.type === 'MethodDefinition'; // Classes methods
473479
const isArgument = node.parent && node.parent.type === 'CallExpression'; // Arguments (callback, etc.)
474480
// Attribute Expressions inside JSX Elements (<button onClick={() => props.handleClick()}></button>)
475481
const isJSXExpressionContainer = node.parent && node.parent.type === 'JSXExpressionContainer';
@@ -486,6 +492,23 @@ function componentRule(rule, context) {
486492
return null;
487493
},
488494

495+
/**
496+
* Get a parent scope created by a FunctionExpression or FunctionDeclaration
497+
* @param {Scope} scope The child scope
498+
* @returns {Scope} A parent function scope
499+
*/
500+
getParentFunctionScope(scope) {
501+
scope = scope.upper;
502+
while (scope) {
503+
const type = scope.block.type;
504+
if (type === 'FunctionExpression' || type === 'FunctionDeclaration') {
505+
return scope;
506+
}
507+
scope = scope.upper;
508+
}
509+
return null;
510+
},
511+
489512
/**
490513
* Get the related component from a node
491514
*

tests/lib/rules/no-this-in-sfc.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,26 @@ ruleTester.run('no-this-in-sfc', rule, {
9999
code: 'const Foo = (props) => props.foo ? <span>{props.bar}</span> : null;'
100100
}, {
101101
code: 'const Foo = ({ foo, bar }) => foo ? <span>{bar}</span> : null;'
102+
}, {
103+
code: `
104+
class Foo {
105+
bar() {
106+
() => {
107+
this.something();
108+
return null;
109+
};
110+
}
111+
}`
112+
}, {
113+
code: `
114+
class Foo {
115+
bar() {
116+
() => () => {
117+
this.something();
118+
return null;
119+
};
120+
}
121+
}`
102122
}],
103123
invalid: [{
104124
code: `
@@ -165,5 +185,25 @@ ruleTester.run('no-this-in-sfc', rule, {
165185
return <div onClick={onClick}>{this.props.foo}</div>;
166186
}`,
167187
errors: [{message: ERROR_MESSAGE}, {message: ERROR_MESSAGE}]
188+
}, {
189+
code: `
190+
() => {
191+
this.something();
192+
return null;
193+
}`,
194+
errors: [{message: ERROR_MESSAGE}]
195+
}, {
196+
code: `
197+
class Foo {
198+
bar() {
199+
function Bar(){
200+
return () => {
201+
this.something();
202+
return null;
203+
}
204+
}
205+
}
206+
}`,
207+
errors: [{message: ERROR_MESSAGE}]
168208
}]
169209
});

0 commit comments

Comments
 (0)