documentation
Version:
a documentation generator
101 lines (93 loc) • 2.8 kB
JavaScript
import pathParse from 'parse-filepath';
import t from '@babel/types';
/**
* Infers a `name` tag from the context.
*
* @name inferName
* @param {Object} comment parsed comment
* @returns {Object} comment with name inferred
*/
export default function inferName(comment) {
if (comment.name) {
return comment;
}
if (comment.alias) {
comment.name = comment.alias;
return comment;
}
if (comment.kind === 'module') {
comment.name = pathParse(comment.context.file).name;
return comment;
}
function inferName(path, node) {
if (node && node.name) {
comment.name = node.name;
return true;
}
if (node && node.type === 'StringLiteral' && node.value) {
comment.name = node.value;
return true;
}
}
const path = comment.context.ast;
if (path) {
if (path.type === 'ExportDefaultDeclaration') {
if (t.isDeclaration(path.node.declaration) && path.node.declaration.id) {
comment.name = path.node.declaration.id.name;
} else {
comment.name = pathParse(comment.context.file).name;
}
return comment;
}
// The strategy here is to do a depth-first traversal of the AST,
// looking for nodes with a "name" property, with exceptions as needed.
// For example, name inference for a MemberExpression `foo.bar = baz` will
// infer the named based on the `property` of the MemberExpression (`bar`)
// rather than the `object` (`foo`).
path.traverse({
/**
* Attempt to extract the name from an Identifier node.
* If the name can be resolved, it will stop traversing.
* @param {Object} path ast path
* @returns {undefined} has side-effects
* @private
*/
Identifier(path) {
if (inferName(path, path.node)) {
path.stop();
}
},
/**
* Attempt to extract the name from a string literal that is the `key`
* part of an ObjectProperty node. If the name can be resolved, it
* will stop traversing.
* @param {Object} path ast path
* @returns {undefined} has side-effects
* @private
*/
StringLiteral(path) {
if (
path.parent.type === 'ObjectProperty' &&
path.node === path.parent.key
) {
if (inferName(path, path.node)) {
path.stop();
}
}
},
/**
* Attempt to extract the name from an Identifier node.
* If the name can be resolved, it will stop traversing.
* @param {Object} path ast path
* @returns {undefined} has side-effects
* @private
*/
MemberExpression(path) {
if (inferName(path, path.node.property)) {
path.stop();
}
}
});
}
return comment;
}