prettier-plugin-jsdoc
Version:
Prettier plugin for format comment blocks and convert to standard Match with Visual studio and other IDE which support jsdoc and comments as markdown.
230 lines (229 loc) • 9.48 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.formatDescription = exports.descriptionEndLine = void 0;
const prettier_1 = require("prettier");
const tags_1 = require("./tags");
const utils_1 = require("./utils");
const mdast_util_from_markdown_1 = __importDefault(require("mdast-util-from-markdown"));
const TABLE = "2@^5!~#sdE!_TABLE";
const parserSynonyms = {
js: ["babel", "babel-flow", "vue"],
javascript: ["babel", "babel-flow", "vue"],
ts: ["typescript", "babel-ts", "angular"],
typescript: ["typescript", "babel-ts", "angular"],
json: ["json", "json5", "json-stringify"],
};
function descriptionEndLine({ tag, isEndTag, }) {
if ([tags_1.DESCRIPTION, tags_1.EXAMPLE, tags_1.TODO].includes(tag) && !isEndTag) {
return "\n";
}
return "";
}
exports.descriptionEndLine = descriptionEndLine;
/**
* Trim, make single line with capitalized text. Insert dot if flag for it is
* set to true and last character is a word character
*
* @private
*/
function formatDescription(tag, text, options, formatOptions) {
if (!text)
return text;
const { printWidth } = options;
const { tagStringLength = 0, beginningSpace } = formatOptions;
/**
* change list with dash to dot for example:
* 1- a thing
*
* to
*
* 1. a thing
*/
text = text.replace(/^(\d+)[-][\s|]+/g, "$1. "); // Start
text = text.replace(/\n+(\s*\d+)[-][\s]+/g, "\n$1. ");
const tables = [];
text = text.replace(/((\n|^)\|[\s\S]*?)((\n[^|])|$)/g, (code, _1, _2, _3) => {
code = _3 ? code.slice(0, -1) : code;
tables.push(code);
return `\n\n${TABLE}\n\n${_3 ? _3.slice(1) : ""}`;
});
text = utils_1.capitalizer(text);
text = `${"!".repeat(tagStringLength)}${text.startsWith("```") ? "\n" : ""}${text}`;
let tableIndex = 0;
const rootAst = mdast_util_from_markdown_1.default(text);
function stringifyASTWithoutChildren(mdAst, intention, parent) {
if (mdAst.type === "inlineCode") {
return `\`${mdAst.value}\``;
}
if (mdAst.type === "code") {
let result = mdAst.value || "";
let _intention = intention;
if (result) {
// Remove two space from lines, maybe added previous format
if (mdAst.lang) {
const supportParsers = parserSynonyms[mdAst.lang.toLowerCase()];
const parser = (supportParsers === null || supportParsers === void 0 ? void 0 : supportParsers.includes(options.parser))
? options.parser
: (supportParsers === null || supportParsers === void 0 ? void 0 : supportParsers[0]) || mdAst.lang;
result = utils_1.formatCode(result, intention, {
...options,
parser,
jsdocKeepUnParseAbleExampleIndent: true,
});
}
else {
_intention = intention + " ".repeat(4);
result = utils_1.formatCode(result, _intention, {
...options,
jsdocKeepUnParseAbleExampleIndent: true,
});
}
}
result = mdAst.lang ? result : result.trimEnd();
return result
? mdAst.lang
? `\n\n${_intention}\`\`\`${mdAst.lang}${result}\`\`\``
: `\n${result}`
: "";
}
if (mdAst.value === TABLE) {
if (parent) {
parent.costumeType = TABLE;
}
if (tables.length > 0) {
let result = (tables === null || tables === void 0 ? void 0 : tables[tableIndex]) || "";
tableIndex++;
if (result) {
result = prettier_1.format(result, {
...options,
parser: "markdown",
}).trim();
}
return `${result
? `\n\n${intention}${result.split("\n").join(`\n${intention}`)}`
: mdAst.value}`;
}
}
if (mdAst.type === "break") {
return `\\\n`;
}
return (mdAst.value || "");
}
function stringyfy(mdAst, intention, parent) {
if (!Array.isArray(mdAst.children)) {
return stringifyASTWithoutChildren(mdAst, intention, parent);
}
return mdAst.children
.map((ast, index) => {
var _a;
if (ast.type === "listItem") {
let _listCount = `\n${intention}- `;
// .replace(/((?!(^))\n)/g, "\n" + _intention);
if (typeof mdAst.start === "number") {
const count = index + ((_a = mdAst.start) !== null && _a !== void 0 ? _a : 1);
_listCount = `\n${intention}${count}. `;
}
const _intention = intention + " ".repeat(_listCount.length - 1);
const result = stringyfy(ast, _intention, mdAst).trim();
return `${_listCount}${result}`;
}
if (ast.type === "list") {
let end = "";
/**
* Add empty line after list if that is end of description
* issue: {@link https://github.com/hosseinmd/prettier-plugin-jsdoc/issues/98}
*/
if (tag !== tags_1.DESCRIPTION &&
mdAst.type === "root" &&
index === mdAst.children.length - 1) {
end = "\n";
}
return `\n${stringyfy(ast, intention, mdAst)}${end}`;
}
if (ast.type === "paragraph") {
const paragraph = stringyfy(ast, intention, parent);
if (ast.costumeType === TABLE) {
return paragraph;
}
return `\n\n${paragraph
/**
* Break by backslash\
* issue: https://github.com/hosseinmd/prettier-plugin-jsdoc/issues/102
*/
.split("\\\n")
.map((_paragraph) => {
const links = [];
// Find jsdoc links and remove spaces
_paragraph = _paragraph.replace(/{@link[\s](([^{}])*)}/g, (_, link) => {
links.push(link);
return `{@link${"_".repeat(link.length)}}`;
});
_paragraph = _paragraph.replace(/\s+/g, " "); // Make single line
_paragraph = utils_1.capitalizer(_paragraph);
if (options.jsdocDescriptionWithDot)
_paragraph = _paragraph.replace(/([\w\p{L}])$/u, "$1."); // Insert dot if needed
let result = breakDescriptionToLines(_paragraph, printWidth, intention);
// Replace links
result = result.replace(/{@link([_]+)}/g, (original, underline) => {
const link = links[0];
if (link.length === underline.length) {
links.shift();
return `{@link ${link}}`;
}
return original;
});
return result;
})
.join("\\\n")}`;
}
if (ast.type === "strong") {
return `**${stringyfy(ast, intention, mdAst)}**`;
}
if (ast.type === "emphasis") {
return `*${stringyfy(ast, intention, mdAst)}*`;
}
if (ast.type === "heading") {
return `\n\n${intention}${"#".repeat(ast.depth)} ${stringyfy(ast, intention, mdAst)}`;
}
if (ast.type === "link") {
return `[${stringyfy(ast, intention, mdAst)}](${ast.url})`;
}
return stringyfy(ast, intention, mdAst);
})
.join("");
}
let result = stringyfy(rootAst, beginningSpace, null);
result = result.trimStart().slice(tagStringLength);
return result;
}
exports.formatDescription = formatDescription;
function breakDescriptionToLines(desContent, maxWidth, beginningSpace) {
let str = desContent.trim();
if (!str) {
return str;
}
const extraLastLineWidth = 10;
let result = "";
while (str.length > maxWidth + extraLastLineWidth) {
let sliceIndex = str.lastIndexOf(" ", str.startsWith("\n") ? maxWidth + 1 : maxWidth);
/**
* When a str is a long word lastIndexOf will gives 4 every time loop
* running unlimited time
*/
if (sliceIndex <= beginningSpace.length)
sliceIndex = str.indexOf(" ", beginningSpace.length + 1);
if (sliceIndex === -1)
sliceIndex = str.length;
result += str.substring(0, sliceIndex);
str = str.substring(sliceIndex + 1);
if (str) {
str = `${beginningSpace}${str}`;
str = `\n${str}`;
}
}
result += str;
return `${beginningSpace}${result}`;
}