src/handlers/componentDocblockHandler.ts (60 lines of code) (raw):
import { namedTypes as t } from 'ast-types';
import type Documentation from '../Documentation';
import { getDocblock } from '../utils/docblock';
import isReactForwardRefCall from '../utils/isReactForwardRefCall';
import resolveToValue from '../utils/resolveToValue';
import type { Importer } from '../parse';
import type { NodePath } from 'ast-types/lib/node-path';
function isClassDefinition(nodePath: NodePath): boolean {
const node = nodePath.node;
return t.ClassDeclaration.check(node) || t.ClassExpression.check(node);
}
function getDocblockFromComponent(
path: NodePath,
importer: Importer,
): string | null {
let description: string | null = null;
if (isClassDefinition(path)) {
// If we have a class declaration or expression, then the comment might be
// attached to the last decorator instead as trailing comment.
if (path.node.decorators && path.node.decorators.length > 0) {
description = getDocblock(
path.get('decorators', path.node.decorators.length - 1),
true,
);
}
}
if (description == null) {
// Find parent statement (e.g. var Component = React.createClass(<path>);)
let searchPath = path;
while (searchPath && !t.Statement.check(searchPath.node)) {
searchPath = searchPath.parent;
}
if (searchPath) {
// If the parent is an export statement, we have to traverse one more up
if (
t.ExportNamedDeclaration.check(searchPath.parentPath.node) ||
t.ExportDefaultDeclaration.check(searchPath.parentPath.node)
) {
searchPath = searchPath.parentPath;
}
description = getDocblock(searchPath);
}
}
if (!description) {
const searchPath = isReactForwardRefCall(path, importer)
? path.get('arguments', 0)
: path;
const inner = resolveToValue(searchPath, importer);
if (inner.node !== path.node) {
return getDocblockFromComponent(inner, importer);
}
}
return description;
}
/**
* Finds the nearest block comment before the component definition.
*/
export default function componentDocblockHandler(
documentation: Documentation,
path: NodePath,
importer: Importer,
): void {
documentation.set(
'description',
getDocblockFromComponent(path, importer) || '',
);
}