'use strict';
module.exports = {
hasTag,
isJsdoc,
parseTags,
};
function isJsdoc(comment) {
return comment.type === 'Block' && comment.value.startsWith('*');
}
function hasTag(comment, tagName) {
return tagEntries(comment).some((tag) => tag.name === tagName);
}
function parseTags(comment) {
const tags = new Map();
for (const { name, text } of tagEntries(comment)) {
if (!tags.has(name)) {
tags.set(name, new Map());
}
if (name === 'typeParam') {
const [typeName, description] = splitNameAndDescription(text);
tags.get(name).set(typeName, description);
} else {
tags.get(name).set('*', text);
}
}
return tags;
}
function tagEntries(comment) {
return commentLines(comment)
.map(tagEntry)
.filter((entry) => entry != null);
}
function commentLines(comment) {
return comment.value.split('\n').map((line, index) => {
let text = index === 0 && line.startsWith('*') ? line.slice(1) : line;
text = text.trimStart();
if (text.startsWith('*')) {
text = text.slice(1);
}
if (text.startsWith(' ')) {
text = text.slice(1);
}
return text.trim();
});
}
function tagEntry(line) {
if (!line.startsWith('@')) {
return null;
}
const [name, text] = splitFirstWord(line.slice(1));
if (name === '') {
return null;
}
return {
name,
text,
};
}
function splitNameAndDescription(text) {
const [name, description] = splitFirstWord(text);
return [
name,
description.startsWith('-') ? description.slice(1).trim() : description,
];
}
function splitFirstWord(text) {
const trimmed = text.trim();
const end = firstWhitespace(trimmed);
if (end === -1) {
return [trimmed, ''];
}
return [trimmed.slice(0, end), trimmed.slice(end).trim()];
}
function firstWhitespace(text) {
for (let i = 0; i < text.length; i++) {
if (isWhitespace(text[i])) {
return i;
}
}
return -1;
}
function isWhitespace(character) {
return character === ' ' || character === '\t';
}