-
Notifications
You must be signed in to change notification settings - Fork 9
feat(cli): split cli into sub commands #250
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
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
f2ebf8b
feat(cli): split cli into sub commands
avivkeller 0255fb6
split into multiple files
avivkeller d480352
add jsdoc
avivkeller fbb3009
include boolean flags in final exec
avivkeller 91d26b2
suggestion from review
avivkeller 4d1a9de
code review
avivkeller 3fad262
Merge branch 'feat/cli/subcommands' of https://github.com/nodejs/api-…
avivkeller 780f9e4
show basic help
avivkeller 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 hidden or 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 hidden or 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 |
---|---|---|
@@ -1,161 +1,53 @@ | ||
#!/usr/bin/env node | ||
|
||
import { resolve } from 'node:path'; | ||
import process from 'node:process'; | ||
import { cpus } from 'node:os'; | ||
import { Argument, Command, Option } from 'commander'; | ||
|
||
import { Command, Option } from 'commander'; | ||
import interactive from './commands/interactive.mjs'; | ||
import list, { types } from './commands/list.mjs'; | ||
import commands from './commands/index.mjs'; | ||
|
||
import { coerce } from 'semver'; | ||
import { DOC_NODE_CHANGELOG_URL, DOC_NODE_VERSION } from '../src/constants.mjs'; | ||
import createGenerator from '../src/generators.mjs'; | ||
import { publicGenerators } from '../src/generators/index.mjs'; | ||
import createLinter from '../src/linter/index.mjs'; | ||
import reporters from '../src/linter/reporters/index.mjs'; | ||
import rules from '../src/linter/rules/index.mjs'; | ||
import createMarkdownLoader from '../src/loaders/markdown.mjs'; | ||
import createMarkdownParser from '../src/parsers/markdown.mjs'; | ||
import createNodeReleases from '../src/releases.mjs'; | ||
|
||
const availableGenerators = Object.keys(publicGenerators); | ||
|
||
const program = new Command(); | ||
|
||
program | ||
const program = new Command() | ||
.name('api-docs-tooling') | ||
.description('CLI tool to generate API documentation of a Node.js project.') | ||
.addOption( | ||
new Option( | ||
'-i, --input [patterns...]', | ||
'Specify input file patterns using glob syntax' | ||
).makeOptionMandatory() | ||
) | ||
.addOption( | ||
new Option( | ||
'--ignore [patterns...]', | ||
'Specify which input files to ignore using glob syntax' | ||
) | ||
) | ||
.addOption( | ||
new Option( | ||
'-o, --output <path>', | ||
'Specify the relative or absolute output directory' | ||
) | ||
) | ||
.addOption( | ||
new Option( | ||
'-v, --version <semver>', | ||
'Specify the target version of Node.js, semver compliant' | ||
).default(DOC_NODE_VERSION) | ||
) | ||
.addOption( | ||
new Option( | ||
'-c, --changelog <url>', | ||
'Specify the path (file: or https://) to the CHANGELOG.md file' | ||
).default(DOC_NODE_CHANGELOG_URL) | ||
) | ||
.addOption( | ||
new Option( | ||
'-t, --target [mode...]', | ||
'Set the processing target modes' | ||
).choices(availableGenerators) | ||
) | ||
.addOption( | ||
new Option('--disable-rule [rule...]', 'Disable a specific linter rule') | ||
.choices(Object.keys(rules)) | ||
.default([]) | ||
) | ||
.addOption( | ||
new Option('--lint-dry-run', 'Run linter in dry-run mode').default(false) | ||
) | ||
.addOption( | ||
new Option('--git-ref', 'A git ref/commit URL pointing to Node.js').default( | ||
'https://github.com/nodejs/node/tree/HEAD' | ||
) | ||
) | ||
.addOption( | ||
new Option('-r, --reporter [reporter]', 'Specify the linter reporter') | ||
.choices(Object.keys(reporters)) | ||
.default('console') | ||
) | ||
.addOption( | ||
new Option( | ||
'-p, --threads <number>', | ||
'The maximum number of threads to use. Set to 1 to disable parallelism' | ||
).default(Math.max(1, cpus().length - 1)) | ||
) | ||
.parse(process.argv); | ||
|
||
/** | ||
* @typedef {keyof publicGenerators} Target A list of the available generator names. | ||
* | ||
* @typedef {Object} Options | ||
* @property {Array<string>|string} input Specifies the glob/path for input files. | ||
* @property {string} output Specifies the directory where output files will be saved. | ||
* @property {Target[]} target Specifies the generator target mode. | ||
* @property {string} version Specifies the target Node.js version. | ||
* @property {string} changelog Specifies the path to the Node.js CHANGELOG.md file. | ||
* @property {string[]} disableRule Specifies the linter rules to disable. | ||
* @property {boolean} lintDryRun Specifies whether the linter should run in dry-run mode. | ||
* @property {boolean} useGit Specifies whether the parser should execute optional git commands. (Should only be used within a git repo) | ||
* @property {keyof reporters} reporter Specifies the linter reporter. | ||
* | ||
* @name ProgramOptions | ||
* @type {Options} | ||
* @description The return type for values sent to the program from the CLI. | ||
*/ | ||
const { | ||
input, | ||
ignore, | ||
output, | ||
target = [], | ||
version, | ||
changelog, | ||
disableRule, | ||
lintDryRun, | ||
gitRef, | ||
reporter, | ||
threads, | ||
} = program.opts(); | ||
.description('CLI tool to generate and lint Node.js API documentation'); | ||
|
||
const linter = createLinter(lintDryRun, disableRule); | ||
// Registering generate and lint commands | ||
commands.forEach(({ name, description, options, action }) => { | ||
const cmd = program.command(name).description(description); | ||
|
||
const { loadFiles } = createMarkdownLoader(); | ||
const { parseApiDocs } = createMarkdownParser(); | ||
// Add options to the command | ||
Object.values(options).forEach(({ flags, desc, prompt }) => { | ||
const option = new Option(flags.join(', '), desc).default( | ||
prompt.initialValue | ||
); | ||
|
||
const apiDocFiles = await loadFiles(input, ignore); | ||
if (prompt.required) { | ||
option.makeOptionMandatory(); | ||
} | ||
|
||
const parsedApiDocs = await parseApiDocs(apiDocFiles); | ||
if (prompt.type === 'multiselect') { | ||
option.choices(prompt.options.map(({ value }) => value)); | ||
} | ||
|
||
const { runGenerators } = createGenerator(parsedApiDocs); | ||
|
||
// Retrieves Node.js release metadata from a given Node.js version and CHANGELOG.md file | ||
const { getAllMajors } = createNodeReleases(changelog); | ||
cmd.addOption(option); | ||
}); | ||
|
||
// Runs the Linter on the parsed API docs | ||
linter.lintAll(parsedApiDocs); | ||
// Set the action for the command | ||
cmd.action(action); | ||
}); | ||
|
||
if (target) { | ||
await runGenerators({ | ||
// A list of target modes for the API docs parser | ||
generators: target, | ||
// Resolved `input` to be used | ||
input: input, | ||
// Resolved `output` path to be used | ||
output: output && resolve(output), | ||
// Resolved SemVer of current Node.js version | ||
version: coerce(version), | ||
// A list of all Node.js major versions with LTS status | ||
releases: await getAllMajors(), | ||
// An URL containing a git ref URL pointing to the commit or ref that was used | ||
// to generate the API docs. This is used to link to the source code of the | ||
gitRef, | ||
// How many threads should be used | ||
threads, | ||
}); | ||
} | ||
// Register the interactive command | ||
program | ||
.command('interactive') | ||
.description('Launch guided CLI wizard') | ||
.action(interactive); | ||
|
||
// Reports Lint Content | ||
linter.report(reporter); | ||
// Register the list command | ||
program | ||
.command('list') | ||
.addArgument(new Argument('<types>', 'The type to list').choices(types)) | ||
.description('List the given type') | ||
.action(list); | ||
|
||
process.exitCode = Number(linter.hasError()); | ||
// Parse and execute command-line arguments | ||
program.parse(process.argv); |
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.
Uh oh!
There was an error while loading. Please reload this page.