diff --git a/README.md b/README.md index 60d9ce7..3548d07 100644 --- a/README.md +++ b/README.md @@ -37,9 +37,8 @@ CLI tool to generate API documentation of a Node.js project. Options: -i, --input [patterns...] Specify input file patterns using glob syntax -o, --output Specify the relative or absolute output directory - -v, --version Specify the target version of Node.js, semver compliant (default: "v22.9.0") - -c, --changelog Specify the path (file: or https://) to the CHANGELOG.md file (default: - "https://raw.githubusercontent.com/nodejs/node/HEAD/CHANGELOG.md") - -t, --target [mode...] Set the processing target modes (choices: "json-simple", "legacy-html", "legacy-html-all", "mandoc") + -v, --version Specify the target version of Node.js, semver compliant (default: "v22.6.0") + -c, --changelog Specify the path (file: or https://) to the CHANGELOG.md file (default: "https://raw.githubusercontent.com/nodejs/node/HEAD/CHANGELOG.md") + -t, --target [mode...] Set the processing target modes (choices: "json-simple", "legacy-html", "legacy-html-all", "man-page") -h, --help display help for command ``` diff --git a/src/generators/man-page/index.mjs b/src/generators/man-page/index.mjs index 03d7b95..94de839 100644 --- a/src/generators/man-page/index.mjs +++ b/src/generators/man-page/index.mjs @@ -26,43 +26,56 @@ export default { dependsOn: 'ast', async generate(input, options) { + // Filter to only 'cli'. + const components = input.filter(({ api }) => api === 'cli'); + if (!components.length) { + throw new Error('CLI.md not found'); + } + // Find the appropriate headers - const optionsStart = input.findIndex(({ slug }) => slug === 'options'); - const environmentStart = input.findIndex( + const optionsStart = components.findIndex(({ slug }) => slug === 'options'); + const environmentStart = components.findIndex( ({ slug }) => slug === 'environment-variables-1' ); + // The first header that is <3 in depth after environmentStart + const environmentEnd = components.findIndex( + ({ heading }, index) => heading.depth < 3 && index > environmentStart + ); - if (optionsStart + environmentStart <= 0) { - throw new Error('Could not find headers'); - } - - // Generate the option mandoc - let optionsOutput = ''; - for (let i = optionsStart + 1; i < environmentStart; i++) { - const el = input[i]; - if (el.heading.depth === 3) { - optionsOutput += convertOptionToMandoc(el); - } - } - - // Generate the environment mandoc - let envOutput = ''; - for (let i = environmentStart + 1; i < input.length; i++) { - const el = input[i]; - if (el.heading.depth === 3) { - envOutput += convertEnvVarToMandoc(el); - } - if (el.heading.depth < 3) break; - } + const output = { + // Extract the CLI options. + options: extractMandoc( + components, + optionsStart + 1, + environmentStart, + convertOptionToMandoc + ), + // Extract the environment variables. + env: extractMandoc( + components, + environmentStart + 1, + environmentEnd, + convertEnvVarToMandoc + ), + }; - const apiTemplate = await readFile( + const template = await readFile( join(import.meta.dirname, 'template.1'), 'utf-8' ); - const template = apiTemplate - .replace('__OPTIONS__', optionsOutput) - .replace('__ENVIRONMENT__', envOutput); - await writeFile(options.output, template); + const filledTemplate = template + .replace('__OPTIONS__', output.options) + .replace('__ENVIRONMENT__', output.env); + + await writeFile(options.output, filledTemplate); }, }; + +function extractMandoc(components, start, end, convert) { + return components + .slice(start, end) + .filter(({ heading }) => heading.depth === 3) + .map(convert) + .join(''); +} diff --git a/src/generators/man-page/utils/converter.mjs b/src/generators/man-page/utils/converter.mjs index 60d1b6c..57bab9e 100644 --- a/src/generators/man-page/utils/converter.mjs +++ b/src/generators/man-page/utils/converter.mjs @@ -69,18 +69,33 @@ export function convertNodeToMandoc(node, isListItem = false) { * @returns {string} The Mandoc formatted representation of the flag and its value. */ export function flagValueToMandoc(flag) { - // The seperator is '=' or ' '. - const sep = flag.match(/[= ]/)?.[0]; - if (sep == null) return ''; - // Split the flag into the name and value based on = or space delimiter. + // The separator is '=' or ' '. + let sep = flag.match(/[= ]/)?.[0]; + + if (sep == null) { + // This flag does not have a default value. + return ''; + } + + // Split the flag into the name and value based on the separator ('=' or space). const value = flag.split(sep)[1]; - // Format the value using Ns and Ar macros for Mandoc, if present. - // If the seperator is ' ', it'll become ''. - return value - ? `${sep === ' ' ? '' : ' Ns = Ns'} Ar ${value.replace(/\]$/, '')}` - : ''; + + // If there is no value, return an empty string. + if (!value) { + return ''; + } + + // Determine the prefix based on the separator type. + const prefix = sep === ' ' ? '' : ' Ns = Ns'; + + // Combine prefix and formatted value. + return `${prefix} Ar ${value.replace(/\]$/, '')}`; } +const formatFlag = flag => + // 'Fl' denotes a flag, followed by an optional 'Ar' (argument). + `Fl ${flag.split(/[= ]/)[0].slice(1)}${flagValueToMandoc(flag)}`; + /** * Converts an API option metadata entry into the Mandoc format. * This function formats command-line options, including flags and descriptions, @@ -94,17 +109,15 @@ export function convertOptionToMandoc(element) { const formattedFlags = element.heading.data.text .replace(/`/g, '') .split(', ') - .map( - // 'Fl' denotes a flag - flag => `Fl ${flag.split(/[= ]/)[0].slice(1)}${flagValueToMandoc(flag)}` - ) - .join(' , '); + .map(formatFlag) + .join(' , ') + .trim(); // Remove the header itself. element.content.children.shift(); // Return the formatted flags and content, separated by Mandoc markers. - return `.It ${formattedFlags.trim()}\n${convertNodeToMandoc(element.content)}\n.\n`; + return `.It ${formattedFlags}\n.\n${convertNodeToMandoc(element.content).trim()}\n.\n`; } /**