UNPKG

prettier-plugin-jsdoc

Version:
250 lines 10.4 kB
import { format } from "prettier"; import { DESCRIPTION, EXAMPLE, TODO } from "./tags.js"; import { capitalizer, formatCode } from "./utils.js"; import { TAGS_PEV_FORMATE_DESCRIPTION } from "./roles.js"; import { fromMarkdown } from "mdast-util-from-markdown"; const TABLE = "2@^5!~#sdE!_TABLE"; const parserSynonyms = (lang) => { switch (lang) { case "js": case "javascript": case "jsx": return ["babel", "babel-flow", "vue"]; case "ts": case "typescript": case "tsx": return ["typescript", "babel-ts", "angular"]; case "json": case "css": return ["css"]; case "less": return ["less"]; case "scss": return ["scss"]; case "html": return ["html"]; case "yaml": return ["yaml"]; default: return ["babel"]; } }; function descriptionEndLine({ tag, isEndTag, }) { if ([DESCRIPTION, EXAMPLE, TODO].includes(tag) && !isEndTag) { return "\n"; } return ""; } async function formatDescription(tag, text, options, formatOptions) { if (!text) return text; const { printWidth } = options; const { tagStringLength = 0, beginningSpace } = formatOptions; text = text.replace(/^(\d+)[-][\s|]+/g, "$1. "); text = text.replace(/\n+(\s*\d+)[-][\s]+/g, "\n$1. "); const fencedCodeBlocks = text.matchAll(/```\S*?\n[\s\S]+?```/gm); const indentedCodeBlocks = text.matchAll(/^\r?\n^(?:(?:(?:[ ]{4}|\t).*(?:\r?\n|$))+)/gm); const allCodeBlocks = [...fencedCodeBlocks, ...indentedCodeBlocks]; const tables = []; text = text.replace(/((\n|^)\|[\s\S]*?)((\n[^|])|$)/g, (code, _1, _2, _3, _, offs) => { for (const block of allCodeBlocks) { if (block.index !== undefined && block.index <= offs + 1 && offs + code.length + 1 <= block.index + block[0].length) { return code; } } code = _3 ? code.slice(0, -1) : code; tables.push(code); return `\n\n${TABLE}\n\n${_3 ? _3.slice(1) : ""}`; }); if (options.jsdocCapitalizeDescription && !TAGS_PEV_FORMATE_DESCRIPTION.includes(tag)) { text = capitalizer(text); } text = `${tagStringLength ? `${"!".repeat(tagStringLength - 1)}?` : ""}${text.startsWith("```") ? "\n" : ""}${text}`; let tableIndex = 0; text = text.replace(new RegExp("\\n" + `[\u0020]{${beginningSpace.length}}`, "g"), "\n"); const rootAst = fromMarkdown(text); async 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) { if (mdAst.lang) { const supportParsers = parserSynonyms(mdAst.lang.toLowerCase()); const parser = supportParsers?.includes(options.parser) ? options.parser : supportParsers?.[0] || mdAst.lang; result = await formatCode(result, intention, { ...options, parser, jsdocKeepUnParseAbleExampleIndent: true, }); } else if (options.jsdocPreferCodeFences || false) { result = await formatCode(result, _intention, { ...options, jsdocKeepUnParseAbleExampleIndent: true, }); } else { _intention = intention + " ".repeat(4); result = await formatCode(result, _intention, { ...options, jsdocKeepUnParseAbleExampleIndent: true, }); } } const addFence = options.jsdocPreferCodeFences || !!mdAst.lang; result = addFence ? result : result.trimEnd(); return result ? addFence ? `\n\n${_intention}\`\`\`${mdAst.lang || ""}${result}\`\`\`` : `\n${result}` : ""; } if (mdAst.value === TABLE) { if (parent) { parent.costumeType = TABLE; } if (tables.length > 0) { let result = tables?.[tableIndex] || ""; tableIndex++; if (result) { result = (await 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 || mdAst.title || mdAst.alt || ""); } async function stringyfy(mdAst, intention, parent) { if (!Array.isArray(mdAst.children)) { return stringifyASTWithoutChildren(mdAst, intention, parent); } return (await Promise.all(mdAst.children.map(async (ast, index) => { switch (ast.type) { case "listItem": { let _listCount = `\n${intention}- `; if (typeof mdAst.start === "number") { const count = index + (mdAst.start ?? 1); _listCount = `\n${intention}${count}. `; } const _intention = intention + " ".repeat(_listCount.length - 1); const result = (await stringyfy(ast, _intention, mdAst)).trim(); return `${_listCount}${result}`; } case "list": { let end = ""; if (tag !== DESCRIPTION && mdAst.type === "root" && index === mdAst.children.length - 1) { end = "\n"; } return `\n${await stringyfy(ast, intention, mdAst)}${end}`; } case "paragraph": { const paragraph = await stringyfy(ast, intention, parent); if (ast.costumeType === TABLE) { return paragraph; } return `\n\n${paragraph .split("\\\n") .map((_paragraph) => { const links = []; _paragraph = _paragraph.replace(/{@(link|linkcode|linkplain)[\s](([^{}])*)}/g, (_, tag, link) => { links.push(link); return `{@${tag}${"_".repeat(link.length)}}`; }); _paragraph = _paragraph.replace(/\s+/g, " "); if (options.jsdocCapitalizeDescription && !TAGS_PEV_FORMATE_DESCRIPTION.includes(tag)) _paragraph = capitalizer(_paragraph); if (options.jsdocDescriptionWithDot) _paragraph = _paragraph.replace(/([\w\p{L}])$/u, "$1."); let result = breakDescriptionToLines(_paragraph, printWidth, intention); result = result.replace(/{@(link|linkcode|linkplain)([_]+)}/g, (original, tag, underline) => { const link = links[0]; if (link.length === underline.length) { links.shift(); return `{@${tag} ${link}}`; } return original; }); return result; }) .join("\\\n")}`; } case "strong": { return `**${await stringyfy(ast, intention, mdAst)}**`; } case "emphasis": { return `_${await stringyfy(ast, intention, mdAst)}_`; } case "heading": { return `\n\n${intention}${"#".repeat(ast.depth)} ${await stringyfy(ast, intention, mdAst)}`; } case "link": case "image": { return `[${await stringyfy(ast, intention, mdAst)}](${ast.url})`; } case "linkReference": { return `[${await stringyfy(ast, intention, mdAst)}][${ast.label}]`; } case "definition": { return `\n\n[${ast.label}]: ${ast.url}`; } case "blockquote": { const paragraph = await stringyfy(ast, "", mdAst); return `\n\n> ${paragraph .trim() .replace(/(\n+)/g, `$1${intention}> `)}`; } } return stringyfy(ast, intention, mdAst); }))).join(""); } let result = await stringyfy(rootAst, beginningSpace, null); result = result.replace(/^[\s\n]+/g, ""); result = result.replace(/^([!]+\?)/g, ""); return result; } function breakDescriptionToLines(desContent, maxWidth, beginningSpace) { let str = desContent.trim(); if (!str) { return str; } let result = ""; while (str.length > maxWidth) { let sliceIndex = str.lastIndexOf(" ", str.startsWith("\n") ? maxWidth + 1 : maxWidth); 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}`; } export { descriptionEndLine, formatDescription }; //# sourceMappingURL=descriptionFormatter.js.map