UNPKG

dgeni-packages

Version:

A collection of dgeni packages for generating documentation from source code

138 lines (114 loc) 4.22 kB
const TagCollection = require('../lib/TagCollection'); const Tag = require('../lib/Tag'); /** * @dgProcessor parseTagsProcessor * @description Parse the doc for jsdoc style tags */ module.exports = function parseTagsProcessor(log, createDocMessage, backTickParserAdapter, htmlBlockParserAdapter) { return { tagDefinitions: [], parserAdapters: [backTickParserAdapter, htmlBlockParserAdapter], $validate: { tagDefinitions: { presence: true }, }, $runAfter: ['parsing-tags'], $runBefore: ['tags-parsed'], $process(docs) { const tagParser = createTagParser(this.tagDefinitions, this.parserAdapters); docs.forEach(doc => { try { doc.tags = tagParser(doc.content || '', doc.startingLine); } catch(e) { const message = createDocMessage('Error parsing tags', doc, e); log.error(message); throw new Error(message); } }); } }; }; /** * Create a map of the tagDefinitions keyed on their name or alias * @param {Array} tagDefinitions A collection of tag definitions to map * @return {Map} [description] */ function createTagDefMap(tagDefinitions) { // Create a map of the tagDefinitions so that we can look up tagDefs based on name or alias const map = new Map(); tagDefinitions.forEach(tagDefinition => { map.set(tagDefinition.name, tagDefinition); if ( tagDefinition.aliases ) { tagDefinition.aliases.forEach(alias => map.set(alias, tagDefinition)); } }); return map; } /** * Create a new tagParser that can parse a set of jsdoc-style tags from a document * @param {Array} tagDefMap A map of tag definitions keyed on tagName/aliasName. * @param {ParserAdapter[]} A collection of adapters that modify the parsing behaviour */ function createTagParser(tagDefinitions, parserAdapters) { const END_OF_LINE = /\r?\n/; const TAG_MARKER = /^\s*@(\S+)\s*(.*)$/; const tagDefMap = createTagDefMap(tagDefinitions); /** * tagParser * @param {string} content The text to parse for tags * @param {number} startingLine The line in the doc file where this text begins * @return {TagCollection} A collection of tags that were parsed */ return function tagParser(content, startingLine) { const lines = content.split(END_OF_LINE); let lineNumber = 0; const descriptionLines = []; let current; // The current that that is being extracted const tags = new TagCollection(); // Contains all the tags that have been found init(lines, tags); // Extract the description block do { let line = lines[lineNumber]; nextLine(line, lineNumber); if (parseForTags()) { const match = TAG_MARKER.exec(line); const tagDef = match && tagDefMap.get(match[1]); if ( match && ( !tagDef || !tagDef.ignore ) ) { // Only store tags that are unknown or not ignored current = new Tag(tagDef, match[1], match[2], startingLine + lineNumber); break; } } lineNumber += 1; descriptionLines.push(line); } while(lineNumber < lines.length); tags.description = descriptionLines.join('\n'); lineNumber += 1; // Extract the tags while(lineNumber < lines.length) { const line = lines[lineNumber]; nextLine(line, lineNumber); const match = TAG_MARKER.exec(line); const tagDef = match && tagDefMap.get(match[1]); if (parseForTags() && match && (!tagDef || !tagDef.ignore) ) { tags.addTag(current); current = new Tag(tagDef, match[1], match[2], startingLine + lineNumber); } else { current.description = current.description ? (current.description + '\n' + line) : line; } lineNumber += 1; } if ( current ) { tags.addTag(current); } return tags; }; function init(lines, tags) { parserAdapters.forEach(adapter => adapter.init(lines, tags)); } function nextLine(line, lineNumber) { parserAdapters.forEach(adapter => adapter.nextLine(line, lineNumber)); } function parseForTags() { return parserAdapters.every(adapter => adapter.parseForTags()); } }