/
findAllComponentDefinitions.js
77 lines (67 loc) · 2.35 KB
/
findAllComponentDefinitions.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
/**
* 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 isReactComponentClass from '../utils/isReactComponentClass';
import isReactCreateClassCall from '../utils/isReactCreateClassCall';
import isReactForwardRefCall from '../utils/isReactForwardRefCall';
import isStatelessComponent from '../utils/isStatelessComponent';
import normalizeClassDefinition from '../utils/normalizeClassDefinition';
import resolveToValue from '../utils/resolveToValue';
const { visit, namedTypes: t } = types;
/**
* Given an AST, this function tries to find all object expressions that are
* passed to `React.createClass` calls, by resolving all references properly.
*/
export default function findAllReactCreateClassCalls(
ast: ASTNode,
): Array<NodePath> {
const definitions = new Set();
function classVisitor(path) {
if (isReactComponentClass(path)) {
normalizeClassDefinition(path);
definitions.add(path);
}
return false;
}
function statelessVisitor(path) {
if (isStatelessComponent(path)) {
definitions.add(path);
}
return false;
}
visit(ast, {
visitFunctionDeclaration: statelessVisitor,
visitFunctionExpression: statelessVisitor,
visitArrowFunctionExpression: statelessVisitor,
visitClassExpression: classVisitor,
visitClassDeclaration: classVisitor,
visitCallExpression: function(path) {
if (isReactForwardRefCall(path)) {
// If the the inner function was previously identified as a component
// replace it with the parent node
const inner = resolveToValue(path.get('arguments', 0));
definitions.delete(inner);
definitions.add(path);
// Do not traverse into arguments
return false;
} else if (isReactCreateClassCall(path)) {
const resolvedPath = resolveToValue(path.get('arguments', 0));
if (t.ObjectExpression.check(resolvedPath.node)) {
definitions.add(resolvedPath);
}
// Do not traverse into arguments
return false;
}
// If it is neither of the above cases we need to traverse further
// as this call expression could be a HOC
this.traverse(path);
},
});
return Array.from(definitions);
}