in jsdoc/processors/inline-tags.js [36:112]
$process(docs) {
const definitions = this.inlineTagDefinitions;
const definitionMap = getMap(definitions);
// Walk the docs and parse the inline-tags
docs.forEach(doc => {
if ( doc.renderedContent ) {
// This is a stack of start-end tag instances
// as a new start-end tag is found it is unshifted onto the front of this array
// Each item looks like: { definition: tagDef, value: { tag: '...', content: '...' } }
const pendingTags = [];
// The resulting array from the split is alternating plain content and inline tags
const parts = doc.renderedContent.split(INLINE_TAG);
doc.renderedContent = parts.reduce((renderedContent, nextPart) => {
const match = INLINE_TAG_DETAIL.exec(nextPart);
if (match) {
// We have a new tag
const tagName = match[1];
const tagDescription = match[2] && match[2].trim();
if (pendingTags.length > 0 && tagName === pendingTags[0].definition.end) {
// We have found a matching end tag. Remove it from the stack and run its handler
const pendingTag = pendingTags.shift();
const startTag = pendingTag.definition;
nextPart = startTag.handler(doc, startTag.name, pendingTag.value, docs);
} else {
// We have a new tag. Look it up in the definitions
const definition = definitionMap.get(tagName);
if (!definition) {
// There is no matching tag definition
log.warn(createDocMessage('No handler provided for inline tag "' + match[0] + '"', doc));
nextPart = match[0];
} else if(definition.end) {
// We have a new start-end tag. Unshift it onto the pendingTags stack
pendingTags.unshift({
definition: definition,
value: {
tag: tagDescription,
content: ''
}
});
nextPart = '';
} else {
// We have a new normal tag. Run its handler
nextPart = definition.handler(doc, definition.name, tagDescription, docs);
}
}
} else if (pendingTags.length) {
// We have some plain content but we are inside a start-end tag
// Add this content to the current start-end tag
pendingTags[0].value.content += nextPart;
nextPart = '';
}
return renderedContent + nextPart;
});
}
});
}