/
isReactComponentClass.js
81 lines (71 loc) · 2.19 KB
/
isReactComponentClass.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
import types from 'ast-types';
import isReactModuleName from './isReactModuleName';
import match from './match';
import resolveToModule from './resolveToModule';
import resolveToValue from './resolveToValue';
const { namedTypes: t } = types;
function isRenderMethod(node) {
const isProperty = node.type === 'ClassProperty';
return (
(t.MethodDefinition.check(node) || isProperty) &&
!node.computed &&
!node.static &&
(node.kind === '' || node.kind === 'method' || isProperty) &&
node.key.name === 'render'
);
}
/**
* Returns `true` of the path represents a class definition which either extends
* `React.Component` or has a superclass and implements a `render()` method.
*/
export default function isReactComponentClass(path: NodePath): boolean {
const node = path.node;
if (!t.ClassDeclaration.check(node) && !t.ClassExpression.check(node)) {
return false;
}
// extends something
if (!node.superClass) {
return false;
}
// React.Component or React.PureComponent
const superClass = resolveToValue(path.get('superClass'));
if (
match(superClass.node, { property: { name: 'Component' } }) ||
match(superClass.node, { property: { name: 'PureComponent' } })
) {
const module = resolveToModule(superClass);
if (module && isReactModuleName(module)) {
return true;
}
}
// render method
if (node.body.body.some(isRenderMethod)) {
return true;
}
// check for @extends React.Component in docblock
if (path.parentPath && path.parentPath.value) {
const classDeclaration = Array.isArray(path.parentPath.value)
? path.parentPath.value.find(function(declaration) {
return declaration.type === 'ClassDeclaration';
})
: path.parentPath.value;
if (
classDeclaration &&
classDeclaration.leadingComments &&
classDeclaration.leadingComments.some(function(comment) {
return /@extends\s+React\.Component/.test(comment.value);
})
) {
return true;
}
}
return false;
}