UNPKG

documentation

Version:
93 lines (84 loc) 2.87 kB
'use strict'; 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;