@optique/core 0.1.0-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +475 -0
- package/dist/doc.cjs +104 -0
- package/dist/doc.d.cts +129 -0
- package/dist/doc.d.ts +129 -0
- package/dist/doc.js +104 -0
- package/dist/facade.cjs +98 -0
- package/dist/facade.d.cts +113 -0
- package/dist/facade.d.ts +113 -0
- package/dist/facade.js +97 -0
- package/dist/index.cjs +42 -0
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +8 -0
- package/dist/message.cjs +202 -0
- package/dist/message.d.cts +199 -0
- package/dist/message.d.ts +199 -0
- package/dist/message.js +194 -0
- package/dist/parser.cjs +1065 -0
- package/dist/parser.d.cts +580 -0
- package/dist/parser.d.ts +580 -0
- package/dist/parser.js +1053 -0
- package/dist/usage.cjs +242 -0
- package/dist/usage.d.cts +217 -0
- package/dist/usage.d.ts +217 -0
- package/dist/usage.js +239 -0
- package/dist/valueparser.cjs +332 -0
- package/dist/valueparser.d.cts +332 -0
- package/dist/valueparser.d.ts +332 -0
- package/dist/valueparser.js +325 -0
- package/package.json +117 -0
package/dist/doc.d.ts
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { Message } from "./message.js";
|
|
2
|
+
import { Usage, UsageTerm } from "./usage.js";
|
|
3
|
+
|
|
4
|
+
//#region src/doc.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A documentation entry which describes a specific usage of a command or
|
|
8
|
+
* option. It includes a subject (the usage), a description, and an optional
|
|
9
|
+
* default value.
|
|
10
|
+
*/
|
|
11
|
+
interface DocEntry {
|
|
12
|
+
/**
|
|
13
|
+
* The subject of the entry, which is typically a command or option
|
|
14
|
+
* usage.
|
|
15
|
+
*/
|
|
16
|
+
readonly term: UsageTerm;
|
|
17
|
+
/**
|
|
18
|
+
* A description of the entry, which provides additional context or
|
|
19
|
+
* information about the usage.
|
|
20
|
+
*/
|
|
21
|
+
readonly description?: Message;
|
|
22
|
+
/**
|
|
23
|
+
* An optional default value for the entry, which can be used to
|
|
24
|
+
* indicate what the default behavior is if the command or option is not
|
|
25
|
+
* specified.
|
|
26
|
+
*/
|
|
27
|
+
readonly default?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A section in a document that groups related entries together.
|
|
31
|
+
*/
|
|
32
|
+
interface DocSection {
|
|
33
|
+
readonly title?: string;
|
|
34
|
+
readonly entries: readonly DocEntry[];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* A document page that contains multiple sections, each with its own brief
|
|
38
|
+
* and a list of entries. This structure is used to organize documentation
|
|
39
|
+
* for commands, options, and other related information.
|
|
40
|
+
*/
|
|
41
|
+
interface DocPage {
|
|
42
|
+
readonly brief?: Message;
|
|
43
|
+
readonly usage?: Usage;
|
|
44
|
+
readonly description?: Message;
|
|
45
|
+
readonly sections: readonly DocSection[];
|
|
46
|
+
readonly footer?: Message;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* A documentation fragment that can be either an entry or a section.
|
|
50
|
+
* Fragments are building blocks used to construct documentation pages.
|
|
51
|
+
*/
|
|
52
|
+
type DocFragment = {
|
|
53
|
+
readonly type: "entry";
|
|
54
|
+
} & DocEntry | {
|
|
55
|
+
readonly type: "section";
|
|
56
|
+
} & DocSection;
|
|
57
|
+
/**
|
|
58
|
+
* A collection of documentation fragments with an optional description.
|
|
59
|
+
* This structure is used to gather fragments before organizing them into
|
|
60
|
+
* a final document page.
|
|
61
|
+
*/
|
|
62
|
+
interface DocFragments {
|
|
63
|
+
/**
|
|
64
|
+
* An optional description that applies to the entire collection of fragments.
|
|
65
|
+
*/
|
|
66
|
+
readonly description?: Message;
|
|
67
|
+
/**
|
|
68
|
+
* An array of documentation fragments that can be entries or sections.
|
|
69
|
+
*/
|
|
70
|
+
readonly fragments: readonly DocFragment[];
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Options for formatting a documentation page.
|
|
74
|
+
*/
|
|
75
|
+
interface DocPageFormatOptions {
|
|
76
|
+
/**
|
|
77
|
+
* Whether to include ANSI color codes in the output.
|
|
78
|
+
* @default `false`
|
|
79
|
+
*/
|
|
80
|
+
colors?: boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Number of spaces to indent terms in documentation entries.
|
|
83
|
+
* @default `2`
|
|
84
|
+
*/
|
|
85
|
+
termIndent?: number;
|
|
86
|
+
/**
|
|
87
|
+
* Width allocated for terms before descriptions start.
|
|
88
|
+
* @default `26`
|
|
89
|
+
*/
|
|
90
|
+
termWidth?: number;
|
|
91
|
+
/**
|
|
92
|
+
* Maximum width of the entire formatted output.
|
|
93
|
+
*/
|
|
94
|
+
maxWidth?: number;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Formats a documentation page into a human-readable string.
|
|
98
|
+
*
|
|
99
|
+
* This function takes a structured {@link DocPage} and converts it into
|
|
100
|
+
* a formatted string suitable for display in terminals or documentation.
|
|
101
|
+
* The formatting includes proper indentation, alignment, and optional
|
|
102
|
+
* color support.
|
|
103
|
+
*
|
|
104
|
+
* @param programName The name of the program, used in usage lines
|
|
105
|
+
* @param page The documentation page to format
|
|
106
|
+
* @param options Formatting options to customize the output
|
|
107
|
+
* @returns A formatted string representation of the documentation page
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```typescript
|
|
111
|
+
* const page: DocPage = {
|
|
112
|
+
* brief: "A CLI tool",
|
|
113
|
+
* usage: [{ type: "literal", value: "myapp" }],
|
|
114
|
+
* sections: [{
|
|
115
|
+
* title: "Options",
|
|
116
|
+
* entries: [{
|
|
117
|
+
* term: { type: "option", short: "-v", long: "--verbose" },
|
|
118
|
+
* description: "Enable verbose output"
|
|
119
|
+
* }]
|
|
120
|
+
* }]
|
|
121
|
+
* };
|
|
122
|
+
*
|
|
123
|
+
* const formatted = formatDocPage("myapp", page, { colors: true });
|
|
124
|
+
* console.log(formatted);
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
declare function formatDocPage(programName: string, page: DocPage, options?: DocPageFormatOptions): string;
|
|
128
|
+
//#endregion
|
|
129
|
+
export { DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, formatDocPage };
|
package/dist/doc.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { formatMessage } from "./message.js";
|
|
2
|
+
import { formatUsage, formatUsageTerm } from "./usage.js";
|
|
3
|
+
|
|
4
|
+
//#region src/doc.ts
|
|
5
|
+
/**
|
|
6
|
+
* Formats a documentation page into a human-readable string.
|
|
7
|
+
*
|
|
8
|
+
* This function takes a structured {@link DocPage} and converts it into
|
|
9
|
+
* a formatted string suitable for display in terminals or documentation.
|
|
10
|
+
* The formatting includes proper indentation, alignment, and optional
|
|
11
|
+
* color support.
|
|
12
|
+
*
|
|
13
|
+
* @param programName The name of the program, used in usage lines
|
|
14
|
+
* @param page The documentation page to format
|
|
15
|
+
* @param options Formatting options to customize the output
|
|
16
|
+
* @returns A formatted string representation of the documentation page
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* const page: DocPage = {
|
|
21
|
+
* brief: "A CLI tool",
|
|
22
|
+
* usage: [{ type: "literal", value: "myapp" }],
|
|
23
|
+
* sections: [{
|
|
24
|
+
* title: "Options",
|
|
25
|
+
* entries: [{
|
|
26
|
+
* term: { type: "option", short: "-v", long: "--verbose" },
|
|
27
|
+
* description: "Enable verbose output"
|
|
28
|
+
* }]
|
|
29
|
+
* }]
|
|
30
|
+
* };
|
|
31
|
+
*
|
|
32
|
+
* const formatted = formatDocPage("myapp", page, { colors: true });
|
|
33
|
+
* console.log(formatted);
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
function formatDocPage(programName, page, options = {}) {
|
|
37
|
+
const termIndent = options.termIndent ?? 2;
|
|
38
|
+
const termWidth = options.termWidth ?? 26;
|
|
39
|
+
let output = "";
|
|
40
|
+
if (page.brief != null) {
|
|
41
|
+
output += formatMessage(page.brief, {
|
|
42
|
+
colors: options.colors,
|
|
43
|
+
maxWidth: options.maxWidth,
|
|
44
|
+
quotes: !options.colors
|
|
45
|
+
});
|
|
46
|
+
output += "\n";
|
|
47
|
+
}
|
|
48
|
+
if (page.usage != null) {
|
|
49
|
+
output += "Usage: ";
|
|
50
|
+
output += indentLines(formatUsage(programName, page.usage, {
|
|
51
|
+
colors: options.colors,
|
|
52
|
+
maxWidth: options.maxWidth == null ? void 0 : options.maxWidth - 7,
|
|
53
|
+
expandCommands: true
|
|
54
|
+
}), 7);
|
|
55
|
+
output += "\n";
|
|
56
|
+
}
|
|
57
|
+
if (page.description != null) {
|
|
58
|
+
output += "\n";
|
|
59
|
+
output += formatMessage(page.description, {
|
|
60
|
+
colors: options.colors,
|
|
61
|
+
maxWidth: options.maxWidth,
|
|
62
|
+
quotes: !options.colors
|
|
63
|
+
});
|
|
64
|
+
output += "\n";
|
|
65
|
+
}
|
|
66
|
+
const sections = page.sections.toSorted((a, b) => a.title == null && b.title == null ? 0 : a.title == null ? -1 : 1);
|
|
67
|
+
for (const section of sections) {
|
|
68
|
+
output += "\n";
|
|
69
|
+
if (section.title != null) output += `${section.title}:\n`;
|
|
70
|
+
for (const entry of section.entries) {
|
|
71
|
+
const term = formatUsageTerm(entry.term, {
|
|
72
|
+
colors: options.colors,
|
|
73
|
+
optionsSeparator: ", ",
|
|
74
|
+
maxWidth: options.maxWidth == null ? void 0 : options.maxWidth - termIndent
|
|
75
|
+
});
|
|
76
|
+
output += `${" ".repeat(termIndent)}${ansiAwareRightPad(term, termWidth)} ${entry.description == null ? "" : indentLines(formatMessage(entry.description, {
|
|
77
|
+
colors: options.colors,
|
|
78
|
+
quotes: !options.colors,
|
|
79
|
+
maxWidth: options.maxWidth == null ? void 0 : options.maxWidth - termIndent - termWidth - 2
|
|
80
|
+
}), termIndent + termWidth + 2)}\n`;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (page.footer != null) {
|
|
84
|
+
output += "\n";
|
|
85
|
+
output += formatMessage(page.footer, {
|
|
86
|
+
colors: options.colors,
|
|
87
|
+
maxWidth: options.maxWidth,
|
|
88
|
+
quotes: !options.colors
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return output;
|
|
92
|
+
}
|
|
93
|
+
function indentLines(text, indent) {
|
|
94
|
+
return text.split("\n").join("\n" + " ".repeat(indent));
|
|
95
|
+
}
|
|
96
|
+
function ansiAwareRightPad(text, length, char = " ") {
|
|
97
|
+
const ansiEscapeCodeRegex = /\x1B\[[0-9;]*[a-zA-Z]/g;
|
|
98
|
+
const strippedText = text.replace(ansiEscapeCodeRegex, "");
|
|
99
|
+
if (strippedText.length >= length) return text;
|
|
100
|
+
return text + char.repeat(length - strippedText.length);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
//#endregion
|
|
104
|
+
export { formatDocPage };
|
package/dist/facade.cjs
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
const require_message = require('./message.cjs');
|
|
2
|
+
const require_usage = require('./usage.cjs');
|
|
3
|
+
const require_doc = require('./doc.cjs');
|
|
4
|
+
const require_valueparser = require('./valueparser.cjs');
|
|
5
|
+
const require_parser = require('./parser.cjs');
|
|
6
|
+
|
|
7
|
+
//#region src/facade.ts
|
|
8
|
+
/**
|
|
9
|
+
* Runs a parser against command-line arguments with built-in help and error
|
|
10
|
+
* handling.
|
|
11
|
+
*
|
|
12
|
+
* This function provides a complete CLI interface by automatically handling
|
|
13
|
+
* help commands/options and displaying formatted error messages with usage
|
|
14
|
+
* information when parsing fails. It augments the provided parser with help
|
|
15
|
+
* functionality based on the configuration options.
|
|
16
|
+
*
|
|
17
|
+
* The function will:
|
|
18
|
+
*
|
|
19
|
+
* 1. Add help command/option support (unless disabled)
|
|
20
|
+
* 2. Parse the provided arguments
|
|
21
|
+
* 3. Display help if requested
|
|
22
|
+
* 4. Show formatted error messages with usage/help info on parse failures
|
|
23
|
+
* 5. Return the parsed result or invoke the appropriate callback
|
|
24
|
+
*
|
|
25
|
+
* @template TParser The parser type being run.
|
|
26
|
+
* @template THelp Return type when help is shown (defaults to `void`).
|
|
27
|
+
* @template TError Return type when an error occurs (defaults to `never`).
|
|
28
|
+
* @param parser The parser to run against the command-line arguments.
|
|
29
|
+
* @param programName Name of the program used in usage and help output.
|
|
30
|
+
* @param args Command-line arguments to parse (typically from
|
|
31
|
+
* `process.argv.slice(2)` on Node.js or `Deno.args` on Deno).
|
|
32
|
+
* @param options Configuration options for output formatting and callbacks.
|
|
33
|
+
* @returns The parsed result value, or the return value of `onHelp`/`onError`
|
|
34
|
+
* callbacks.
|
|
35
|
+
* @throws {RunError} When parsing fails and no `onError` callback is provided.
|
|
36
|
+
*/
|
|
37
|
+
function run(parser, programName, args, options = {}) {
|
|
38
|
+
let { colors, maxWidth, help = "none", onHelp = () => {}, aboveError = "usage", onError = () => {
|
|
39
|
+
throw new RunError("Failed to parse command line arguments.");
|
|
40
|
+
}, stderr = console.error, stdout = console.log } = options;
|
|
41
|
+
const helpCommand = require_parser.command("help", require_parser.multiple(require_parser.argument(require_valueparser.string({ metavar: "COMMAND" }))), { description: require_message.message`Show help information.` });
|
|
42
|
+
const helpOption = require_parser.option("--help", { description: require_message.message`Show help information.` });
|
|
43
|
+
const augmentedParser = help === "none" ? require_parser.object({
|
|
44
|
+
help: require_parser.constant(false),
|
|
45
|
+
result: parser
|
|
46
|
+
}) : require_parser.or(require_parser.object({
|
|
47
|
+
help: require_parser.constant(false),
|
|
48
|
+
result: parser
|
|
49
|
+
}), require_parser.object({
|
|
50
|
+
help: require_parser.constant(true),
|
|
51
|
+
command: help === "both" ? require_parser.or(helpCommand, helpOption) : help === "command" ? helpCommand : helpOption
|
|
52
|
+
}));
|
|
53
|
+
const result = require_parser.parse(augmentedParser, args);
|
|
54
|
+
if (result.success) {
|
|
55
|
+
if (!result.value.help) return result.value.result;
|
|
56
|
+
const doc = require_parser.getDocPage(typeof result.value.command === "boolean" || result.value.command.length < 1 ? augmentedParser : parser, typeof result.value.command === "boolean" ? [] : result.value.command);
|
|
57
|
+
if (doc != null) stdout(require_doc.formatDocPage(programName, doc, {
|
|
58
|
+
colors,
|
|
59
|
+
maxWidth
|
|
60
|
+
}));
|
|
61
|
+
return onHelp(0);
|
|
62
|
+
}
|
|
63
|
+
if (aboveError === "help") {
|
|
64
|
+
const doc = require_parser.getDocPage(args.length < 1 ? augmentedParser : parser, args);
|
|
65
|
+
if (doc == null) aboveError = "usage";
|
|
66
|
+
else stderr(require_doc.formatDocPage(programName, doc, {
|
|
67
|
+
colors,
|
|
68
|
+
maxWidth
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
if (aboveError === "usage") stderr(`Usage: ${indentLines(require_usage.formatUsage(programName, augmentedParser.usage, {
|
|
72
|
+
colors,
|
|
73
|
+
maxWidth: maxWidth == null ? void 0 : maxWidth - 7,
|
|
74
|
+
expandCommands: true
|
|
75
|
+
}), 7)}`);
|
|
76
|
+
stderr(`Error: ${require_message.formatMessage(result.error, {
|
|
77
|
+
colors,
|
|
78
|
+
quotes: !colors
|
|
79
|
+
})}`);
|
|
80
|
+
return onError(1);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* An error class used to indicate that the command line arguments
|
|
84
|
+
* could not be parsed successfully.
|
|
85
|
+
*/
|
|
86
|
+
var RunError = class extends Error {
|
|
87
|
+
constructor(message$1) {
|
|
88
|
+
super(message$1);
|
|
89
|
+
this.name = "RunError";
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
function indentLines(text, indent) {
|
|
93
|
+
return text.split("\n").join("\n" + " ".repeat(indent));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
//#endregion
|
|
97
|
+
exports.RunError = RunError;
|
|
98
|
+
exports.run = run;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { InferValue, Parser } from "./parser.cjs";
|
|
2
|
+
|
|
3
|
+
//#region src/facade.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Configuration options for the {@link run} function.
|
|
7
|
+
*
|
|
8
|
+
* @template THelp The return type when help is shown.
|
|
9
|
+
* @template TError The return type when an error occurs.
|
|
10
|
+
*/
|
|
11
|
+
interface RunOptions<THelp, TError> {
|
|
12
|
+
/**
|
|
13
|
+
* Enable colored output in help and error messages.
|
|
14
|
+
*
|
|
15
|
+
* @default `false`
|
|
16
|
+
*/
|
|
17
|
+
readonly colors?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Maximum width for output formatting. Text will be wrapped to fit within
|
|
20
|
+
* this width. If not specified, text will not be wrapped.
|
|
21
|
+
*/
|
|
22
|
+
readonly maxWidth?: number;
|
|
23
|
+
/**
|
|
24
|
+
* Determines how help is made available:
|
|
25
|
+
*
|
|
26
|
+
* - `"command"`: Only the `help` subcommand is available
|
|
27
|
+
* - `"option"`: Only the `--help` option is available
|
|
28
|
+
* - `"both"`: Both `help` subcommand and `--help` option are available
|
|
29
|
+
* - `"none"`: No help functionality is provided
|
|
30
|
+
*
|
|
31
|
+
* @default `"none"`
|
|
32
|
+
*/
|
|
33
|
+
readonly help?: "command" | "option" | "both" | "none";
|
|
34
|
+
/**
|
|
35
|
+
* Callback function invoked when help is requested. The function can
|
|
36
|
+
* optionally receive an exit code parameter.
|
|
37
|
+
*
|
|
38
|
+
* You usually want to pass `process.exit` on Node.js or Bun and `Deno.exit`
|
|
39
|
+
* on Deno to this option.
|
|
40
|
+
*
|
|
41
|
+
* @default Returns `void` when help is shown.
|
|
42
|
+
*/
|
|
43
|
+
readonly onHelp?: (() => THelp) | ((exitCode: number) => THelp);
|
|
44
|
+
/**
|
|
45
|
+
* What to display above error messages:
|
|
46
|
+
* - `"usage"`: Show usage information
|
|
47
|
+
* - `"help"`: Show help text (if available)
|
|
48
|
+
* - `"none"`: Show nothing above errors
|
|
49
|
+
*
|
|
50
|
+
* @default `"usage"`
|
|
51
|
+
*/
|
|
52
|
+
readonly aboveError?: "usage" | "help" | "none";
|
|
53
|
+
/**
|
|
54
|
+
* Callback function invoked when parsing fails. The function can
|
|
55
|
+
* optionally receive an exit code parameter.
|
|
56
|
+
*
|
|
57
|
+
* You usually want to pass `process.exit` on Node.js or Bun and `Deno.exit`
|
|
58
|
+
* on Deno to this option.
|
|
59
|
+
* @default Throws a {@link RunError}.
|
|
60
|
+
*/
|
|
61
|
+
readonly onError?: (() => TError) | ((exitCode: number) => TError);
|
|
62
|
+
/**
|
|
63
|
+
* Function used to output error messages.
|
|
64
|
+
*
|
|
65
|
+
* @default `console.error`
|
|
66
|
+
*/
|
|
67
|
+
readonly stderr?: (text: string) => void;
|
|
68
|
+
/**
|
|
69
|
+
* Function used to output help and usage messages.
|
|
70
|
+
*
|
|
71
|
+
* @default `console.log`
|
|
72
|
+
*/
|
|
73
|
+
readonly stdout?: (text: string) => void;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Runs a parser against command-line arguments with built-in help and error
|
|
77
|
+
* handling.
|
|
78
|
+
*
|
|
79
|
+
* This function provides a complete CLI interface by automatically handling
|
|
80
|
+
* help commands/options and displaying formatted error messages with usage
|
|
81
|
+
* information when parsing fails. It augments the provided parser with help
|
|
82
|
+
* functionality based on the configuration options.
|
|
83
|
+
*
|
|
84
|
+
* The function will:
|
|
85
|
+
*
|
|
86
|
+
* 1. Add help command/option support (unless disabled)
|
|
87
|
+
* 2. Parse the provided arguments
|
|
88
|
+
* 3. Display help if requested
|
|
89
|
+
* 4. Show formatted error messages with usage/help info on parse failures
|
|
90
|
+
* 5. Return the parsed result or invoke the appropriate callback
|
|
91
|
+
*
|
|
92
|
+
* @template TParser The parser type being run.
|
|
93
|
+
* @template THelp Return type when help is shown (defaults to `void`).
|
|
94
|
+
* @template TError Return type when an error occurs (defaults to `never`).
|
|
95
|
+
* @param parser The parser to run against the command-line arguments.
|
|
96
|
+
* @param programName Name of the program used in usage and help output.
|
|
97
|
+
* @param args Command-line arguments to parse (typically from
|
|
98
|
+
* `process.argv.slice(2)` on Node.js or `Deno.args` on Deno).
|
|
99
|
+
* @param options Configuration options for output formatting and callbacks.
|
|
100
|
+
* @returns The parsed result value, or the return value of `onHelp`/`onError`
|
|
101
|
+
* callbacks.
|
|
102
|
+
* @throws {RunError} When parsing fails and no `onError` callback is provided.
|
|
103
|
+
*/
|
|
104
|
+
declare function run<TParser extends Parser<unknown, unknown>, THelp = void, TError = never>(parser: TParser, programName: string, args: readonly string[], options?: RunOptions<THelp, TError>): InferValue<TParser>;
|
|
105
|
+
/**
|
|
106
|
+
* An error class used to indicate that the command line arguments
|
|
107
|
+
* could not be parsed successfully.
|
|
108
|
+
*/
|
|
109
|
+
declare class RunError extends Error {
|
|
110
|
+
constructor(message: string);
|
|
111
|
+
}
|
|
112
|
+
//#endregion
|
|
113
|
+
export { RunError, RunOptions, run };
|
package/dist/facade.d.ts
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { InferValue, Parser } from "./parser.js";
|
|
2
|
+
|
|
3
|
+
//#region src/facade.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Configuration options for the {@link run} function.
|
|
7
|
+
*
|
|
8
|
+
* @template THelp The return type when help is shown.
|
|
9
|
+
* @template TError The return type when an error occurs.
|
|
10
|
+
*/
|
|
11
|
+
interface RunOptions<THelp, TError> {
|
|
12
|
+
/**
|
|
13
|
+
* Enable colored output in help and error messages.
|
|
14
|
+
*
|
|
15
|
+
* @default `false`
|
|
16
|
+
*/
|
|
17
|
+
readonly colors?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Maximum width for output formatting. Text will be wrapped to fit within
|
|
20
|
+
* this width. If not specified, text will not be wrapped.
|
|
21
|
+
*/
|
|
22
|
+
readonly maxWidth?: number;
|
|
23
|
+
/**
|
|
24
|
+
* Determines how help is made available:
|
|
25
|
+
*
|
|
26
|
+
* - `"command"`: Only the `help` subcommand is available
|
|
27
|
+
* - `"option"`: Only the `--help` option is available
|
|
28
|
+
* - `"both"`: Both `help` subcommand and `--help` option are available
|
|
29
|
+
* - `"none"`: No help functionality is provided
|
|
30
|
+
*
|
|
31
|
+
* @default `"none"`
|
|
32
|
+
*/
|
|
33
|
+
readonly help?: "command" | "option" | "both" | "none";
|
|
34
|
+
/**
|
|
35
|
+
* Callback function invoked when help is requested. The function can
|
|
36
|
+
* optionally receive an exit code parameter.
|
|
37
|
+
*
|
|
38
|
+
* You usually want to pass `process.exit` on Node.js or Bun and `Deno.exit`
|
|
39
|
+
* on Deno to this option.
|
|
40
|
+
*
|
|
41
|
+
* @default Returns `void` when help is shown.
|
|
42
|
+
*/
|
|
43
|
+
readonly onHelp?: (() => THelp) | ((exitCode: number) => THelp);
|
|
44
|
+
/**
|
|
45
|
+
* What to display above error messages:
|
|
46
|
+
* - `"usage"`: Show usage information
|
|
47
|
+
* - `"help"`: Show help text (if available)
|
|
48
|
+
* - `"none"`: Show nothing above errors
|
|
49
|
+
*
|
|
50
|
+
* @default `"usage"`
|
|
51
|
+
*/
|
|
52
|
+
readonly aboveError?: "usage" | "help" | "none";
|
|
53
|
+
/**
|
|
54
|
+
* Callback function invoked when parsing fails. The function can
|
|
55
|
+
* optionally receive an exit code parameter.
|
|
56
|
+
*
|
|
57
|
+
* You usually want to pass `process.exit` on Node.js or Bun and `Deno.exit`
|
|
58
|
+
* on Deno to this option.
|
|
59
|
+
* @default Throws a {@link RunError}.
|
|
60
|
+
*/
|
|
61
|
+
readonly onError?: (() => TError) | ((exitCode: number) => TError);
|
|
62
|
+
/**
|
|
63
|
+
* Function used to output error messages.
|
|
64
|
+
*
|
|
65
|
+
* @default `console.error`
|
|
66
|
+
*/
|
|
67
|
+
readonly stderr?: (text: string) => void;
|
|
68
|
+
/**
|
|
69
|
+
* Function used to output help and usage messages.
|
|
70
|
+
*
|
|
71
|
+
* @default `console.log`
|
|
72
|
+
*/
|
|
73
|
+
readonly stdout?: (text: string) => void;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Runs a parser against command-line arguments with built-in help and error
|
|
77
|
+
* handling.
|
|
78
|
+
*
|
|
79
|
+
* This function provides a complete CLI interface by automatically handling
|
|
80
|
+
* help commands/options and displaying formatted error messages with usage
|
|
81
|
+
* information when parsing fails. It augments the provided parser with help
|
|
82
|
+
* functionality based on the configuration options.
|
|
83
|
+
*
|
|
84
|
+
* The function will:
|
|
85
|
+
*
|
|
86
|
+
* 1. Add help command/option support (unless disabled)
|
|
87
|
+
* 2. Parse the provided arguments
|
|
88
|
+
* 3. Display help if requested
|
|
89
|
+
* 4. Show formatted error messages with usage/help info on parse failures
|
|
90
|
+
* 5. Return the parsed result or invoke the appropriate callback
|
|
91
|
+
*
|
|
92
|
+
* @template TParser The parser type being run.
|
|
93
|
+
* @template THelp Return type when help is shown (defaults to `void`).
|
|
94
|
+
* @template TError Return type when an error occurs (defaults to `never`).
|
|
95
|
+
* @param parser The parser to run against the command-line arguments.
|
|
96
|
+
* @param programName Name of the program used in usage and help output.
|
|
97
|
+
* @param args Command-line arguments to parse (typically from
|
|
98
|
+
* `process.argv.slice(2)` on Node.js or `Deno.args` on Deno).
|
|
99
|
+
* @param options Configuration options for output formatting and callbacks.
|
|
100
|
+
* @returns The parsed result value, or the return value of `onHelp`/`onError`
|
|
101
|
+
* callbacks.
|
|
102
|
+
* @throws {RunError} When parsing fails and no `onError` callback is provided.
|
|
103
|
+
*/
|
|
104
|
+
declare function run<TParser extends Parser<unknown, unknown>, THelp = void, TError = never>(parser: TParser, programName: string, args: readonly string[], options?: RunOptions<THelp, TError>): InferValue<TParser>;
|
|
105
|
+
/**
|
|
106
|
+
* An error class used to indicate that the command line arguments
|
|
107
|
+
* could not be parsed successfully.
|
|
108
|
+
*/
|
|
109
|
+
declare class RunError extends Error {
|
|
110
|
+
constructor(message: string);
|
|
111
|
+
}
|
|
112
|
+
//#endregion
|
|
113
|
+
export { RunError, RunOptions, run };
|
package/dist/facade.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { formatMessage, message } from "./message.js";
|
|
2
|
+
import { formatUsage } from "./usage.js";
|
|
3
|
+
import { formatDocPage } from "./doc.js";
|
|
4
|
+
import { string } from "./valueparser.js";
|
|
5
|
+
import { argument, command, constant, getDocPage, multiple, object, option, or, parse } from "./parser.js";
|
|
6
|
+
|
|
7
|
+
//#region src/facade.ts
|
|
8
|
+
/**
|
|
9
|
+
* Runs a parser against command-line arguments with built-in help and error
|
|
10
|
+
* handling.
|
|
11
|
+
*
|
|
12
|
+
* This function provides a complete CLI interface by automatically handling
|
|
13
|
+
* help commands/options and displaying formatted error messages with usage
|
|
14
|
+
* information when parsing fails. It augments the provided parser with help
|
|
15
|
+
* functionality based on the configuration options.
|
|
16
|
+
*
|
|
17
|
+
* The function will:
|
|
18
|
+
*
|
|
19
|
+
* 1. Add help command/option support (unless disabled)
|
|
20
|
+
* 2. Parse the provided arguments
|
|
21
|
+
* 3. Display help if requested
|
|
22
|
+
* 4. Show formatted error messages with usage/help info on parse failures
|
|
23
|
+
* 5. Return the parsed result or invoke the appropriate callback
|
|
24
|
+
*
|
|
25
|
+
* @template TParser The parser type being run.
|
|
26
|
+
* @template THelp Return type when help is shown (defaults to `void`).
|
|
27
|
+
* @template TError Return type when an error occurs (defaults to `never`).
|
|
28
|
+
* @param parser The parser to run against the command-line arguments.
|
|
29
|
+
* @param programName Name of the program used in usage and help output.
|
|
30
|
+
* @param args Command-line arguments to parse (typically from
|
|
31
|
+
* `process.argv.slice(2)` on Node.js or `Deno.args` on Deno).
|
|
32
|
+
* @param options Configuration options for output formatting and callbacks.
|
|
33
|
+
* @returns The parsed result value, or the return value of `onHelp`/`onError`
|
|
34
|
+
* callbacks.
|
|
35
|
+
* @throws {RunError} When parsing fails and no `onError` callback is provided.
|
|
36
|
+
*/
|
|
37
|
+
function run(parser, programName, args, options = {}) {
|
|
38
|
+
let { colors, maxWidth, help = "none", onHelp = () => {}, aboveError = "usage", onError = () => {
|
|
39
|
+
throw new RunError("Failed to parse command line arguments.");
|
|
40
|
+
}, stderr = console.error, stdout = console.log } = options;
|
|
41
|
+
const helpCommand = command("help", multiple(argument(string({ metavar: "COMMAND" }))), { description: message`Show help information.` });
|
|
42
|
+
const helpOption = option("--help", { description: message`Show help information.` });
|
|
43
|
+
const augmentedParser = help === "none" ? object({
|
|
44
|
+
help: constant(false),
|
|
45
|
+
result: parser
|
|
46
|
+
}) : or(object({
|
|
47
|
+
help: constant(false),
|
|
48
|
+
result: parser
|
|
49
|
+
}), object({
|
|
50
|
+
help: constant(true),
|
|
51
|
+
command: help === "both" ? or(helpCommand, helpOption) : help === "command" ? helpCommand : helpOption
|
|
52
|
+
}));
|
|
53
|
+
const result = parse(augmentedParser, args);
|
|
54
|
+
if (result.success) {
|
|
55
|
+
if (!result.value.help) return result.value.result;
|
|
56
|
+
const doc = getDocPage(typeof result.value.command === "boolean" || result.value.command.length < 1 ? augmentedParser : parser, typeof result.value.command === "boolean" ? [] : result.value.command);
|
|
57
|
+
if (doc != null) stdout(formatDocPage(programName, doc, {
|
|
58
|
+
colors,
|
|
59
|
+
maxWidth
|
|
60
|
+
}));
|
|
61
|
+
return onHelp(0);
|
|
62
|
+
}
|
|
63
|
+
if (aboveError === "help") {
|
|
64
|
+
const doc = getDocPage(args.length < 1 ? augmentedParser : parser, args);
|
|
65
|
+
if (doc == null) aboveError = "usage";
|
|
66
|
+
else stderr(formatDocPage(programName, doc, {
|
|
67
|
+
colors,
|
|
68
|
+
maxWidth
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
if (aboveError === "usage") stderr(`Usage: ${indentLines(formatUsage(programName, augmentedParser.usage, {
|
|
72
|
+
colors,
|
|
73
|
+
maxWidth: maxWidth == null ? void 0 : maxWidth - 7,
|
|
74
|
+
expandCommands: true
|
|
75
|
+
}), 7)}`);
|
|
76
|
+
stderr(`Error: ${formatMessage(result.error, {
|
|
77
|
+
colors,
|
|
78
|
+
quotes: !colors
|
|
79
|
+
})}`);
|
|
80
|
+
return onError(1);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* An error class used to indicate that the command line arguments
|
|
84
|
+
* could not be parsed successfully.
|
|
85
|
+
*/
|
|
86
|
+
var RunError = class extends Error {
|
|
87
|
+
constructor(message$1) {
|
|
88
|
+
super(message$1);
|
|
89
|
+
this.name = "RunError";
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
function indentLines(text, indent) {
|
|
93
|
+
return text.split("\n").join("\n" + " ".repeat(indent));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
//#endregion
|
|
97
|
+
export { RunError, run };
|