burgee 0.3.0 → 0.4.0
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/LICENSE +21 -0
- package/README.md +61 -9
- package/dist/brand.d.ts +62 -1
- package/dist/brand.js +73 -7
- package/dist/{commander-argument.js → commander/argument.js} +4 -1
- package/dist/{commander-command.d.ts → commander/command.d.ts} +5 -5
- package/dist/{commander-command.js → commander/command.js} +159 -22
- package/dist/{commander-error.js → commander/error.js} +2 -0
- package/dist/{commander-help.d.ts → commander/help.d.ts} +3 -3
- package/dist/{commander-help.js → commander/help.js} +18 -1
- package/dist/{commander-option.d.ts → commander/option.d.ts} +1 -1
- package/dist/{commander-option.js → commander/option.js} +15 -1
- package/dist/commander.d.ts +8 -8
- package/dist/commander.js +8 -8
- package/dist/completions.js +15 -4
- package/dist/execute.js +39 -24
- package/dist/schema.d.ts +2 -0
- package/dist/schema.js +3 -0
- package/dist/unknown-option.d.ts +9 -0
- package/dist/unknown-option.js +27 -0
- package/dist/{yargs-burgee.d.ts → yargs/burgee.d.ts} +2 -2
- package/dist/{yargs-burgee.js → yargs/burgee.js} +15 -1
- package/dist/{yargs-cliui.js → yargs/cliui.js} +8 -0
- package/dist/{yargs-command.d.ts → yargs/command.d.ts} +5 -5
- package/dist/{yargs-command.js → yargs/command.js} +9 -2
- package/dist/{yargs-completion.d.ts → yargs/completion.d.ts} +3 -3
- package/dist/{yargs-completion.js → yargs/completion.js} +7 -2
- package/dist/{yargs-factory.d.ts → yargs/factory.d.ts} +8 -8
- package/dist/{yargs-factory.js → yargs/factory.js} +63 -13
- package/dist/{yargs-middleware.js → yargs/middleware.js} +6 -1
- package/dist/{yargs-shim.d.ts → yargs/shim.d.ts} +3 -3
- package/dist/{yargs-shim.js → yargs/shim.js} +24 -5
- package/dist/{yargs-usage.d.ts → yargs/usage.d.ts} +1 -1
- package/dist/{yargs-usage.js → yargs/usage.js} +9 -1
- package/dist/{yargs-utils.js → yargs/utils.js} +11 -0
- package/dist/{yargs-validation.d.ts → yargs/validation.d.ts} +1 -1
- package/dist/{yargs-validation.js → yargs/validation.js} +7 -1
- package/dist/{yargs-y18n.js → yargs/y18n.js} +6 -0
- package/dist/yargs-helpers.d.ts +1 -1
- package/dist/yargs-helpers.js +1 -1
- package/dist/yargs.d.ts +4 -4
- package/dist/yargs.js +5 -5
- package/package.json +2 -1
- /package/dist/{commander-argument.d.ts → commander/argument.d.ts} +0 -0
- /package/dist/{commander-error.d.ts → commander/error.d.ts} +0 -0
- /package/dist/{commander-suggest.d.ts → suggest.d.ts} +0 -0
- /package/dist/{commander-suggest.js → suggest.js} +0 -0
- /package/dist/{yargs-cliui.d.ts → yargs/cliui.d.ts} +0 -0
- /package/dist/{yargs-middleware.d.ts → yargs/middleware.d.ts} +0 -0
- /package/dist/{yargs-utils.d.ts → yargs/utils.d.ts} +0 -0
- /package/dist/{yargs-y18n.d.ts → yargs/y18n.d.ts} +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/** commander's error classes, byte-for-byte in shape: `code`, `exitCode`, `nestedError`. */
|
|
1
2
|
export class CommanderError extends Error {
|
|
2
3
|
code;
|
|
3
4
|
exitCode;
|
|
@@ -18,3 +19,4 @@ export class InvalidArgumentError extends CommanderError {
|
|
|
18
19
|
this.name = this.constructor.name;
|
|
19
20
|
}
|
|
20
21
|
}
|
|
22
|
+
//# sourceMappingURL=error.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { type Argument } from './
|
|
2
|
-
import type { Command } from './
|
|
3
|
-
import type { Option } from './
|
|
1
|
+
import { type Argument } from './argument.js';
|
|
2
|
+
import type { Command } from './command.js';
|
|
3
|
+
import type { Option } from './option.js';
|
|
4
4
|
export interface HelpContext {
|
|
5
5
|
error?: boolean;
|
|
6
6
|
helpWidth?: number;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { stripVTControlCharacters } from 'node:util';
|
|
2
|
-
import { humanReadableArgName } from './
|
|
2
|
+
import { humanReadableArgName } from './argument.js';
|
|
3
|
+
/** Methods are static in style so a subclass, or plain functions via `configureHelp`, can override them. */
|
|
3
4
|
export class Help {
|
|
4
5
|
helpWidth = undefined;
|
|
5
6
|
minWidthToWrap = 40;
|
|
6
7
|
sortSubcommands = false;
|
|
7
8
|
sortOptions = false;
|
|
8
9
|
showGlobalOptions = false;
|
|
10
|
+
/** Called after `configureHelp` overrides are applied and just before `formatHelp`. */
|
|
9
11
|
prepareContext(contextOptions) {
|
|
10
12
|
this.helpWidth = this.helpWidth ?? contextOptions.helpWidth ?? 80;
|
|
11
13
|
}
|
|
@@ -26,6 +28,7 @@ export class Help {
|
|
|
26
28
|
const visibleOptions = cmd.options.filter((option) => !option.hidden);
|
|
27
29
|
const helpOption = cmd._getHelpOption();
|
|
28
30
|
if (helpOption && !helpOption.hidden) {
|
|
31
|
+
// Historical: hide the built-in help flags a user option already took.
|
|
29
32
|
const removeShort = helpOption.short && cmd._findOption(helpOption.short);
|
|
30
33
|
const removeLong = helpOption.long && cmd._findOption(helpOption.long);
|
|
31
34
|
if (!removeShort && !removeLong)
|
|
@@ -51,6 +54,7 @@ export class Help {
|
|
|
51
54
|
return globalOptions;
|
|
52
55
|
}
|
|
53
56
|
visibleArguments(cmd) {
|
|
57
|
+
// Side effect: apply the legacy descriptions before the arguments are displayed.
|
|
54
58
|
if (cmd._argsDescription) {
|
|
55
59
|
for (const argument of cmd.registeredArguments) {
|
|
56
60
|
argument.description = argument.description || cmd._argsDescription[argument.name()] || '';
|
|
@@ -106,6 +110,7 @@ export class Help {
|
|
|
106
110
|
commandDescription(cmd) {
|
|
107
111
|
return cmd.description();
|
|
108
112
|
}
|
|
113
|
+
/** Summary, falling back to description for backwards compatibility. */
|
|
109
114
|
subcommandDescription(cmd) {
|
|
110
115
|
return cmd.summary() || cmd.description();
|
|
111
116
|
}
|
|
@@ -115,6 +120,7 @@ export class Help {
|
|
|
115
120
|
extraInfo.push(`choices: ${option.argChoices.map((choice) => JSON.stringify(choice)).join(', ')}`);
|
|
116
121
|
}
|
|
117
122
|
if (option.defaultValue !== undefined) {
|
|
123
|
+
// Defaults for boolean and negated are more for the programmer than the end user.
|
|
118
124
|
const showDefault = option.required || option.optional || (option.isBoolean() && typeof option.defaultValue === 'boolean');
|
|
119
125
|
if (showDefault)
|
|
120
126
|
extraInfo.push(`default: ${option.defaultValueDescription || JSON.stringify(option.defaultValue)}`);
|
|
@@ -148,6 +154,7 @@ export class Help {
|
|
|
148
154
|
return [];
|
|
149
155
|
return [helper.styleTitle(heading), ...items, ''];
|
|
150
156
|
}
|
|
157
|
+
/** Groups in order of first appearance among all items; members in order of the visible items. */
|
|
151
158
|
groupItems(unsortedItems, visibleItems, getGroup) {
|
|
152
159
|
const result = new Map();
|
|
153
160
|
for (const item of unsortedItems) {
|
|
@@ -196,6 +203,7 @@ export class Help {
|
|
|
196
203
|
}
|
|
197
204
|
return output.join('\n');
|
|
198
205
|
}
|
|
206
|
+
/** Width ignoring ANSI escapes, for padding and wrapping. */
|
|
199
207
|
displayWidth(str) {
|
|
200
208
|
return stripVTControlCharacters(str).length;
|
|
201
209
|
}
|
|
@@ -203,6 +211,7 @@ export class Help {
|
|
|
203
211
|
return str;
|
|
204
212
|
}
|
|
205
213
|
styleUsage(str) {
|
|
214
|
+
// Assume the default usage shape: command subcommand [options] [command] <foo> [bar]
|
|
206
215
|
return str
|
|
207
216
|
.split(' ')
|
|
208
217
|
.map((word) => {
|
|
@@ -264,9 +273,15 @@ export class Help {
|
|
|
264
273
|
padWidth(cmd, helper) {
|
|
265
274
|
return Math.max(helper.longestOptionTermLength(cmd, helper), helper.longestGlobalOptionTermLength(cmd, helper), helper.longestSubcommandTermLength(cmd, helper), helper.longestArgumentTermLength(cmd, helper));
|
|
266
275
|
}
|
|
276
|
+
/** Manually wrapped text: a line break followed by whitespace. */
|
|
267
277
|
preformatted(str) {
|
|
268
278
|
return /\n[^\S\r\n]/.test(str);
|
|
269
279
|
}
|
|
280
|
+
/**
|
|
281
|
+
* Pad the term and wrap the description, indenting the following lines:
|
|
282
|
+
* TTT DDD DDDD
|
|
283
|
+
* DD DDD
|
|
284
|
+
*/
|
|
270
285
|
formatItem(term, termWidth, description, helper) {
|
|
271
286
|
const itemIndent = 2;
|
|
272
287
|
const itemIndentStr = ' '.repeat(itemIndent);
|
|
@@ -286,6 +301,7 @@ export class Help {
|
|
|
286
301
|
}
|
|
287
302
|
return itemIndentStr + paddedTerm + ' '.repeat(spacerWidth) + formattedDescription.replace(/\n/g, `\n${itemIndentStr}`);
|
|
288
303
|
}
|
|
304
|
+
/** Wrap at whitespace, preserving existing line breaks; skipped below `minWidthToWrap`. */
|
|
289
305
|
boxWrap(str, width) {
|
|
290
306
|
if (width < this.minWidthToWrap)
|
|
291
307
|
return str;
|
|
@@ -317,3 +333,4 @@ export class Help {
|
|
|
317
333
|
return wrappedLines.join('\n');
|
|
318
334
|
}
|
|
319
335
|
}
|
|
336
|
+
//# sourceMappingURL=help.js.map
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {} from './argument.js';
|
|
2
|
+
import { InvalidArgumentError } from './error.js';
|
|
2
3
|
export class Option {
|
|
3
4
|
flags;
|
|
4
5
|
description;
|
|
@@ -24,6 +25,7 @@ export class Option {
|
|
|
24
25
|
this.description = description || '';
|
|
25
26
|
this.required = flags.includes('<');
|
|
26
27
|
this.optional = flags.includes('[');
|
|
28
|
+
// `<value,...>` describes custom splitting of one argument, not a variadic option.
|
|
27
29
|
this.variadic = /\w\.\.\.[>\]]$/.test(flags);
|
|
28
30
|
const { shortFlag, longFlag } = splitOptionFlags(flags);
|
|
29
31
|
this.short = shortFlag;
|
|
@@ -36,6 +38,7 @@ export class Option {
|
|
|
36
38
|
this.defaultValueDescription = description;
|
|
37
39
|
return this;
|
|
38
40
|
}
|
|
41
|
+
/** Value used when the option appears without an option-argument. `parseArg` still runs. */
|
|
39
42
|
preset(arg) {
|
|
40
43
|
this.presetArg = arg;
|
|
41
44
|
return this;
|
|
@@ -44,6 +47,7 @@ export class Option {
|
|
|
44
47
|
this.conflictsWith = this.conflictsWith.concat(names);
|
|
45
48
|
return this;
|
|
46
49
|
}
|
|
50
|
+
/** Values implied for other options when this one is set and they are not. `parseArg` does not run on them. */
|
|
47
51
|
implies(impliedOptionValues) {
|
|
48
52
|
const newImplied = typeof impliedOptionValues === 'string' ? { [impliedOptionValues]: true } : impliedOptionValues;
|
|
49
53
|
this.implied = Object.assign(this.implied ?? {}, newImplied);
|
|
@@ -86,6 +90,7 @@ export class Option {
|
|
|
86
90
|
return this.long.replace(/^--/, '');
|
|
87
91
|
return (this.short ?? '').replace(/^-/, '');
|
|
88
92
|
}
|
|
93
|
+
/** camelCase key used on the options object; `--no-foo` shares `foo` with `--foo`. */
|
|
89
94
|
attributeName() {
|
|
90
95
|
return camelcase(this.negate ? this.name().replace(/^no-/, '') : this.name());
|
|
91
96
|
}
|
|
@@ -96,10 +101,15 @@ export class Option {
|
|
|
96
101
|
is(arg) {
|
|
97
102
|
return this.short === arg || this.long === arg;
|
|
98
103
|
}
|
|
104
|
+
/** Options are one of boolean, negated, required-argument or optional-argument. */
|
|
99
105
|
isBoolean() {
|
|
100
106
|
return !this.required && !this.optional && !this.negate;
|
|
101
107
|
}
|
|
102
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* `--build` and `--no-build` share one value. This works out which of the pair a
|
|
111
|
+
* value (probably) came from, so implied values are only applied for the right one.
|
|
112
|
+
*/
|
|
103
113
|
export class DualOptions {
|
|
104
114
|
positiveOptions = new Map();
|
|
105
115
|
negativeOptions = new Map();
|
|
@@ -125,6 +135,7 @@ export class DualOptions {
|
|
|
125
135
|
function camelcase(str) {
|
|
126
136
|
return str.split('-').reduce((acc, word) => acc + (word[0] ?? '').toUpperCase() + word.slice(1));
|
|
127
137
|
}
|
|
138
|
+
/** Split `'-m,--mixed <value>'` into its short and long flags, failing noisily on anything else. */
|
|
128
139
|
export function splitOptionFlags(flags) {
|
|
129
140
|
let shortFlag;
|
|
130
141
|
let longFlag;
|
|
@@ -136,8 +147,10 @@ export function splitOptionFlags(flags) {
|
|
|
136
147
|
shortFlag = flagParts.shift();
|
|
137
148
|
if (longFlagExp.test(head()))
|
|
138
149
|
longFlag = flagParts.shift();
|
|
150
|
+
// Long then short. Rarely used but fine.
|
|
139
151
|
if (!shortFlag && shortFlagExp.test(head()))
|
|
140
152
|
shortFlag = flagParts.shift();
|
|
153
|
+
// Two long flags, like '--ws, --workspace': the supported way to have a shortish flag.
|
|
141
154
|
if (!shortFlag && longFlagExp.test(head())) {
|
|
142
155
|
shortFlag = longFlag;
|
|
143
156
|
longFlag = flagParts.shift();
|
|
@@ -162,3 +175,4 @@ export function splitOptionFlags(flags) {
|
|
|
162
175
|
}
|
|
163
176
|
return { shortFlag, longFlag };
|
|
164
177
|
}
|
|
178
|
+
//# sourceMappingURL=option.js.map
|
package/dist/commander.d.ts
CHANGED
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
* dependency on commander itself). Graded by commander's own suite; see
|
|
4
4
|
* `.sdlc/intents/commander-compat/design.md` and `npm run compat`.
|
|
5
5
|
*/
|
|
6
|
-
import { Argument } from './commander
|
|
7
|
-
import { Command } from './commander
|
|
8
|
-
import { Option } from './commander
|
|
9
|
-
export { Argument, humanReadableArgName } from './commander
|
|
10
|
-
export { Command, useColor, type AddHelpTextContext, type AddHelpTextPosition, type BurgeeParseOptions, type CommandOptions, type ErrorOptions, type ExecutableCommandOptions, type HookEvent, type HookListener, type OutputConfiguration, type OutputContext, type ParseOptions, } from './commander
|
|
11
|
-
export { CommanderError, InvalidArgumentError, InvalidArgumentError as InvalidOptionArgumentError } from './commander
|
|
12
|
-
export { Help, type HelpContext } from './commander
|
|
13
|
-
export { DualOptions, Option } from './commander
|
|
6
|
+
import { Argument } from './commander/argument.js';
|
|
7
|
+
import { Command } from './commander/command.js';
|
|
8
|
+
import { Option } from './commander/option.js';
|
|
9
|
+
export { Argument, humanReadableArgName } from './commander/argument.js';
|
|
10
|
+
export { Command, useColor, type AddHelpTextContext, type AddHelpTextPosition, type BurgeeParseOptions, type CommandOptions, type ErrorOptions, type ExecutableCommandOptions, type HookEvent, type HookListener, type OutputConfiguration, type OutputContext, type ParseOptions, } from './commander/command.js';
|
|
11
|
+
export { CommanderError, InvalidArgumentError, InvalidArgumentError as InvalidOptionArgumentError } from './commander/error.js';
|
|
12
|
+
export { Help, type HelpContext } from './commander/help.js';
|
|
13
|
+
export { DualOptions, Option } from './commander/option.js';
|
|
14
14
|
/** The root command, for programs that never construct their own. */
|
|
15
15
|
export declare const program: Command;
|
|
16
16
|
export declare const createCommand: (name?: string) => Command;
|
package/dist/commander.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { Argument } from './commander
|
|
2
|
-
import { Command } from './commander
|
|
3
|
-
import { Option } from './commander
|
|
4
|
-
export { Argument, humanReadableArgName } from './commander
|
|
5
|
-
export { Command, useColor, } from './commander
|
|
6
|
-
export { CommanderError, InvalidArgumentError, InvalidArgumentError as InvalidOptionArgumentError } from './commander
|
|
7
|
-
export { Help } from './commander
|
|
8
|
-
export { DualOptions, Option } from './commander
|
|
1
|
+
import { Argument } from './commander/argument.js';
|
|
2
|
+
import { Command } from './commander/command.js';
|
|
3
|
+
import { Option } from './commander/option.js';
|
|
4
|
+
export { Argument, humanReadableArgName } from './commander/argument.js';
|
|
5
|
+
export { Command, useColor, } from './commander/command.js';
|
|
6
|
+
export { CommanderError, InvalidArgumentError, InvalidArgumentError as InvalidOptionArgumentError } from './commander/error.js';
|
|
7
|
+
export { Help } from './commander/help.js';
|
|
8
|
+
export { DualOptions, Option } from './commander/option.js';
|
|
9
9
|
export const program = new Command();
|
|
10
10
|
export const createCommand = (name) => new Command(name);
|
|
11
11
|
export const createOption = (flags, description) => new Option(flags, description);
|
package/dist/completions.js
CHANGED
|
@@ -14,7 +14,9 @@ function children(manifest, at) {
|
|
|
14
14
|
.map((c) => nodeOf(manifest, c));
|
|
15
15
|
}
|
|
16
16
|
function nodeOf(manifest, c) {
|
|
17
|
-
const visible = Object.fromEntries(Object.entries(c.options)
|
|
17
|
+
const visible = Object.fromEntries(Object.entries(c.options)
|
|
18
|
+
.filter(([, spec]) => spec.hidden !== true)
|
|
19
|
+
.map(([name, spec]) => [name, spec.type === 'boolean' ? { ...spec, negatable: true } : spec]));
|
|
18
20
|
const isRoot = c.path.length === manifest.rootPath.length;
|
|
19
21
|
return {
|
|
20
22
|
path: c.path.slice(manifest.rootPath.length),
|
|
@@ -40,7 +42,11 @@ function walk(root) {
|
|
|
40
42
|
return out;
|
|
41
43
|
}
|
|
42
44
|
const sq = (s) => `'${s.replaceAll("'", "'\\''")}'`;
|
|
43
|
-
const flags = (name, spec) =>
|
|
45
|
+
const flags = (name, spec) => {
|
|
46
|
+
const long = `--${kebab(name)}`;
|
|
47
|
+
const spellings = spec.short === undefined ? [long] : [`-${spec.short}`, long];
|
|
48
|
+
return spec.negatable === true ? [...spellings, `--no-${kebab(name)}`] : spellings;
|
|
49
|
+
};
|
|
44
50
|
const takesValue = (spec) => spec.type !== 'boolean';
|
|
45
51
|
const fname = (program, path) => `_${[program, ...path].join('_').replaceAll(/[^A-Za-z0-9_]/g, '_')}`;
|
|
46
52
|
function bashCase(program, node) {
|
|
@@ -141,8 +147,13 @@ function fish(program, root) {
|
|
|
141
147
|
const cond = sq(fishCondition(node));
|
|
142
148
|
for (const c of node.children)
|
|
143
149
|
lines.push(`complete -c ${program} -n ${cond} -f -a ${c.path[c.path.length - 1] ?? ''} -d ${sq(c.description)}`);
|
|
144
|
-
for (const [name, spec] of Object.entries(node.options))
|
|
145
|
-
lines.push(fishOption(program, cond, name, spec));
|
|
150
|
+
for (const [name, spec] of Object.entries(node.options)) {
|
|
151
|
+
lines.push(fishOption(program, cond, kebab(name), spec));
|
|
152
|
+
if (spec.negatable === true) {
|
|
153
|
+
const { short: _short, ...unshort } = spec;
|
|
154
|
+
lines.push(fishOption(program, cond, `no-${kebab(name)}`, unshort));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
146
157
|
}
|
|
147
158
|
return `# ${program} completion for fish, generated by burgee — never runs ${program} on TAB.
|
|
148
159
|
# Install: ${program} completion fish > ~/.config/fish/completions/${program}.fish
|
package/dist/execute.js
CHANGED
|
@@ -8,7 +8,7 @@ import { serveMcp } from './mcp.js';
|
|
|
8
8
|
import { camel, kebab } from './names.js';
|
|
9
9
|
import { nearestPackage } from './pkg.js';
|
|
10
10
|
import { ConfigError, explain, resolve as resolveLayers } from './precedence.js';
|
|
11
|
-
import { commandSchemaOf, schemaOf, summaryOf } from './schema.js';
|
|
11
|
+
import { commandSchemaOf, machineJson, schemaOf, summaryOf } from './schema.js';
|
|
12
12
|
import { checkDefinition, checkRelations, coerce, UsageError } from './validate.js';
|
|
13
13
|
function helpFields(c) {
|
|
14
14
|
const node = {};
|
|
@@ -116,6 +116,7 @@ function render(value) {
|
|
|
116
116
|
}
|
|
117
117
|
return String(value);
|
|
118
118
|
}
|
|
119
|
+
const NO = 'no-';
|
|
119
120
|
function toParseConfig(specs, withConfig) {
|
|
120
121
|
const config = { json: { type: 'boolean' }, help: { type: 'boolean' }, version: { type: 'boolean' }, explain: { type: 'string' } };
|
|
121
122
|
if (withConfig) {
|
|
@@ -128,11 +129,28 @@ function toParseConfig(specs, withConfig) {
|
|
|
128
129
|
...(spec.short === undefined ? {} : { short: spec.short }),
|
|
129
130
|
...(spec.multiple === true ? { multiple: true } : {}),
|
|
130
131
|
};
|
|
132
|
+
if (spec.type === 'boolean')
|
|
133
|
+
config[`${NO}${kebab(name)}`] = { type: 'boolean' };
|
|
131
134
|
}
|
|
132
135
|
return config;
|
|
133
136
|
}
|
|
134
|
-
function canonical(values) {
|
|
135
|
-
|
|
137
|
+
function canonical(values, specs, tokens) {
|
|
138
|
+
const out = {};
|
|
139
|
+
const negatable = (key) => {
|
|
140
|
+
const bare = camel(key.startsWith(NO) ? key.slice(NO.length) : key);
|
|
141
|
+
return specs[bare]?.type === 'boolean' ? bare : '';
|
|
142
|
+
};
|
|
143
|
+
for (const [k, v] of Object.entries(values))
|
|
144
|
+
if (!k.startsWith(NO) || negatable(k) === '')
|
|
145
|
+
out[camel(k)] = v;
|
|
146
|
+
for (const token of tokens) {
|
|
147
|
+
if (token.kind !== 'option')
|
|
148
|
+
continue;
|
|
149
|
+
const bare = negatable(token.name);
|
|
150
|
+
if (bare !== '')
|
|
151
|
+
out[bare] = !token.name.startsWith(NO);
|
|
152
|
+
}
|
|
153
|
+
return out;
|
|
136
154
|
}
|
|
137
155
|
function packageLayer(pkg, name) {
|
|
138
156
|
if (pkg === undefined || name === undefined)
|
|
@@ -195,18 +213,7 @@ function exitSignal(cause) {
|
|
|
195
213
|
const code = cause?.code;
|
|
196
214
|
return typeof code === 'number' && isExitCode(code) ? code : undefined;
|
|
197
215
|
}
|
|
198
|
-
|
|
199
|
-
function singleDashHint(argv) {
|
|
200
|
-
for (const token of argv) {
|
|
201
|
-
if (token === '--')
|
|
202
|
-
return undefined;
|
|
203
|
-
const found = SINGLE_DASH_WORD.exec(token);
|
|
204
|
-
if (found?.[1] !== undefined)
|
|
205
|
-
return `did you mean --${found[1]}? a single dash introduces one-letter options`;
|
|
206
|
-
}
|
|
207
|
-
return undefined;
|
|
208
|
-
}
|
|
209
|
-
function describeFailure(cause, argv) {
|
|
216
|
+
async function describeFailure(cause, argv, node) {
|
|
210
217
|
const signal = exitSignal(cause);
|
|
211
218
|
if (signal !== undefined)
|
|
212
219
|
return { code: signal, message: '', silent: true };
|
|
@@ -220,7 +227,12 @@ function describeFailure(cause, argv) {
|
|
|
220
227
|
return { code: ExitCode.CONFIG, message, ...(cause.hint === undefined ? {} : { hint: cause.hint }) };
|
|
221
228
|
}
|
|
222
229
|
if (isParseArgsFailure(cause)) {
|
|
223
|
-
|
|
230
|
+
const explain = await import('./unknown-option.js');
|
|
231
|
+
const dash = explain.singleDashHint(argv);
|
|
232
|
+
if (dash !== undefined)
|
|
233
|
+
return { code: ExitCode.USAGE, message, hint: dash };
|
|
234
|
+
const better = explain.unknownOption(cause, Object.keys(node?.options ?? {}));
|
|
235
|
+
return { code: ExitCode.USAGE, message, hint: 'run --help to see the available options', ...better };
|
|
224
236
|
}
|
|
225
237
|
return { code: ExitCode.RUNTIME, message };
|
|
226
238
|
}
|
|
@@ -246,13 +258,16 @@ export function beforeTerminator(argv) {
|
|
|
246
258
|
function rootNode(manifest, root) {
|
|
247
259
|
return manifest.find(root) ?? { path: root, options: {} };
|
|
248
260
|
}
|
|
249
|
-
function unresolved({ manifest, root, io
|
|
261
|
+
function unresolved({ manifest, root, io }, argv, at) {
|
|
250
262
|
const node = at ?? rootNode(manifest, root);
|
|
251
263
|
const typed = argv.slice(node.path.length - root.length);
|
|
252
|
-
|
|
253
|
-
|
|
264
|
+
const first = typed[0] ?? '';
|
|
265
|
+
if (typed.length > 0 && HELP_FLAGS.has(first))
|
|
266
|
+
return { text: renderHelp(manifest, node, { width: io.width }), code: ExitCode.OK };
|
|
267
|
+
if (first === '--version' || first === '-V')
|
|
268
|
+
return { text: `${versionOf(manifest, io)}\n`, code: ExitCode.OK };
|
|
254
269
|
if (typed.length === 0)
|
|
255
|
-
return { text: renderHelp(manifest, node, { width }), code: ExitCode.USAGE };
|
|
270
|
+
return { text: renderHelp(manifest, node, { width: io.width }), code: ExitCode.USAGE };
|
|
256
271
|
throw new UsageError(`unknown command "${typed[0] ?? ''}"`, 'run --help to see the available commands');
|
|
257
272
|
}
|
|
258
273
|
async function completion(manifest, argv, io) {
|
|
@@ -279,7 +294,7 @@ async function surface(manifest, argv, io) {
|
|
|
279
294
|
return true;
|
|
280
295
|
}
|
|
281
296
|
if (head.includes('--schema')) {
|
|
282
|
-
io.out.write(`${
|
|
297
|
+
io.out.write(`${machineJson(schemaSurface(manifest, argv), head)}\n`);
|
|
283
298
|
return true;
|
|
284
299
|
}
|
|
285
300
|
if (head[0] === '--mcp') {
|
|
@@ -305,7 +320,7 @@ async function surface(manifest, argv, io) {
|
|
|
305
320
|
}
|
|
306
321
|
const SCHEMA_BUDGET = 48_000;
|
|
307
322
|
function schemaSurface(manifest, argv) {
|
|
308
|
-
const { node } = manifest.resolve(beforeTerminator(argv).filter((a) => a !== '--schema'), manifest.rootPath);
|
|
323
|
+
const { node } = manifest.resolve(beforeTerminator(argv).filter((a) => a !== '--schema' && !a.startsWith('--format=')), manifest.rootPath);
|
|
309
324
|
if (node?.run !== undefined)
|
|
310
325
|
return commandSchemaOf(node, manifest.rootPath);
|
|
311
326
|
const full = schemaOf(manifest);
|
|
@@ -333,7 +348,7 @@ function versionOf(manifest, io) {
|
|
|
333
348
|
}
|
|
334
349
|
async function dispatch(manifest, { node, rest, name }, io) {
|
|
335
350
|
const parsed = parseArgs({ args: rest, options: toParseConfig(node.options, manifest.config !== undefined), allowPositionals: true, strict: true, tokens: true });
|
|
336
|
-
const flags = canonical(parsed.values);
|
|
351
|
+
const flags = canonical(parsed.values, node.options, parsed.tokens);
|
|
337
352
|
const json = flags.json === true;
|
|
338
353
|
if (flags.help === true)
|
|
339
354
|
return { json, text: renderHelp(manifest, node, { width: io.width }) };
|
|
@@ -389,7 +404,7 @@ function emit(io, outcome) {
|
|
|
389
404
|
return io.exit(ExitCode.OK);
|
|
390
405
|
}
|
|
391
406
|
async function report(cause, { manifest, io, argv, json, name }) {
|
|
392
|
-
const failure = describeFailure(cause, argv);
|
|
407
|
+
const failure = await describeFailure(cause, argv, resolveCommand(manifest, argv) ?? undefined);
|
|
393
408
|
if (failure.silent === true)
|
|
394
409
|
return io.exit(failure.code);
|
|
395
410
|
await manifest.fire('onError', name, {});
|
package/dist/schema.d.ts
CHANGED
|
@@ -77,3 +77,5 @@ export interface SchemaSummary {
|
|
|
77
77
|
/** Above the budget (N13): every command by name and summary, and the drilling command for one in full. */
|
|
78
78
|
export declare function summaryOf(manifest: Manifest, budget: number): SchemaSummary;
|
|
79
79
|
export declare function schemaOf(manifest: Manifest): ProgramSchema;
|
|
80
|
+
/** The machine document, compact unless a person asked for the readable one. */
|
|
81
|
+
export declare const machineJson: (value: unknown, head: readonly string[]) => string;
|
package/dist/schema.js
CHANGED
|
@@ -114,3 +114,6 @@ export function schemaOf(manifest) {
|
|
|
114
114
|
out.description = description;
|
|
115
115
|
return out;
|
|
116
116
|
}
|
|
117
|
+
const JSON_PRETTY = '--format=json-pretty';
|
|
118
|
+
const INDENT = 2;
|
|
119
|
+
export const machineJson = (value, head) => JSON.stringify(value, null, head.includes(JSON_PRETTY) ? INDENT : 0);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `-foo=bar` means three short flags to a parser and one long flag to a person
|
|
3
|
+
* (citty #237). The more specific reading of the same argv, so it is offered first.
|
|
4
|
+
*/
|
|
5
|
+
export declare function singleDashHint(argv: readonly string[]): string | undefined;
|
|
6
|
+
export declare function unknownOption(cause: unknown, declared: readonly string[]): {
|
|
7
|
+
message: string;
|
|
8
|
+
hint: string;
|
|
9
|
+
} | undefined;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { suggestSimilar } from './suggest.js';
|
|
2
|
+
const UNKNOWN_OPTION = /^Unknown option '(?<flag>[^']+)'/u;
|
|
3
|
+
const NEAREST = /--[\w-]+/u;
|
|
4
|
+
const SINGLE_DASH_WORD = /^-(?<word>[a-zA-Z][\w-]+)(?:=.*)?$/u;
|
|
5
|
+
export function singleDashHint(argv) {
|
|
6
|
+
for (const token of argv) {
|
|
7
|
+
if (token === '--')
|
|
8
|
+
return undefined;
|
|
9
|
+
const word = SINGLE_DASH_WORD.exec(token)?.groups?.['word'];
|
|
10
|
+
if (word !== undefined)
|
|
11
|
+
return `did you mean --${word}? a single dash introduces one-letter options`;
|
|
12
|
+
}
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
export function unknownOption(cause, declared) {
|
|
16
|
+
if (!(cause instanceof Error))
|
|
17
|
+
return undefined;
|
|
18
|
+
const flag = UNKNOWN_OPTION.exec(cause.message)?.groups?.['flag'];
|
|
19
|
+
if (flag === undefined)
|
|
20
|
+
return undefined;
|
|
21
|
+
const dashed = declared.map((option) => `--${option}`);
|
|
22
|
+
const near = NEAREST.exec(suggestSimilar(flag, dashed))?.[0];
|
|
23
|
+
return {
|
|
24
|
+
message: `unknown option ${flag}`,
|
|
25
|
+
hint: near === undefined ? 'run --help to see the available options' : `did you mean ${near}?`,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* this module projects that snapshot into the manifest every surface reads (J7, J8).
|
|
5
5
|
* Nothing here runs at parse time unless a burgee surface was asked for.
|
|
6
6
|
*/
|
|
7
|
-
import { type Effects, type Manifest, type OptionSpec } from '
|
|
8
|
-
import type { Positional } from './
|
|
7
|
+
import { type Effects, type Manifest, type OptionSpec } from '../manifest.js';
|
|
8
|
+
import type { Positional } from './utils.js';
|
|
9
9
|
/** What one yargs instance (the root, or a command's builder run on a scratch) registered. */
|
|
10
10
|
export interface Snapshot {
|
|
11
11
|
name: string;
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* burgee's additions on yargs syntax — the pure half. `yargs-factory.ts` snapshots what
|
|
3
|
+
* a program registered (options, descriptions, commands and their builders' results) and
|
|
4
|
+
* this module projects that snapshot into the manifest every surface reads (J7, J8).
|
|
5
|
+
* Nothing here runs at parse time unless a burgee surface was asked for.
|
|
6
|
+
*/
|
|
7
|
+
import {} from '../manifest.js';
|
|
8
|
+
import { camelCase } from '../yargs-parser.js';
|
|
2
9
|
const DEFER_PREFIX = '__yargsString__:';
|
|
3
10
|
function describe(descriptions, key) {
|
|
4
11
|
const raw = descriptions[key];
|
|
@@ -14,6 +21,7 @@ function typeOf(s, key) {
|
|
|
14
21
|
return 'number';
|
|
15
22
|
return 'string';
|
|
16
23
|
}
|
|
24
|
+
/** Options as the manifest describes them, on a null-prototype record keyed by the canonical camelCase name. */
|
|
17
25
|
export function optionSpecs(s) {
|
|
18
26
|
const specs = Object.create(null);
|
|
19
27
|
const aliasOf = new Set();
|
|
@@ -68,6 +76,10 @@ function argumentsOf(s) {
|
|
|
68
76
|
push(p, false);
|
|
69
77
|
return out;
|
|
70
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* Project a snapshot into the manifest: the root, then every command as a child path.
|
|
81
|
+
* Plugin-contributed nodes survive re-projection, exactly as on the commander façade.
|
|
82
|
+
*/
|
|
71
83
|
export function projectManifest(manifest, root) {
|
|
72
84
|
const contributed = manifest.commands.filter((c) => c.plugin !== undefined);
|
|
73
85
|
manifest.commands.splice(0, manifest.commands.length, ...contributed);
|
|
@@ -90,6 +102,7 @@ export function projectManifest(manifest, root) {
|
|
|
90
102
|
};
|
|
91
103
|
visit(root, [root.name], root.description, undefined);
|
|
92
104
|
}
|
|
105
|
+
/** What a run prints for a handler's return value when the streams are injected. */
|
|
93
106
|
export function render(value) {
|
|
94
107
|
if (value === undefined || value === null)
|
|
95
108
|
return '';
|
|
@@ -102,3 +115,4 @@ export function render(value) {
|
|
|
102
115
|
}
|
|
103
116
|
return `${JSON.stringify(value)}\n`;
|
|
104
117
|
}
|
|
118
|
+
//# sourceMappingURL=burgee.js.map
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cliui 9 — the column layout yargs' usage renders through — with the string-width,
|
|
3
|
+
* strip-ansi and wrap-ansi it depends on, ported for `burgee/yargs`. The wrapping
|
|
4
|
+
* arithmetic is byte-for-byte the upstream's: yargs' usage tests compare whole help
|
|
5
|
+
* screens.
|
|
6
|
+
*/
|
|
1
7
|
const ANSI_PATTERN = '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))';
|
|
2
8
|
export function stripAnsi(str) {
|
|
3
9
|
return typeof str === 'string' ? str.replace(new RegExp(ANSI_PATTERN, 'g'), '') : str;
|
|
@@ -47,6 +53,7 @@ export function stringWidth(input) {
|
|
|
47
53
|
}
|
|
48
54
|
return width;
|
|
49
55
|
}
|
|
56
|
+
/** ansi-styles' open→close map, the part wrap-ansi reads. */
|
|
50
57
|
function closeCode(code) {
|
|
51
58
|
if (code === 1 || code === 2)
|
|
52
59
|
return 22;
|
|
@@ -419,3 +426,4 @@ function alignCenter(str, width) {
|
|
|
419
426
|
export function cliui(opts) {
|
|
420
427
|
return new UI({ width: opts?.width || getWindowWidth(), wrap: opts?.wrap });
|
|
421
428
|
}
|
|
429
|
+
//# sourceMappingURL=cliui.js.map
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
* builder/handler pipeline, positionals and the default command — ported for
|
|
4
4
|
* `burgee/yargs`.
|
|
5
5
|
*/
|
|
6
|
-
import { type Middleware } from './
|
|
7
|
-
import type { PlatformShim } from './
|
|
8
|
-
import type { UsageInstance } from './
|
|
9
|
-
import { type Positional } from './
|
|
10
|
-
import type { ValidationInstance } from './
|
|
6
|
+
import { type Middleware } from './middleware.js';
|
|
7
|
+
import type { PlatformShim } from './shim.js';
|
|
8
|
+
import type { UsageInstance } from './usage.js';
|
|
9
|
+
import { type Positional } from './utils.js';
|
|
10
|
+
import type { ValidationInstance } from './validation.js';
|
|
11
11
|
export interface CommandHandler {
|
|
12
12
|
original: string;
|
|
13
13
|
description?: string | false | undefined;
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* yargs' command instance — `.command()` in its five shapes, `.commandDir()`, the
|
|
3
|
+
* builder/handler pipeline, positionals and the default command — ported for
|
|
4
|
+
* `burgee/yargs`.
|
|
5
|
+
*/
|
|
6
|
+
import { applyMiddleware, commandMiddlewareFactory } from './middleware.js';
|
|
7
|
+
import { isPromise, maybeAsyncResult, parseCommand } from './utils.js';
|
|
3
8
|
const DEFAULT_MARKER = /(^\*)|(^\$0)/;
|
|
4
9
|
export function isYargsInstance(y) {
|
|
5
10
|
return !!y && typeof y.getInternalMethods === 'function';
|
|
@@ -222,6 +227,7 @@ export class CommandInstance {
|
|
|
222
227
|
yargs.getInternalMethods().getUsageInstance().fail(null, error);
|
|
223
228
|
}
|
|
224
229
|
catch {
|
|
230
|
+
// the failure was reported; yargs swallows the rethrow here
|
|
225
231
|
}
|
|
226
232
|
});
|
|
227
233
|
}
|
|
@@ -412,3 +418,4 @@ function isCommandBuilderOptionDefinitions(builder) {
|
|
|
412
418
|
export function isCommandHandlerDefinition(cmd) {
|
|
413
419
|
return typeof cmd === 'object' && !Array.isArray(cmd);
|
|
414
420
|
}
|
|
421
|
+
//# sourceMappingURL=command.js.map
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* yargs' completion — `--get-yargs-completions`, the custom completion function in its
|
|
3
3
|
* three arities, and the bash/zsh script templates — ported for `burgee/yargs`.
|
|
4
4
|
*/
|
|
5
|
-
import { type CommandInstance } from './
|
|
6
|
-
import type { PlatformShim } from './
|
|
7
|
-
import type { UsageInstance } from './
|
|
5
|
+
import { type CommandInstance } from './command.js';
|
|
6
|
+
import type { PlatformShim } from './shim.js';
|
|
7
|
+
import type { UsageInstance } from './usage.js';
|
|
8
8
|
export declare const completionShTemplate = "###-begin-{{app_name}}-completions-###\n#\n# yargs command completion script\n#\n# Installation: {{app_path}} {{completion_command}} >> ~/.bashrc\n# or {{app_path}} {{completion_command}} >> ~/.bash_profile on OSX.\n#\n_{{app_name}}_yargs_completions()\n{\n local cur_word args type_list\n\n cur_word=\"${COMP_WORDS[COMP_CWORD]}\"\n args=(\"${COMP_WORDS[@]}\")\n\n # ask yargs to generate completions.\n # see https://stackoverflow.com/a/40944195/7080036 for the spaces-handling awk\n mapfile -t type_list < <({{app_path}} --get-yargs-completions \"${args[@]}\")\n mapfile -t COMPREPLY < <(compgen -W \"$( printf '%q ' \"${type_list[@]}\" )\" -- \"${cur_word}\" |\n awk '/ / { print \"\\\"\"$0\"\\\"\" } /^[^ ]+$/ { print $0 }')\n\n # if no match was found, fall back to filename completion\n if [ ${#COMPREPLY[@]} -eq 0 ]; then\n COMPREPLY=()\n fi\n\n return 0\n}\ncomplete -o bashdefault -o default -F _{{app_name}}_yargs_completions {{app_name}}\n###-end-{{app_name}}-completions-###\n";
|
|
9
9
|
export declare const completionZshTemplate = "#compdef {{app_name}}\n###-begin-{{app_name}}-completions-###\n#\n# yargs command completion script\n#\n# Installation: {{app_path}} {{completion_command}} >> ~/.zshrc\n# or {{app_path}} {{completion_command}} >> ~/.zprofile on OSX.\n#\n_{{app_name}}_yargs_completions()\n{\n local reply\n local si=$IFS\n IFS=$'\n' reply=($(COMP_CWORD=\"$((CURRENT-1))\" COMP_LINE=\"$BUFFER\" COMP_POINT=\"$CURSOR\" {{app_path}} --get-yargs-completions \"${words[@]}\"))\n IFS=$si\n if [[ ${#reply} -gt 0 ]]; then\n _describe 'values' reply\n else\n _default\n fi\n}\nif [[ \"'${zsh_eval_context[-1]}\" == \"loadautofunc\" ]]; then\n _{{app_name}}_yargs_completions \"$@\"\nelse\n compdef _{{app_name}}_yargs_completions {{app_name}}\nfi\n###-end-{{app_name}}-completions-###\n";
|
|
10
10
|
type Done = (err: Error | null, completions: string[] | undefined) => void;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* yargs' completion — `--get-yargs-completions`, the custom completion function in its
|
|
3
|
+
* three arities, and the bash/zsh script templates — ported for `burgee/yargs`.
|
|
4
|
+
*/
|
|
5
|
+
import { isCommandBuilderCallback } from './command.js';
|
|
6
|
+
import { isPromise, parseCommand } from './utils.js';
|
|
3
7
|
export const completionShTemplate = `###-begin-{{app_name}}-completions-###
|
|
4
8
|
#
|
|
5
9
|
# yargs command completion script
|
|
@@ -269,3 +273,4 @@ function isSyncCompletionFunction(fn) {
|
|
|
269
273
|
function isFallbackCompletionFunction(fn) {
|
|
270
274
|
return fn.length > 3;
|
|
271
275
|
}
|
|
276
|
+
//# sourceMappingURL=completion.js.map
|