UNPKG

antsibull-docs

Version:

TypeScript library for processing Ansible documentation markup

214 lines 9.2 kB
"use strict"; /* Simplified BSD License (see LICENSES/BSD-2-Clause.txt or https://opensource.org/licenses/BSD-2-Clause) SPDX-FileCopyrightText: Ansible Project SPDX-License-Identifier: BSD-2-Clause */ Object.defineProperty(exports, "__esModule", { value: true }); exports.quoteRST = quoteRST; exports.postprocessRSTParagraph = postprocessRSTParagraph; exports.toRST = toRST; const opts_1 = require("./opts"); const format_1 = require("./format"); const util_1 = require("./util"); function quoteRST(text, escape_starting_whitespace = false, escape_ending_whitespace = false, must_not_be_empty = false) { text = text.replace(/([\\<>_*`|])/g, '\\$1'); if (escape_ending_whitespace && /\s$/.test(text.substring(text.length - 1))) { text = text + '\\ '; } if (escape_starting_whitespace && /^\s/.test(text)) { text = '\\ ' + text; } if (must_not_be_empty && text === '') { text = '\\ '; } return text; } function removeBackslashSpace(line) { let start = 0; let end = line.length; while (true) { // Remove starting '\ '. These have no effect. while ((0, util_1.startsWith)(line, '\\ ', start, end)) { start += 2; } // If the line now starts with regular whitespace, trim it. if ((0, util_1.startsWith)(line, ' ', start, end)) { start += 1; } else { // If there is none, we're done. break; } // Remove more starting whitespace, and then check again for leading '\ ' etc. while ((0, util_1.startsWith)(line, ' ', start, end)) { start += 1; } } while (true) { /* Remove trailing '\ ' resp. '\' (after line.trim()). These actually have an effect, since they remove the linebreak. *But* if our markup generator emits '\ ' followed by a line break, we still want the line break to count, so this is actually fixing a bug. */ if ((0, util_1.endsWith)(line, '\\', start, end)) { end -= 1; } while ((0, util_1.endsWith)(line, '\\ ', start, end)) { end -= 2; } // If the line now ends with regular whitespace, trim it. if ((0, util_1.endsWith)(line, ' ', start, end)) { end -= 1; } else { // If there is none, we're done. break; } // Remove more ending whitespace, and then check again for trailing '\' etc. while ((0, util_1.endsWith)(line, ' ', start, end)) { end -= 1; } } // Return subset of the line line = line.substring(start, end); line = line.replace(/\\ (?:\\ )+/g, '\\ '); line = line.replace(/(?<![\\])([ ])\\ (?![`])/g, '$1'); line = line.replace(/(?<!:`)\\ ([ .])/g, '$1'); return line; } function checkLine(index, lines, line) { if (index < 0 || index >= lines.length) { return false; } return lines[index] === line; } function modifyLine(index, line, lines) { const raw_html = '.. raw:: html'; const dashes = '------------'; const hr = ' <hr>'; if (line !== '' && line !== raw_html && line !== dashes && line !== hr) { return true; } if (line === raw_html || line === dashes) { return false; } if (line === hr && checkLine(index - 2, lines, raw_html)) { return false; } if (line === '' && (checkLine(index + 1, lines, raw_html) || checkLine(index - 1, lines, raw_html) || checkLine(index - 3, lines, raw_html))) { return false; } if (line === '' && (checkLine(index + 1, lines, dashes) || checkLine(index - 1, lines, dashes))) { return false; } return true; } function postprocessRSTParagraph(par) { let lines = (0, util_1.splitLines)(par.trim()); lines = lines.map((line, index) => modifyLine(index, line, lines) ? removeBackslashSpace(line.trim().replace('\t', ' ')) : line); return lines.filter((line, index) => (modifyLine(index, line, lines) ? !!line : true)).join('\n'); } function formatAntsibullOptionLike(part, role) { const result = []; if (part.plugin) { result.push(part.plugin.fqcn); result.push('#'); result.push(part.plugin.type); result.push(':'); } if (part.entrypoint !== undefined) { result.push(part.entrypoint); result.push(':'); } result.push(part.name); if (part.value !== undefined) { result.push('='); result.push(part.value); } return `\\ :${role}:\`${quoteRST(result.join(''), true, true, true)}\`\\ `; } function formatPlainOptionLike(part) { const plugin = []; if (part.plugin) { plugin.push(part.plugin.type); if (!['module', 'role', 'playbook'].includes(part.plugin.type)) { plugin.push(' plugin'); } plugin.push(` :ref:\`${quoteRST(part.plugin.fqcn)} <ansible_collections.${part.plugin.fqcn}_${part.plugin.type}>\``); } if (part.entrypoint !== undefined) { if (plugin.length) { plugin.push(', '); } plugin.push('entrypoint '); plugin.push(quoteRST(part.entrypoint, true)); } let value = part.name; if (part.value !== undefined) { value = `${value}=${part.value}`; } const pluginText = plugin.length ? ` (of ${plugin.join('')})` : ''; const mainText = `:literal:\`${quoteRST(value, true, true, true)}\``; return `\\ ${mainText}${pluginText}\\ `; } const DEFAULT_FORMATTER = { formatError: (part) => `\\ :strong:\`ERROR while parsing\`\\ : ${quoteRST(part.message, true, true, true)}\\ `, formatBold: (part) => `\\ :strong:\`${quoteRST(part.text, true, true, true)}\`\\ `, formatCode: (part) => `\\ :literal:\`${quoteRST(part.text, true, true, true)}\`\\ `, formatHorizontalLine: () => '\n\n.. raw:: html\n\n <hr>\n\n', formatItalic: (part) => `\\ :emphasis:\`${quoteRST(part.text, true, true, true)}\`\\ `, formatLink: (part) => part.text === '' ? '' : part.url === '' ? quoteRST(part.text) : `\\ \`${quoteRST(part.text)} <${encodeURI(part.url)}>\`__\\ `, formatModule: (part) => `\\ :ref:\`${quoteRST(part.fqcn, true, true, true)} <ansible_collections.${part.fqcn}_module>\`\\ `, formatRSTRef: (part) => `\\ :ref:\`${quoteRST(part.text, true, true, true)} <${part.ref}>\`\\ `, formatURL: (part) => (part.url === '' ? '' : `\\ \`${quoteRST(part.url)} <${encodeURI(part.url)}>\`__\\ `), formatText: (part) => quoteRST(part.text), formatEnvVariable: (part) => `\\ :envvar:\`${quoteRST(part.name, true, true, true)}\`\\ `, formatOptionName: (part) => formatAntsibullOptionLike(part, 'ansopt'), formatOptionValue: (part) => `\\ :ansval:\`${quoteRST(part.value, true, true, true)}\`\\ `, formatPlugin: (part) => `\\ :ref:\`${quoteRST(part.plugin.fqcn)} <ansible_collections.${part.plugin.fqcn}_${part.plugin.type}>\`\\ `, formatReturnValue: (part) => formatAntsibullOptionLike(part, 'ansretval'), }; const PLAIN_FORMATTER = { formatError: (part) => `\\ :strong:\`ERROR while parsing\`\\ : ${quoteRST(part.message, true, true, true)}\\ `, formatBold: (part) => `\\ :strong:\`${quoteRST(part.text, true, true, true)}\`\\ `, formatCode: (part) => `\\ :literal:\`${quoteRST(part.text, true, true, true)}\`\\ `, formatHorizontalLine: () => '\n\n------------\n\n', formatItalic: (part) => `\\ :emphasis:\`${quoteRST(part.text, true, true, true)}\`\\ `, formatLink: (part) => part.text === '' ? '' : part.url === '' ? quoteRST(part.text) : `\\ \`${quoteRST(part.text)} <${encodeURI(part.url)}>\`__\\ `, formatModule: (part) => `\\ :ref:\`${quoteRST(part.fqcn, true, true, true)} <ansible_collections.${part.fqcn}_module>\`\\ `, formatRSTRef: (part) => `\\ :ref:\`${quoteRST(part.text, true, true, true)} <${part.ref}>\`\\ `, formatURL: (part) => (part.url === '' ? '' : `\\ \`${quoteRST(part.url)} <${encodeURI(part.url)}>\`__\\ `), formatText: (part) => quoteRST(part.text), formatEnvVariable: (part) => `\\ :envvar:\`${quoteRST(part.name, true, true, true)}\`\\ `, formatOptionName: (part) => formatPlainOptionLike(part), formatOptionValue: (part) => `\\ :literal:\`${quoteRST(part.value, true, true, true)}\`\\ `, formatPlugin: (part) => `\\ :ref:\`${quoteRST(part.plugin.fqcn)} <ansible_collections.${part.plugin.fqcn}_${part.plugin.type}>\`\\ `, formatReturnValue: (part) => formatPlainOptionLike(part), }; function toRST(paragraphs, opts) { opts = opts !== null && opts !== void 0 ? opts : {}; const style = opts.style || 'antsibull-docs'; const mergedOpts = (0, opts_1.mergeOpts)(opts, style === 'antsibull-docs' ? DEFAULT_FORMATTER : PLAIN_FORMATTER); const result = []; for (const paragraph of paragraphs) { const line = []; (0, format_1.addToDestination)(line, paragraph, mergedOpts); const lineStr = postprocessRSTParagraph(line.join('')); result.push(lineStr || '\\'); } return result.join('\n\n'); } //# sourceMappingURL=rst.js.map