@webex/jsdoctrinetest
Version:
120 lines (104 loc) • 2.85 kB
JavaScript
/*!
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
*/
import fs from 'fs';
import traverse from '@babel/traverse';
import doctrine from 'doctrine';
import {isProgram} from '@babel/types';
import parse from './parse';
/**
* transform function which operates on each discovered example block
* @callback transformCallback
* @param {Object} options
* @param {ast} options.comment
* @param {string} options.name
* @param {string} options.filename
* @param {string} options.type
*/
/**
* Extracts comment blocks from the source code in the specified file
* @param {transformCallback} transform
* @param {string} filename
* @returns {Array<ast>}
*/
export default function extract(transform, filename) {
// eslint-disable-next-line no-sync
const code = fs.readFileSync(filename, {encoding: 'utf8'});
const ast = parse(code, {sourceFilename: filename});
const results = [];
let done = false;
traverse(ast, {
enter(path) {
if (path.node.leadingComments) {
path.node.leadingComments.filter(isJSDocComment).forEach((comment) => {
const result = doctrine.parse(comment.value, {
unwrap: true,
sloppy: true,
recoverable: true,
lineNumbers: true,
});
if (result.tags) {
result.tags.forEach((tag) => {
if (tag.title === 'example') {
results.push(
transform({
comment: tag.description,
name: getNodeName(path.node),
filename: path.node.loc.filename,
type: path.node.type,
})
);
}
});
}
});
}
},
Program: {
exit(path) {
if (isProgram(path)) {
if (done) {
return;
}
path.pushContainer('body', results);
done = true;
}
},
},
});
return ast;
}
/**
* Extracts the name from the specified node
* @param {Node} node
* @returns {string}
*/
function getNodeName(node) {
if (node.id) {
return node.id.name;
}
if (node.key) {
return node.key.name;
}
throw new Error('Could not find name for node');
}
/**
* Indicates if the specified comment block is a doc block
* @param {CommentBlock} comment
* @returns {Boolean}
*/
function isJSDocComment(comment) {
const asterisks = comment.value.match(/^(\*+)/);
if (comment.value.startsWith('/*') && comment.value.endsWith('*/')) {
return false;
}
// eslint-disable-next-line
return (
(comment.type === 'CommentBlock' || // estree
// eslint-disable-next-line
comment.type === `Block`) && // get-comments / traditional
// eslint-disable-next-line
asterisks &&
asterisks[1].length === 1
);
}