-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add man-page
generator
#125
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
'use strict'; | ||
|
||
import { writeFile, readFile } from 'node:fs/promises'; | ||
import { join } from 'node:path'; | ||
|
||
import { | ||
convertOptionToMandoc, | ||
convertEnvVarToMandoc, | ||
} from './utils/converter.mjs'; | ||
|
||
/** | ||
* This generator generates a man page version of the CLI.md file. | ||
* See https://man.openbsd.org/mdoc.7 for the formatting. | ||
* | ||
* @typedef {Array<ApiDocMetadataEntry>} Input | ||
* | ||
* @type {import('../types.d.ts').GeneratorMetadata<Input, string>} | ||
*/ | ||
export default { | ||
name: 'man-page', | ||
|
||
version: '1.0.0', | ||
|
||
description: 'Generates the Node.js man-page.', | ||
|
||
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 = components.findIndex(({ slug }) => slug === 'options'); | ||
const environmentStart = components.findIndex( | ||
({ slug }) => slug === 'environment-variables-1' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should probably be a constant (including the If that file ever gets updated with this content removed, we're screwed. |
||
); | ||
// The first header that is <3 in depth after environmentStart | ||
const environmentEnd = components.findIndex( | ||
({ heading }, index) => heading.depth < 3 && index > environmentStart | ||
); | ||
|
||
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 template = await readFile( | ||
join(import.meta.dirname, 'template.1'), | ||
'utf-8' | ||
); | ||
|
||
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(''); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
.\" | ||
.\" This file is automatically generated by api-docs-tooling. | ||
.\" Do not edit this file directly. Please make changes to CLI.md | ||
.\" and then regenerate this file. | ||
.\" | ||
.\" For generation instructions using api-docs-tooling, see: | ||
.\" https://github.com/nodejs/api-docs-tooling | ||
.\" | ||
.\"====================================================================== | ||
.Dd $Mdocdate$ | ||
.Dt NODE 1 | ||
. | ||
.Sh NAME | ||
.Nm node | ||
.Nd server-side JavaScript runtime | ||
. | ||
.Sh SYNOPSIS | ||
.Nm node | ||
.Op Ar options | ||
.Op Ar v8 options | ||
.Op Ar <program-entry-point> | Fl e Ar string | Fl - | ||
.Op Ar arguments ... | ||
. | ||
.Nm node | ||
.Cm inspect, | ||
.Op Ar <program-entry-point> | Fl e Ar string | Ar <host>:<port> | ||
.Ar ... | ||
. | ||
.Nm node | ||
.Op Fl -v8-options | ||
. | ||
.Sh DESCRIPTION | ||
Node.js is a set of libraries for JavaScript which allows it to be used outside of the browser. | ||
It is primarily focused on creating simple, easy-to-build network clients and servers. | ||
.Pp | ||
Execute | ||
.Nm | ||
without arguments to start a REPL. | ||
. | ||
.Sh OPTIONS | ||
.Bl -tag -width 6n | ||
__OPTIONS__ | ||
.El | ||
. | ||
.Sh ENVIRONMENT | ||
.Bl -tag -width 6n | ||
__ENVIRONMENT__ | ||
.El | ||
. | ||
.Sh BUGS | ||
Bugs are tracked in GitHub Issues: | ||
.Sy https://github.com/nodejs/node/issues | ||
. | ||
.Sh COPYRIGHT | ||
Copyright Node.js contributors. | ||
Node.js is available under the MIT license. | ||
. | ||
.Pp | ||
Node.js also includes external libraries that are available under a variety of licenses. | ||
See | ||
.Sy https://github.com/nodejs/node/blob/HEAD/LICENSE | ||
for the full license text. | ||
. | ||
.Sh SEE ALSO | ||
Website: | ||
.Sy https://nodejs.org/ | ||
. | ||
.Pp | ||
Documentation: | ||
.Sy https://nodejs.org/api/ | ||
. | ||
.Pp | ||
GitHub repository and issue tracker: | ||
.Sy https://github.com/nodejs/node |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
/** | ||
* Converts an Abstract Syntax Tree (AST) node to the Mandoc format for Unix manual pages. | ||
* This function processes the node recursively, converting each supported node type | ||
* to its corresponding Mandoc markup representation. Unsupported node types will be ignored. | ||
* | ||
* @param {import("mdast").Node} node - The AST node to be converted to Mandoc format. | ||
* @param {boolean} [isListItem=false] - Indicates if the current node is a list item. | ||
* This parameter is used to correctly format list elements in Mandoc. | ||
* @returns {string} The Mandoc formatted string representing the given node and its children. | ||
*/ | ||
export function convertNodeToMandoc(node, isListItem = false) { | ||
const convertChildren = (sep = '', ili = false) => | ||
node.children.map(child => convertNodeToMandoc(child, ili)).join(sep); | ||
const escapeText = () => node.value.replace(/\\/g, '\\\\'); | ||
|
||
switch (node.type) { | ||
case 'root': | ||
// Process the root node by converting all children and separating them with new lines. | ||
return convertChildren('\n'); | ||
|
||
case 'heading': | ||
// Convert to a Mandoc heading section (.Sh). | ||
return `.Sh ${convertChildren()}`; | ||
|
||
case 'link': | ||
case 'paragraph': | ||
case 'listItem': | ||
// Convert to Mandoc paragraph or list item. | ||
// .It denotes a list item in Mandoc, added only if the node is a list item. | ||
return `${isListItem && node.type === 'listItem' ? '.It\n' : ''}${convertChildren()}`; | ||
|
||
case 'text': | ||
// Escape any special characters in plain text content. | ||
return escapeText(); | ||
|
||
case 'inlineCode': | ||
// Format inline code using Mandoc's bold markup (\\fB ... \\fR). | ||
return `\\fB${escapeText()}\\fR`; | ||
|
||
case 'strong': | ||
// Format inline code + strong using Mandoc's bold markup (\\fB ... \\fR). | ||
return `\\fB${convertChildren()}\\fR`; | ||
|
||
case 'code': | ||
// Format code blocks as literal text using .Bd -literal and .Ed for start and end. | ||
return `.Bd -literal\n${escapeText()}\n.Ed`; | ||
|
||
case 'list': | ||
// Convert to a bullet list in Mandoc, starting with .Bl -bullet and ending with .El. | ||
return `.Bl -bullet\n${convertChildren('\n', true)}\n.El`; | ||
|
||
case 'emphasis': | ||
// Format emphasized text in Mandoc using italic markup (\\fI ... \\fR). | ||
return `\\fI${convertChildren()}\\fR`; | ||
|
||
default: | ||
// Ignore `html`, `blockquote`, etc. | ||
return ''; | ||
} | ||
} | ||
|
||
/** | ||
* Converts a command-line flag to its Mandoc representation. | ||
* This function splits the flag into its name and optional value (if present), | ||
* formatting them appropriately for Mandoc manual pages. | ||
* | ||
* @param {string} flag - The command-line flag to be formatted. It may include a value | ||
* specified with either an equals sign (=) or a space. | ||
* @returns {string} The Mandoc formatted representation of the flag and its value. | ||
*/ | ||
export function flagValueToMandoc(flag) { | ||
// 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]; | ||
|
||
// 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, | ||
* for display in Unix manual pages using Mandoc. | ||
* | ||
* @param {ApiDocMetadataEntry} element - The metadata entry containing details about the API option. | ||
* @returns {string} The Mandoc formatted string representing the API option, including flags and content. | ||
*/ | ||
export function convertOptionToMandoc(element) { | ||
// Format the option flags by splitting them, removing backticks, and converting each flag. | ||
const formattedFlags = element.heading.data.text | ||
.replace(/`/g, '') | ||
.split(', ') | ||
.map(formatFlag) | ||
.join(' , ') | ||
.trim(); | ||
|
||
// Remove the header itself. | ||
element.content.children.shift(); | ||
|
||
// Return the formatted flags and content, separated by Mandoc markers. | ||
RedYetiDev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return `.It ${formattedFlags}\n${convertNodeToMandoc(element.content).trim()}\n.\n`; | ||
} | ||
|
||
/** | ||
* Converts an API environment variable metadata entry into the Mandoc format. | ||
* This function formats environment variables for Unix manual pages, converting | ||
* the variable name and value, along with any associated descriptions, into Mandoc. | ||
* | ||
* @param {ApiDocMetadataEntry} element - The metadata entry containing details about the environment variable. | ||
* @returns {string} The Mandoc formatted representation of the environment variable and its content. | ||
*/ | ||
export function convertEnvVarToMandoc(element) { | ||
// Split the environment variable into name and optional value. | ||
const [varName, varValue] = element.heading.data.text | ||
.replace(/`/g, '') | ||
.split('='); | ||
|
||
// Format the variable value if present. | ||
RedYetiDev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const formattedValue = varValue ? ` Ar ${varValue}` : ''; | ||
|
||
// Remove the header itself. | ||
element.content.children.shift(); | ||
|
||
// Return the formatted environment variable and content, using Mandoc's .It (List item) and .Ev (Env Var) macros. | ||
RedYetiDev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return `.It Ev ${varName}${formattedValue}\n${convertNodeToMandoc(element.content)}\n.\n`; | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could have been a more laid-out error message