mirror of
https://github.com/documentationjs/documentation.git
synced 2026-01-25 14:26:29 +00:00
108 lines
3.1 KiB
JavaScript
108 lines
3.1 KiB
JavaScript
const _ = require('lodash');
|
|
|
|
const PATH_SPLIT = /(?:\[])?\./g;
|
|
|
|
function removeUnnamedTags(tags) {
|
|
return tags.filter(tag => typeof tag.name === 'string');
|
|
}
|
|
|
|
const tagDepth = tag => tag.name.split(PATH_SPLIT).length;
|
|
|
|
/**
|
|
* Nest nestable tags, like param and property, into nested
|
|
* arrays that are suitable for output.
|
|
* Okay, so we're building a tree of comments, with the tag.name
|
|
* being the indexer. We sort by depth, so that we add each
|
|
* level of the tree incrementally, and throw if we run against
|
|
* a node that doesn't have a parent.
|
|
*
|
|
* foo.abe
|
|
* foo.bar.baz
|
|
* foo.bar.a
|
|
* foo.bar[].bax
|
|
*
|
|
* foo -> .abe
|
|
* \-> .bar -> .baz
|
|
* \-> .a
|
|
* \-> [].baz
|
|
*
|
|
* @private
|
|
* @param {Array<CommentTag>} tags a list of tags
|
|
* @returns {Object} nested comment
|
|
*/
|
|
const nestTag = (
|
|
tags,
|
|
errors
|
|
// Use lodash here both for brevity and also because, unlike JavaScript's
|
|
// sort, it's stable.
|
|
) =>
|
|
_.sortBy(removeUnnamedTags(tags), tagDepth).reduce(
|
|
(memo, tag) => {
|
|
function insertTag(node, parts) {
|
|
// The 'done' case: we're at parts.length === 1,
|
|
// this is where the node should be placed. We reliably
|
|
// get to this case because the recursive method
|
|
// is always passed parts.slice(1)
|
|
if (parts.length === 1) {
|
|
Object.assign(node, {
|
|
properties: (node.properties || []).concat(tag)
|
|
});
|
|
} else {
|
|
// The recursive case: try to find the child that owns
|
|
// this tag.
|
|
const child =
|
|
node.properties &&
|
|
node.properties.find(
|
|
property => parts[0] === _.last(property.name.split(PATH_SPLIT))
|
|
);
|
|
|
|
if (!child) {
|
|
if (tag.name.match(/^(\$\d+)/)) {
|
|
errors.push({
|
|
message:
|
|
`Parent of ${
|
|
tag.name
|
|
} not found. To document a destructuring\n` +
|
|
`type, add a @param tag in its position to specify the name of the\n` +
|
|
`destructured parameter`,
|
|
commentLineNumber: tag.lineNumber
|
|
});
|
|
} else {
|
|
errors.push({
|
|
message: `Parent of ${tag.name} not found`,
|
|
commentLineNumber: tag.lineNumber
|
|
});
|
|
}
|
|
} else {
|
|
insertTag(child, parts.slice(1));
|
|
}
|
|
}
|
|
}
|
|
|
|
insertTag(memo, tag.name.split(PATH_SPLIT));
|
|
return memo;
|
|
},
|
|
{ properties: [] }
|
|
).properties;
|
|
|
|
/**
|
|
* Nests
|
|
* [parameters with properties](http://usejsdoc.org/tags-param.html#parameters-with-properties).
|
|
*
|
|
* A parameter `employee.name` will be attached to the parent parameter `employee` in
|
|
* a `properties` array.
|
|
*
|
|
* This assumes that incoming comments have been flattened.
|
|
*
|
|
* @param {Object} comment input comment
|
|
* @returns {Object} nested comment
|
|
*/
|
|
const nest = comment =>
|
|
Object.assign(comment, {
|
|
params: nestTag(comment.params, comment.errors),
|
|
properties: nestTag(comment.properties, comment.errors)
|
|
});
|
|
|
|
module.exports = nest;
|
|
module.exports.nestTag = nestTag;
|