in src/utils/resolveToValue.ts [120:229]
export default function resolveToValue(
path: NodePath,
importer: Importer,
): NodePath {
const node = path.node;
if (t.VariableDeclarator.check(node)) {
if (node.init) {
return resolveToValue(path.get('init'), importer);
}
} else if (t.MemberExpression.check(node)) {
const root = getMemberExpressionRoot(path);
const resolved = resolveToValue(root, importer);
if (t.ObjectExpression.check(resolved.node)) {
let propertyPath: NodePath | null = resolved;
for (const propertyName of toArray(path, importer).slice(1)) {
if (propertyPath && t.ObjectExpression.check(propertyPath.node)) {
propertyPath = getPropertyValuePath(
propertyPath,
propertyName,
importer,
);
}
if (!propertyPath) {
return path;
}
propertyPath = resolveToValue(propertyPath, importer);
}
return propertyPath;
} else if (isSupportedDefinitionType(resolved)) {
const memberPath = getMemberValuePath(
resolved,
path.node.property.name,
importer,
);
if (memberPath) {
return resolveToValue(memberPath, importer);
}
} else if (
t.ImportDeclaration.check(resolved.node) &&
resolved.node.specifiers
) {
// Handle references to namespace imports, e.g. import * as foo from 'bar'.
// Try to find a specifier that matches the root of the member expression, and
// find the export that matches the property name.
for (const specifier of resolved.node.specifiers) {
if (
t.ImportNamespaceSpecifier.check(specifier) &&
specifier.local &&
specifier.local.name === root.node.name
) {
const resolvedPath = importer(
resolved,
root.parentPath.node.property.name,
);
if (resolvedPath) {
return resolveToValue(resolvedPath, importer);
}
}
}
}
} else if (
t.ImportDefaultSpecifier.check(node) ||
t.ImportNamespaceSpecifier.check(node) ||
t.ImportSpecifier.check(node)
) {
// go up two levels as first level is only the array of specifiers
return path.parentPath.parentPath;
} else if (t.AssignmentExpression.check(node)) {
if (node.operator === '=') {
return resolveToValue(path.get('right'), importer);
}
} else if (
t.TypeCastExpression.check(node) ||
t.TSAsExpression.check(node) ||
t.TSTypeAssertion.check(node)
) {
return resolveToValue(path.get('expression'), importer);
} else if (t.Identifier.check(node)) {
if (
(t.ClassDeclaration.check(path.parentPath.node) ||
t.ClassExpression.check(path.parentPath.node) ||
t.Function.check(path.parentPath.node)) &&
path.parentPath.get('id') === path
) {
return path.parentPath;
}
let scope: Scope = path.scope.lookup(node.name);
let resolvedPath: NodePath | null = null;
if (scope) {
// The variable may be assigned a different value after initialization.
// We are first trying to find all assignments to the variable in the
// block where it is defined (i.e. we are not traversing into statements)
resolvedPath = findLastAssignedValue(scope, path, importer);
if (!resolvedPath) {
const bindings = scope.getBindings()[node.name];
resolvedPath = findScopePath(bindings, path, importer);
}
} else {
scope = path.scope.lookupType(node.name);
if (scope) {
const typesInScope = scope.getTypes()[node.name];
resolvedPath = findScopePath(typesInScope, path, importer);
}
}
return resolvedPath || path;
}
return path;
}