Skip to content

Latest commit

 

History

History
188 lines (115 loc) · 10.9 KB

File metadata and controls

188 lines (115 loc) · 10.9 KB

mdat-plugin-cli-help

NPM Package mdat-plugin-cli-help License: MIT CI

Mdat plugin to generate tabular help documentation for CLI tools in Markdown files.

Overview

This is a plugin for the mdat CLI tool, which is a simple Markdown templating system optimized for embedding dynamic content in repository readmes and the like.

This plugin automatically transforms a CLI command's --help output into nicely formatted Markdown tables.

The rule also recursively calls --help on any subcommands found for inclusion in the output.

Currently, the rule can parse help output in the format provided by Commander-, Yargs-, and Meow-based tools. If parsing fails, the rule will fall back to show the raw help output in a regular code block instead.

Getting started

Dependencies

We'll assume you have mdat installed either globally or in your local project.

Installation

Install the plugin as a development dependency:

pnpm add -D mdat-plugin-cli-help

Register the plugin in your mdat config file, e.g. mdat.config.ts:

import { defineConfig } from 'mdat'
import cliHelp from 'mdat-plugin-cli-help'

export default defineConfig({
  ...cliHelp,
})

Usage

Assuming you have an executable with a --help flag on your path or in your project's scope:

<!-- cli-help({ command: "mdat", depth: 1 }) -->

Then run the mdat CLI command on your Markdown file to expand the rule and embed the tabular help output:

<!-- cli-help({ command: "mdat", depth: 1 }) -->

#### Command: `mdat`

Work with MDAT placeholder comments in any Markdown file.

If no command is provided, `mdat expand` is run by default.

Usage:

```txt
mdat [command]
```

| Positional Argument | Description                                      | Type     |
| ------------------- | ------------------------------------------------ | -------- |
| `files`             | Markdown file(s) with MDAT placeholder comments. | `string` |

| Command    | Argument                | Description                                                    |
| ---------- | ----------------------- | -------------------------------------------------------------- |
| `expand`   | `<files..>` `[options]` | Expand MDAT placeholder comments. _(Default command.)_         |
| `check`    | `<files..>` `[options]` | Validate a Markdown file containing MDAT placeholder comments. |
| `collapse` | `<files..>` `[options]` | Collapse MDAT placeholder comments.                            |
| `readme`   | `[command]`             | Work with MDAT comments in your readme.md.                     |

| Option              | Description                                                                                                                                                                                                 | Type      | Default                                                                       |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------- |
| `--config`          | Path(s) to files containing MDAT configuration.                                                                                                                                                             | `array`   | Configuration is loaded if found from the usual places, or defaults are used. |
| `--rules`<br>`-r`   | Path(s) to files containing MDAT comment expansion rules.                                                                                                                                                   | `array`   |                                                                               |
| `--output`<br>`-o`  | Output file directory.                                                                                                                                                                                      | `string`  | Same directory as input file.                                                 |
| `--name`<br>`-n`    | Output file name.                                                                                                                                                                                           | `string`  | Same name as input file. Overwrites the input file.                           |
| `--meta`<br>`-m`    | Embed an extra comment at the top of the generated Markdown warning editors that certain sections of the document have been generated dynamically.                                                          | `boolean` |                                                                               |
| `--prefix`          | Require a string prefix before all comments to be considered for expansion. Useful if you have a bunch of non-MDAT comments in your Markdown file, or if you're willing to trade some verbosity for safety. | `string`  |                                                                               |
| `--print`           | Print the expanded Markdown to stdout instead of saving to a file. Ignores `--output` and `--name` options.                                                                                                 | `boolean` |                                                                               |
| `--verbose`         | Enable verbose logging. All verbose logs and prefixed with their log level and are printed to stderr for ease of redirection.                                                                               | `boolean` |                                                                               |
| `--help`<br>`-h`    | Show help                                                                                                                                                                                                   | `boolean` |                                                                               |
| `--version`<br>`-v` | Show version number                                                                                                                                                                                         | `boolean` |                                                                               |

<!-- /cli-help -->

To generate help for a specific subcommand, pass subcommand. Whitespace-separated for nested paths:

<!-- cli-help({ command: "mdat", subcommand: "readme", depth: 1 }) -->

This invokes mdat readme --help. Discovered sub-subcommands are appended to this path during recursion.

The command is also aliased under the <!-- cli --> keyword.

This would have equivalent output to the above:

<!-- cli({ command: "mdat", depth: 1 }) -->

If you embed the rule without any arguments, it will look for the binary file listed in the closest package.json file and run it with --help. This is what you want if you're documenting a package's CLI options in its readme.md file:

<!-- cli-help -->

Supported CLI frameworks

Fully supported, including options, commands, positionals, choices, defaults, and type annotations.

The parser handles line-wrapped output by unwrapping continuation lines before parsing. However, when Yargs wraps command arguments onto new lines at very narrow terminal widths (e.g. below ~70 columns), those wrapped argument lines are indistinguishable from new command rows and cannot be reliably unwrapped. In practice, this is rare.

For the most reliable parsing if you control the upstream project, configure your Yargs CLI to disable wrapping:

yargs(process.argv).wrap(process.stdout.isTTY ? Math.min(120, yargs.terminalWidth()) : 0)

This outputs unwrapped help text when piped, while preserving normal wrapping for interactive use.

Fully supported, including options, commands, arguments (positionals), and parenthesized defaults with optional environment variable annotations (e.g. (default: "value", env: MY_VAR)).

The parser handles line-wrapped output by unwrapping continuation lines before parsing. Commander's built-in help command is automatically filtered from subcommand recursion to avoid duplicate output.

Should be fully supported or nearly so.

Development notes

Parsing arbitrary --help output is a bit tricky.

You're right to think that an LLM could make quick work of this kind of "fuzzy text to structured data" transcription. However, when this tool was originally developed in 2024, testing a language model approach yielded sub-par results, so I pursued a traditional lexer/parser approach instead. There is also the logistical overhead of providing a smart-enough model both locally and in CI, where this tool frequently runs; it's technically feasible, but unpleasant. While the current hand-tuned parsers are admittedly a brittle tangle, future versions may revisit the LLM approach.

In terms of prior art, the jc project stands out as a heroic collection of CLI-tool output parsers, but does not currently implement help output parsing. It might be interesting to try to contribute mdat's help parsing implementations to jc.

Currently, the parser implementation lives in this repository because I really only use it in the context of my CLI tool readme files. In theory, it really belongs in a separate package.

Maintainers

kitschpatrol

Contributing

Issues are welcome and appreciated.

Please open an issue to discuss changes before submitting a pull request. Unsolicited PRs (especially AI-generated ones) are unlikely to be merged.

This repository uses @kitschpatrol/shared-config (via its ksc CLI) for linting and formatting, plus MDAT for readme placeholder expansion.

License

MIT © Eric Mika