Skip to content

Commit

Permalink
Merge pull request #1995 from sergei-startsev/fix-1960-no-this-in-sfc
Browse files Browse the repository at this point in the history
Fix `no-this-in-sfc` for class properties
  • Loading branch information
ljharb committed Sep 29, 2018
2 parents aef3ee9 + e779b00 commit b77be96
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 16 deletions.
24 changes: 10 additions & 14 deletions lib/util/Components.js
Expand Up @@ -457,15 +457,12 @@ function componentRule(rule, context) {
let scope = context.getScope();
while (scope) {
const node = scope.block;
const isClass = node.type === 'ClassExpression';
const isFunction = /Function/.test(node.type); // Functions
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 isArrowFunction = astUtil.isArrowFunction(node);
const enclosingScope = isArrowFunction ? utils.getArrowFunctionScope(scope) : scope;
const enclosingScopeParent = enclosingScope && enclosingScope.block.parent;
const isClass = enclosingScope && astUtil.isClass(enclosingScope.block);
const isMethod = enclosingScopeParent && enclosingScopeParent.type === 'MethodDefinition'; // Classes methods
const isArgument = node.parent && node.parent.type === 'CallExpression'; // Arguments (callback, etc.)
// Attribute Expressions inside JSX Elements (<button onClick={() => props.handleClick()}></button>)
const isJSXExpressionContainer = node.parent && node.parent.type === 'JSXExpressionContainer';
Expand All @@ -483,15 +480,14 @@ function componentRule(rule, context) {
},

/**
* Get a parent scope created by a FunctionExpression or FunctionDeclaration
* @param {Scope} scope The child scope
* @returns {Scope} A parent function scope
* Get an enclosing scope used to find `this` value by an arrow function
* @param {Scope} scope Current scope
* @returns {Scope} An enclosing scope used by an arrow function
*/
getParentFunctionScope(scope) {
getArrowFunctionScope(scope) {
scope = scope.upper;
while (scope) {
const type = scope.block.type;
if (type === 'FunctionExpression' || type === 'FunctionDeclaration') {
if (astUtil.isFunction(scope.block) || astUtil.isClass(scope.block)) {
return scope;
}
scope = scope.upper;
Expand Down
34 changes: 32 additions & 2 deletions lib/util/ast.js
Expand Up @@ -102,11 +102,41 @@ function isFunctionLikeExpression(node) {
return node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression';
}

/**
* Checks if the node is a function.
* @param {Object} context The node to check
* @return {Boolean} true if it's a function
*/
function isFunction(node) {
return node.type === 'FunctionExpression' || node.type === 'FunctionDeclaration';
}

/**
* Checks if the node is an arrow function.
* @param {Object} context The node to check
* @return {Boolean} true if it's an arrow function
*/
function isArrowFunction(node) {
return node.type === 'ArrowFunctionExpression';
}

/**
* Checks if the node is a class.
* @param {Object} context The node to check
* @return {Boolean} true if it's a class
*/
function isClass(node) {
return node.type === 'ClassDeclaration' || node.type === 'ClassExpression';
}

module.exports = {
findReturnStatement: findReturnStatement,
getPropertyName: getPropertyName,
getPropertyNameNode: getPropertyNameNode,
getComponentProperties: getComponentProperties,
isNodeFirstInLine: isNodeFirstInLine,
isFunctionLikeExpression: isFunctionLikeExpression
isArrowFunction: isArrowFunction,
isClass: isClass,
isFunction: isFunction,
isFunctionLikeExpression: isFunctionLikeExpression,
isNodeFirstInLine: isNodeFirstInLine
};
18 changes: 18 additions & 0 deletions tests/lib/rules/no-this-in-sfc.js
Expand Up @@ -119,6 +119,24 @@ ruleTester.run('no-this-in-sfc', rule, {
};
}
}`
}, {
code: `
class Foo {
bar = () => {
this.something();
return null;
};
}`,
parser: 'babel-eslint'
}, {
code: `
class Foo {
bar = () => () => {
this.something();
return null;
};
}`,
parser: 'babel-eslint'
}],
invalid: [{
code: `
Expand Down

0 comments on commit b77be96

Please sign in to comment.