in src/utils/isStatelessComponent.ts [32:143]
function resolvesToJSXElementOrReactCall(
path: NodePath,
importer: Importer,
seen: WeakSet<NodePath>,
): boolean {
// avoid returns with recursive function calls
if (seen.has(path)) {
return false;
}
seen.add(path);
// Is the path is already a JSX element or a call to one of the React.* functions
if (isJSXElementOrReactCall(path, importer)) {
return true;
}
const resolvedPath = resolveToValue(path, importer);
// If the path points to a conditional expression, then we need to look only at
// the two possible paths
if (resolvedPath.node.type === 'ConditionalExpression') {
return (
resolvesToJSXElementOrReactCall(
resolvedPath.get('consequent'),
importer,
seen,
) ||
resolvesToJSXElementOrReactCall(
resolvedPath.get('alternate'),
importer,
seen,
)
);
}
// If the path points to a logical expression (AND, OR, ...), then we need to look only at
// the two possible paths
if (resolvedPath.node.type === 'LogicalExpression') {
return (
resolvesToJSXElementOrReactCall(
resolvedPath.get('left'),
importer,
seen,
) ||
resolvesToJSXElementOrReactCall(resolvedPath.get('right'), importer, seen)
);
}
// Is the resolved path is already a JSX element or a call to one of the React.* functions
// Only do this if the resolvedPath actually resolved something as otherwise we did this check already
if (
resolvedPath !== path &&
isJSXElementOrReactCall(resolvedPath, importer)
) {
return true;
}
// If we have a call expression, lets try to follow it
if (resolvedPath.node.type === 'CallExpression') {
let calleeValue = resolveToValue(resolvedPath.get('callee'), importer);
if (returnsJSXElementOrReactCall(calleeValue, importer, seen)) {
return true;
}
let resolvedValue;
const namesToResolve = [calleeValue.get('property')];
if (calleeValue.node.type === 'MemberExpression') {
if (calleeValue.get('object').node.type === 'Identifier') {
resolvedValue = resolveToValue(calleeValue.get('object'), importer);
} else if (t.MemberExpression.check(calleeValue.node)) {
do {
calleeValue = calleeValue.get('object');
namesToResolve.unshift(calleeValue.get('property'));
} while (t.MemberExpression.check(calleeValue.node));
resolvedValue = resolveToValue(calleeValue.get('object'), importer);
}
}
if (resolvedValue && t.ObjectExpression.check(resolvedValue.node)) {
const resolvedMemberExpression = namesToResolve.reduce(
(result, nodePath) => {
if (!nodePath) {
return result;
}
if (result) {
result = getPropertyValuePath(result, nodePath.node.name, importer);
if (result && t.Identifier.check(result.node)) {
return resolveToValue(result, importer);
}
}
return result;
},
resolvedValue,
);
if (
!resolvedMemberExpression ||
returnsJSXElementOrReactCall(resolvedMemberExpression, importer, seen)
) {
return true;
}
}
}
return false;
}