Skip to content

Commit 8cbbe4d

Browse files
gausieyannickcr
authored andcommitted
Add support for explicit declaration that class extends React.Component (fixes jsx-eslint#68)
1 parent 2a04fd4 commit 8cbbe4d

File tree

3 files changed

+49
-0
lines changed

3 files changed

+49
-0
lines changed

lib/util/Components.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
'use strict';
66

77
var util = require('util');
8+
var doctrine = require('doctrine');
89
var variableUtil = require('./variable');
910
var pragmaUtil = require('./pragma');
1011

@@ -160,12 +161,41 @@ function componentRule(rule, context) {
160161
* @returns {Boolean} True if the node is a React ES6 component, false if not
161162
*/
162163
isES6Component: function(node) {
164+
if (utils.isExplicitComponent(node)) {
165+
return true;
166+
}
167+
163168
if (!node.superClass) {
164169
return false;
165170
}
166171
return new RegExp('^(' + pragma + '\\.)?Component$').test(sourceCode.getText(node.superClass));
167172
},
168173

174+
/**
175+
* Check if the node is explicitly declared as a descendant of a React Component
176+
*
177+
* @param {ASTNode} node The AST node being checked (can be a ReturnStatement or an ArrowFunctionExpression).
178+
* @returns {Boolean} True if the node is explicitly declared as a descendant of a React Component, false if not
179+
*/
180+
isExplicitComponent: function(node) {
181+
var comment = sourceCode.getJSDocComment(node);
182+
183+
if (comment === null) {
184+
return false;
185+
}
186+
187+
var commentAst = doctrine.parse(comment.value, {
188+
unwrap: true,
189+
tags: ['extends', 'augments']
190+
});
191+
192+
var relevantTags = commentAst.tags.filter(function(tag) {
193+
return tag.name === 'React.Component';
194+
});
195+
196+
return relevantTags.length > 0;
197+
},
198+
169199
/**
170200
* Check if the node is returning JSX
171201
*

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
},
2323
"homepage": "https://github.com/yannickcr/eslint-plugin-react",
2424
"bugs": "https://github.com/yannickcr/eslint-plugin-react/issues",
25+
"dependencies": {
26+
"doctrine": "^1.2.0"
27+
},
2528
"devDependencies": {
2629
"babel-eslint": "6.0.4",
2730
"coveralls": "2.11.9",

tests/lib/rules/prop-types.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1274,6 +1274,22 @@ ruleTester.run('prop-types', rule, {
12741274
column: 35,
12751275
type: 'Identifier'
12761276
}]
1277+
}, {
1278+
code: [
1279+
'/** @extends React.Component */',
1280+
'class Hello extends ChildComponent {',
1281+
' render() {',
1282+
' return <div>Hello {this.props.name}</div>;',
1283+
' }',
1284+
'}'
1285+
].join('\n'),
1286+
parserOptions: parserOptions,
1287+
errors: [{
1288+
message: '\'name\' is missing in props validation',
1289+
line: 4,
1290+
column: 35,
1291+
type: 'Identifier'
1292+
}]
12771293
}, {
12781294
code: [
12791295
'class Hello extends React.Component {',

0 commit comments

Comments
 (0)