burgee 0.7.1 → 0.9.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.
Files changed (65) hide show
  1. package/README.md +1 -0
  2. package/dist/check.d.ts +22 -0
  3. package/dist/check.js +35 -0
  4. package/dist/cli.d.ts +31 -3
  5. package/dist/cli.js +36 -7
  6. package/dist/commander/argument.js +0 -3
  7. package/dist/commander/command.d.ts +7 -3
  8. package/dist/commander/command.js +54 -187
  9. package/dist/commander/error.js +0 -2
  10. package/dist/commander/help.js +0 -17
  11. package/dist/commander/option.js +0 -14
  12. package/dist/compat.d.ts +30 -0
  13. package/dist/compat.js +4 -0
  14. package/dist/config.d.ts +10 -0
  15. package/dist/config.js +2 -0
  16. package/dist/definition.d.ts +24 -6
  17. package/dist/definition.js +18 -14
  18. package/dist/execute.d.ts +1 -0
  19. package/dist/execute.js +45 -27
  20. package/dist/exit-code.d.ts +17 -1
  21. package/dist/exit-code.js +1 -0
  22. package/dist/help-entry.d.ts +2 -0
  23. package/dist/help-entry.js +1 -0
  24. package/dist/help.d.ts +12 -0
  25. package/dist/help.js +6 -0
  26. package/dist/index.d.ts +32 -7
  27. package/dist/index.js +1 -7
  28. package/dist/mcp-entry.d.ts +2 -0
  29. package/dist/mcp-entry.js +1 -0
  30. package/dist/mcp.d.ts +33 -13
  31. package/dist/mcp.js +4 -3
  32. package/dist/meow/parse.d.ts +21 -0
  33. package/dist/meow/parse.js +43 -0
  34. package/dist/meow/present.d.ts +35 -0
  35. package/dist/meow/present.js +58 -0
  36. package/dist/meow/types.d.ts +47 -0
  37. package/dist/meow/types.js +3 -0
  38. package/dist/meow/validate.d.ts +35 -0
  39. package/dist/meow/validate.js +144 -0
  40. package/dist/meow.d.ts +6 -0
  41. package/dist/meow.js +146 -0
  42. package/dist/migrate.d.ts +142 -0
  43. package/dist/migrate.js +284 -0
  44. package/dist/plugin.d.ts +1 -1
  45. package/dist/plugin.js +1 -1
  46. package/dist/runtime.d.ts +2 -0
  47. package/dist/runtime.js +3 -0
  48. package/dist/schema-entry.d.ts +3 -0
  49. package/dist/schema-entry.js +2 -0
  50. package/dist/schema.json +1 -1
  51. package/dist/testing-helpers.js +3 -1
  52. package/dist/validate.d.ts +15 -0
  53. package/dist/validate.js +10 -0
  54. package/dist/yargs/burgee.js +0 -14
  55. package/dist/yargs/cliui.js +0 -53
  56. package/dist/yargs/command.js +0 -7
  57. package/dist/yargs/completion.js +0 -5
  58. package/dist/yargs/factory.js +7 -57
  59. package/dist/yargs/middleware.js +0 -5
  60. package/dist/yargs/shim.js +0 -20
  61. package/dist/yargs/usage.js +0 -8
  62. package/dist/yargs/utils.js +0 -11
  63. package/dist/yargs/validation.js +0 -6
  64. package/dist/yargs/y18n.js +0 -6
  65. package/package.json +32 -7
package/dist/index.d.ts CHANGED
@@ -4,15 +4,40 @@
4
4
  *
5
5
  * The public entry, and only that. The execution core lives in execute.ts so a
6
6
  * façade can import it without pulling this barrel.
7
+ *
8
+ * ## What is not here, and why (D-093, reversed on a measurement)
9
+ *
10
+ * This barrel used to re-export the value half of `help.ts`, `mcp.ts`, `schema.ts`,
11
+ * `plugin.ts`, `manifest.ts` and `seniority/precedence` as a convenience. A re-export is
12
+ * not free: it makes those modules live for every consumer of `burgee`, whether or not
13
+ * anything reads them. `execute.ts` loads each one behind an `await import()`, so the only
14
+ * thing keeping them on the startup path was this file.
15
+ *
16
+ * Measured 2026-09-21 with `--splitting --outdir` over the transitive closure of `import`
17
+ * statements — the initial load a consumer actually pays:
18
+ *
19
+ * - `import { run } from 'burgee'` — **44,663 bytes**
20
+ * - the same program against `execute.ts` directly — **31,047 bytes**
21
+ * - cold start, `burgee ÷ cac` — **2.113 → 1.717**
22
+ *
23
+ * D-093 declined this split on a cold-start argument it did not have the number for. The
24
+ * number says 13,616 bytes and 19% of startup, so the split lands: every value moved here
25
+ * has a subpath of its own (`burgee/help`, `burgee/mcp`, `burgee/schema`, `burgee/plugin`,
26
+ * `burgee/config`), which is where a program that wants it should say so.
27
+ *
28
+ * **Every `type` stays.** A type re-export is erased and costs a consumer nothing, so the
29
+ * whole type surface is still importable from `burgee` and no typed program has to move.
7
30
  */
8
31
  export { ExitCode, isExitCode, type ExitCode as ExitCodeValue } from './exit-code.js';
9
32
  export { defineCommand, defineProgram, execute, resolveCommand, run, runCommand, sharedOptions, type AnyCommand, type Command, type CommandContext, type InferOptions, type OptionSpecs, type Program, type RunOptions, type RunResult, } from './execute.js';
10
33
  export { checkCommand, checkDefinition } from './definition.js';
11
- export { camel, kebab, UsageError } from './validate.js';
34
+ export { AuthError, camel, kebab, UsageError } from './validate.js';
12
35
  export { AGENT_PROBES, detectAgent, type AgentProbe, type Detection } from './agent.js';
13
- export { renderHelp, type HelpOptions, type HelpTheme, type HelpToken } from './help.js';
14
- export { annotationsOf, MCP_PROTOCOL_VERSION, serveMcp, toolsOf, type Invoke, type ServeOptions, type Tool, type ToolAnnotations } from './mcp.js';
15
- export { ConfigError, envName, explain, resolve, screaming, type Candidate, type Layers, type Provenance, type Resolution, type Source } from 'seniority/precedence';
16
- export { commandSchemaOf, inputSchemaOf, schemaOf, summaryOf, type CommandSchema, type JsonSchema, type ProgramSchema, type SchemaSummary } from './schema.js';
17
- export { CONTRACT, definePlugin, PluginError, type PluginErrorCode } from './plugin.js';
18
- export { Manifest, type ArgumentSpec, type CommandNode, type Effects, type Example, type Hook, type LazyModule, type OptionSpec, type ActionRequiredSpec, type Plugin, type Relation, type RunContext, type StandardResult, type StandardSchemaV1, } from './manifest.js';
36
+ export type { HelpOptions, HelpTheme, HelpToken } from './help.js';
37
+ export type { Invoke, ServeOptions, Tool, ToolAnnotations } from './mcp.js';
38
+ export type { Candidate, Layers, Provenance, Resolution, Source } from 'seniority/precedence';
39
+ export type { CommandSchema, JsonSchema, ProgramSchema, SchemaSummary } from './schema.js';
40
+ export type { PluginErrorCode } from './plugin.js';
41
+ export type {
42
+ /** The class itself lives at `burgee/schema`; the *type* stays here so `defineProgram`'s return type is nameable. */
43
+ Manifest, ArgumentSpec, CommandNode, Effects, Example, Hook, LazyModule, OptionSpec, ActionRequiredSpec, Plugin, Relation, RunContext, StandardResult, StandardSchemaV1, } from './manifest.js';
package/dist/index.js CHANGED
@@ -1,11 +1,5 @@
1
1
  export { ExitCode, isExitCode } from './exit-code.js';
2
2
  export { defineCommand, defineProgram, execute, resolveCommand, run, runCommand, sharedOptions, } from './execute.js';
3
3
  export { checkCommand, checkDefinition } from './definition.js';
4
- export { camel, kebab, UsageError } from './validate.js';
4
+ export { AuthError, camel, kebab, UsageError } from './validate.js';
5
5
  export { AGENT_PROBES, detectAgent } from './agent.js';
6
- export { renderHelp } from './help.js';
7
- export { annotationsOf, MCP_PROTOCOL_VERSION, serveMcp, toolsOf } from './mcp.js';
8
- export { ConfigError, envName, explain, resolve, screaming } from 'seniority/precedence';
9
- export { commandSchemaOf, inputSchemaOf, schemaOf, summaryOf } from './schema.js';
10
- export { CONTRACT, definePlugin, PluginError } from './plugin.js';
11
- export { Manifest, } from './manifest.js';
@@ -0,0 +1,2 @@
1
+ /** `burgee/mcp` — the MCP server, by itself. See `index.ts` for why it is not in the barrel. */
2
+ export { annotationsOf, MCP_PROTOCOL_VERSION, serveMcp, toolsOf, type Invoke, type ServeOptions, type Tool, type ToolAnnotations } from './mcp.js';
@@ -0,0 +1 @@
1
+ export { annotationsOf, MCP_PROTOCOL_VERSION, serveMcp, toolsOf } from './mcp.js';
package/dist/mcp.d.ts CHANGED
@@ -2,9 +2,15 @@ import { type CommandNode, type Effects, type Manifest } from './manifest.js';
2
2
  import { type JsonSchema } from './schema.js';
3
3
  export declare const MCP_PROTOCOL_VERSION = "2025-06-18";
4
4
  export interface ToolAnnotations {
5
- readOnlyHint: boolean;
6
- idempotentHint: boolean;
7
- destructiveHint: boolean;
5
+ readOnlyHint?: boolean;
6
+ idempotentHint?: boolean;
7
+ destructiveHint?: boolean;
8
+ /**
9
+ * `'undeclared'`, and only ever that (G1). It appears on a command whose author said
10
+ * nothing — every commander and yargs command that did not call `.effects()` — and never
11
+ * beside a hint, because a hint is what a declaration produces.
12
+ */
13
+ effects?: 'undeclared';
8
14
  }
9
15
  export interface Tool {
10
16
  name: string;
@@ -18,20 +24,34 @@ export type Invoke = (argv: string[]) => Promise<{
18
24
  stderr: string;
19
25
  code: number;
20
26
  }>;
21
- /** MCP's hints, from the declared effects. `destructiveHint` is only ever false by declaration. */
22
- export declare function annotationsOf(effects: Effects): ToolAnnotations;
27
+ /**
28
+ * MCP's hints, from the declared effects. `destructiveHint` is only ever false by declaration.
29
+ *
30
+ * No declaration returns no hints (G1). That is not a gap: MCP defines a default for each of
31
+ * the three — `readOnlyHint: false`, `destructiveHint: true`, `idempotentHint: false` — so an
32
+ * absent hint already reads as *assume the worst*, in the client's own vocabulary and without
33
+ * burgee inventing a value it has no basis for. `effects: 'undeclared'` is the positive half:
34
+ * this command is not a `read_only` one, and it is not a `withheld` one either — nobody said.
35
+ */
36
+ export declare function annotationsOf(effects?: Effects): ToolAnnotations;
23
37
  /** `config get` → `config_get`: MCP tool names are `[a-zA-Z0-9_-]`. */
24
38
  export declare const toolName: (node: CommandNode, root: string[]) => string;
25
39
  /**
26
- * The tool list: every runnable, visible command that declared what running it does.
40
+ * The tool list: every runnable, visible command an author has not withheld.
41
+ *
42
+ * One word is absent and one is not, and until 2026-09-21 they were the same thing. An
43
+ * author who wrote `'withheld'` thought about it and said no; that is what the word is for
44
+ * and it still means absent. An author who wrote nothing — which on burgee's own API
45
+ * `checkCommand` refuses, and which **every** command built through the commander or yargs
46
+ * façade is, because neither incumbent has a notion of effects and neither can be made to
47
+ * acquire one without breaking the suites that grade the façades — was treated the same way,
48
+ * so a migrated user's whole program was silently not a tool.
27
49
  *
28
- * Two commands are absent and for different reasons. One declared `'withheld'` — an author
29
- * who thought about it and said no, which is what that word is for. The other has no
30
- * `effects` at all, which `checkCommand` now refuses at declaration, so on burgee's own API
31
- * it cannot reach here; a command built through the commander or yargs façade still can,
32
- * because neither incumbent has a notion of effects and neither can be made to acquire one
33
- * without breaking the suites that grade the façades. The filter treats both as *not a
34
- * tool*, which is the same conservative reading it always had.
50
+ * Reading silence as refusal was conservative and it was also the thing standing between the
51
+ * product and its own pitch. Absent-from-the-list is strictly worse for the caller than
52
+ * present-with-honest-annotations: an agent that cannot see a command cannot decide about it,
53
+ * and cannot ask. So an undeclared command is listed and says so — see {@link annotationsOf}
54
+ * for why it carries no hints rather than a reassuring default.
35
55
  */
36
56
  export declare function toolsOf(manifest: Manifest): Tool[];
37
57
  /** A tool call's arguments back into argv: the command, its options, `--json`, then positionals in declared order. */
package/dist/mcp.js CHANGED
@@ -6,6 +6,8 @@ const JSON_RPC_INVALID_REQUEST = -32600;
6
6
  const JSON_RPC_METHOD_NOT_FOUND = -32601;
7
7
  const JSON_RPC_INVALID_PARAMS = -32602;
8
8
  export function annotationsOf(effects) {
9
+ if (effects === undefined)
10
+ return { effects: 'undeclared' };
9
11
  return {
10
12
  readOnlyHint: effects === 'read_only',
11
13
  idempotentHint: effects !== 'non_idempotent',
@@ -21,7 +23,7 @@ function describe(node) {
21
23
  }
22
24
  export function toolsOf(manifest) {
23
25
  return runnable(manifest)
24
- .filter((c) => c.effects !== undefined && c.effects !== WITHHELD)
26
+ .filter((c) => c.effects !== WITHHELD)
25
27
  .map((c) => ({ name: toolName(c, manifest.rootPath), description: describe(c), inputSchema: inputSchemaOf(c), annotations: annotationsOf(c.effects) }));
26
28
  }
27
29
  function optionArgs(node, args) {
@@ -59,8 +61,7 @@ async function callTool(session, params) {
59
61
  const given = params ?? {};
60
62
  const raw = given['name'];
61
63
  const name = typeof raw === 'string' ? raw : '';
62
- const exposed = new Set(toolsOf(manifest).map((t) => t.name));
63
- const node = exposed.has(name) ? runnable(manifest).find((c) => toolName(c, root) === name) : undefined;
64
+ const node = runnable(manifest).find((c) => c.effects !== WITHHELD && toolName(c, root) === name);
64
65
  if (node === undefined)
65
66
  return { error: { code: JSON_RPC_INVALID_PARAMS, message: `unknown tool "${name}"` } };
66
67
  const args = (given['arguments'] ?? {});
@@ -0,0 +1,21 @@
1
+ import { type AnyFlag, type Options } from './types.js';
2
+ /** Where a command run's parent arguments end and the child's begin. */
3
+ export interface Split {
4
+ parent: string[];
5
+ input: string[];
6
+ command?: string;
7
+ unknownCommand?: string;
8
+ }
9
+ /** Every flag name a caller may write, and the canonical name each maps to. */
10
+ export declare function aliasMap(flags: Record<string, AnyFlag>): Record<string, string[]>;
11
+ export declare function typeofDefault(value: unknown): 'string' | 'boolean' | 'number' | undefined;
12
+ /**
13
+ * Where the parent's arguments end and the command's begin.
14
+ *
15
+ * The first token the parser reads as positional is the command word; everything after it in
16
+ * the *raw* argv is the child's, unparsed. `--` is not a fence here — the suite states that
17
+ * `-- --unknown run` reports `Unknown command: --unknown`, so a post-separator word is a
18
+ * candidate command like any other.
19
+ */
20
+ export declare function splitAtCommand(argv: string[], parserOptions: Record<string, unknown>, opts: Options): Split;
21
+ /** stderr and exit 2 — how meow ends a run the flags do not support. */
@@ -0,0 +1,43 @@
1
+ import parser, { decamelize } from '../yargs-parser.js';
2
+ export function aliasMap(flags) {
3
+ const out = {};
4
+ for (const [name, spec] of Object.entries(flags)) {
5
+ const names = [];
6
+ if (typeof spec.shortFlag === 'string')
7
+ names.push(spec.shortFlag);
8
+ if (typeof spec.alias === 'string')
9
+ names.push(spec.alias);
10
+ for (const extra of spec.aliases ?? [])
11
+ names.push(extra);
12
+ const decamelized = decamelize(name, '-');
13
+ if (decamelized !== name)
14
+ names.push(decamelized);
15
+ if (names.length > 0)
16
+ Object.defineProperty(out, name, { value: names, writable: true, enumerable: true, configurable: true });
17
+ }
18
+ return out;
19
+ }
20
+ export function typeofDefault(value) {
21
+ if (typeof value === 'boolean')
22
+ return 'boolean';
23
+ if (typeof value === 'number')
24
+ return 'number';
25
+ if (typeof value === 'string')
26
+ return 'string';
27
+ if (Array.isArray(value))
28
+ return typeofDefault(value[0]);
29
+ return undefined;
30
+ }
31
+ export function splitAtCommand(argv, parserOptions, opts) {
32
+ const probe = parser.detailed(argv, parserOptions);
33
+ const first = probe.argv['_'][0];
34
+ if (first === undefined)
35
+ return { parent: argv, input: [] };
36
+ const word = String(first);
37
+ const at = argv.indexOf(word);
38
+ const parent = at === -1 ? argv : argv.slice(0, at);
39
+ const input = at === -1 ? [] : argv.slice(at + 1);
40
+ if (!(opts.commands ?? []).includes(word))
41
+ return { parent, input, unknownCommand: word };
42
+ return { parent, input, command: word };
43
+ }
@@ -0,0 +1,35 @@
1
+ import { type Options } from './types.js';
2
+ /** The nearest `package.json` above the caller's module, which is what `importMeta` is for. */
3
+ /** The nearest `package.json` above the caller's module, which is what `importMeta` is for. */
4
+ export declare function readPackageUp(importMeta: ImportMeta | undefined): Record<string, unknown>;
5
+ /**
6
+ * meow's help block.
7
+ *
8
+ * Indented by `helpIndent` (2 by default) — but only when there is more than one line to
9
+ * indent, which is why `{description: false, help: 'single line'}` comes back flush. The
10
+ * suite states both shapes and they disagree about the indent, not about the text.
11
+ */
12
+ /**
13
+ * meow's help block.
14
+ *
15
+ * Indented by `helpIndent` (2 by default) — but only when there is more than one line to
16
+ * indent, which is why `{description: false, help: 'single line'}` comes back flush. The
17
+ * suite states both shapes and they disagree about the indent, not about the text.
18
+ */
19
+ export declare function buildHelp(options: Options, pkg: Record<string, unknown>): string;
20
+ /** `common-tags`' `stripIndent`, for the template literals meow's callers write help in. */
21
+ /** `common-tags`' `stripIndent`, for the template literals meow's callers write help in. */
22
+ export declare function stripIndent(text: string): string;
23
+ /** Every flag name a caller may write, and the canonical name each maps to. */
24
+ /**
25
+ * The half of `normalize-package-data` meow's callers can see.
26
+ *
27
+ * `bin` as a string becomes `{ [name]: path }` — the suite reads `cli.pkg.bin['browser-sync']`
28
+ * — and an absent `version` becomes `''`. A copy, because `pkg normalization is lazy` asserts
29
+ * the object the caller passed in is untouched.
30
+ */
31
+ export declare function normalizePackage(pkg: Record<string, unknown>): Record<string, unknown>;
32
+ /** meow renames the process after the binary it is, which `ps` and a crash report both read. */
33
+ /** meow renames the process after the binary it is, which `ps` and a crash report both read. */
34
+ export declare function setProcessTitle(pkg: Record<string, unknown>): void;
35
+ /** An own property under a key the caller chose — never the prototype setter. */
@@ -0,0 +1,58 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { host } from '../runtime.js';
5
+ const indent = (text, spaces) => text.replace(/^(?!\s*$)/gmu, ' '.repeat(spaces));
6
+ export function readPackageUp(importMeta) {
7
+ if (importMeta?.url === undefined)
8
+ return {};
9
+ let dir = dirname(fileURLToPath(importMeta.url));
10
+ for (let depth = 0; depth < 64; depth += 1) {
11
+ try {
12
+ return JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8'));
13
+ }
14
+ catch {
15
+ const up = dirname(dir);
16
+ if (up === dir)
17
+ break;
18
+ dir = up;
19
+ }
20
+ }
21
+ return {};
22
+ }
23
+ export function buildHelp(options, pkg) {
24
+ const description = options.description === false ? '' : (options.description ?? pkg['description'] ?? '');
25
+ const body = options.help === false ? '' : stripIndent(options.help ?? '');
26
+ const parts = [description, body].filter((p) => p !== '');
27
+ if (parts.length === 0)
28
+ return '';
29
+ const text = parts.join('\n\n');
30
+ const width = options.helpIndent ?? 2;
31
+ return `\n${text.includes('\n') ? indent(text, width) : text}\n`;
32
+ }
33
+ export function stripIndent(text) {
34
+ const lines = text.split('\n');
35
+ const widths = lines.filter((l) => l.trim() !== '').map((l) => (/^(\s*)/u.exec(l)?.[1] ?? '').length);
36
+ const smallest = widths.length === 0 ? 0 : Math.min(...widths);
37
+ return lines
38
+ .map((l) => l.slice(smallest))
39
+ .join('\n')
40
+ .trim();
41
+ }
42
+ export function normalizePackage(pkg) {
43
+ const out = { ...pkg };
44
+ const name = typeof out['name'] === 'string' ? out['name'].replace(/^@[^/]+\//u, '') : undefined;
45
+ if (typeof out['bin'] === 'string' && name !== undefined)
46
+ out['bin'] = Object.fromEntries([[name, out['bin']]]);
47
+ if (out['version'] === undefined)
48
+ out['version'] = '';
49
+ return out;
50
+ }
51
+ export function setProcessTitle(pkg) {
52
+ const bin = pkg['bin'];
53
+ const first = typeof bin === 'object' && bin !== null ? Object.keys(bin)[0] : undefined;
54
+ const name = typeof pkg['name'] === 'string' ? pkg['name'].replace(/^@[^/]+\//u, '') : undefined;
55
+ const title = first ?? name;
56
+ if (title !== undefined && title !== '')
57
+ host.setTitle(title);
58
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * `burgee/meow` — the option and result shapes meow's callers write against.
3
+ *
4
+ * Kept beside the implementation rather than inside it because three files read them and a
5
+ * façade's contract is the part most worth seeing on its own.
6
+ */
7
+ export interface AnyFlag {
8
+ type?: 'string' | 'boolean' | 'number';
9
+ alias?: string;
10
+ aliases?: string[];
11
+ shortFlag?: string;
12
+ default?: unknown;
13
+ isRequired?: boolean | ((flags: Record<string, unknown>, input: string[]) => boolean);
14
+ isMultiple?: boolean;
15
+ choices?: unknown[];
16
+ }
17
+ export interface Options {
18
+ importMeta?: ImportMeta;
19
+ argv?: readonly string[];
20
+ description?: string | false;
21
+ help?: string | false;
22
+ version?: string | false;
23
+ autoHelp?: boolean;
24
+ autoVersion?: boolean;
25
+ helpIndent?: number;
26
+ flags?: Record<string, AnyFlag>;
27
+ pkg?: Record<string, unknown>;
28
+ input?: unknown;
29
+ inferType?: boolean;
30
+ booleanDefault?: boolean | null | undefined;
31
+ hardRejection?: boolean;
32
+ allowUnknownFlags?: boolean;
33
+ commands?: string[];
34
+ }
35
+ export interface Result {
36
+ input: string[];
37
+ flags: Record<string, unknown>;
38
+ unnormalizedFlags: Record<string, unknown>;
39
+ pkg: Record<string, unknown>;
40
+ help: string;
41
+ version: string;
42
+ command?: string;
43
+ showHelp: (code?: number) => never;
44
+ showVersion: () => void;
45
+ }
46
+ /** An own property under a key the caller chose — never the prototype setter. */
47
+ export declare function own(target: Record<string, unknown>, key: string, value: unknown): void;
@@ -0,0 +1,3 @@
1
+ export function own(target, key, value) {
2
+ Object.defineProperty(target, key, { value, writable: true, enumerable: true, configurable: true });
3
+ }
@@ -0,0 +1,35 @@
1
+ import { type AnyFlag, type Options } from './types.js';
2
+ export declare function validateFlags(flags: Record<string, AnyFlag>): void;
3
+ /** meow refuses to guess where the caller's `package.json` is. */
4
+ /** meow refuses to guess where the caller's `package.json` is. */
5
+ export declare function requireImportMeta(importMeta: ImportMeta | undefined): void;
6
+ /** meow, over burgee's parser. */
7
+ /** `commands` is an array of bare words, and meow says so in three different sentences. */
8
+ export declare function validateCommands(commands: string[] | undefined): void;
9
+ /**
10
+ * Where the parent's arguments end and the command's begin.
11
+ *
12
+ * The first token the parser reads as positional is the command word; everything after it in
13
+ * the *raw* argv is the child's, unparsed. `--` is not a fence here — the suite states that
14
+ * `-- --unknown run` reports `Unknown command: --unknown`, so a post-separator word is a
15
+ * candidate command like any other.
16
+ */
17
+ export declare function checkChoices(specs: Record<string, AnyFlag>, flags: Record<string, unknown>): void;
18
+ export declare function checkRequired(specs: Record<string, AnyFlag>, flags: Record<string, unknown>, input: string[]): void;
19
+ export declare function checkUnknown(specs: Record<string, AnyFlag>, parsedFlags: Record<string, unknown>, argv: string[], opts: Options): void;
20
+ /** `commands` is an array of bare words, and meow says so in three different sentences. */
21
+ /** meow's `input` option may demand positionals, as a boolean or as a predicate. */
22
+ export declare function checkInput(opts: Options, input: string[], flags: Record<string, unknown>): void;
23
+ /** A flag declared once may be given once — the parser collects repeats into an array. */
24
+ /** A flag declared once may be given once — the parser collects repeats into an array. */
25
+ export declare function checkSetOnce(specs: Record<string, AnyFlag>, parsed: Record<string, unknown>): void;
26
+ /**
27
+ * The half of `normalize-package-data` meow's callers can see.
28
+ *
29
+ * `bin` as a string becomes `{ [name]: path }` — the suite reads `cli.pkg.bin['browser-sync']`
30
+ * — and an absent `version` becomes `''`. A copy, because `pkg normalization is lazy` asserts
31
+ * the object the caller passed in is untouched.
32
+ */
33
+ /** stderr and exit 2 — how meow ends a run the flags do not support. */
34
+ export declare function reportAndExit(message: string): never;
35
+ /** meow's `input` option may demand positionals, as a boolean or as a predicate. */
@@ -0,0 +1,144 @@
1
+ import { fileURLToPath } from 'node:url';
2
+ import { ExitCode } from '../exit-code.js';
3
+ import { host } from '../runtime.js';
4
+ import { camelCase, decamelize } from '../yargs-parser.js';
5
+ export function validateFlags(flags) {
6
+ const errors = [];
7
+ const kebab = Object.keys(flags).filter((name) => name.includes('-') && name !== '--');
8
+ if (kebab.length > 0)
9
+ errors.push(`Flag keys may not contain '-'. Invalid flags: ${kebab.map((k) => `\`${k}\``).join(', ')}`);
10
+ const renamed = Object.entries(flags).filter(([, spec]) => typeof spec.alias === 'string');
11
+ if (renamed.length > 0) {
12
+ errors.push(`The option \`alias\` has been renamed to \`shortFlag\`. The following flags need to be updated: ${renamed.map(([n]) => `\`--${n}\``).join(', ')}`);
13
+ }
14
+ const badChoices = Object.entries(flags).filter(([, spec]) => spec.choices !== undefined && !Array.isArray(spec.choices));
15
+ if (badChoices.length > 0) {
16
+ errors.push(`The option \`choices\` must be an array. Invalid flags: ${badChoices.map(([n]) => `\`--${n}\``).join(', ')}`);
17
+ }
18
+ for (const [name, spec] of Object.entries(flags)) {
19
+ if (spec.default === undefined || spec.type === undefined)
20
+ continue;
21
+ const values = Array.isArray(spec.default) ? spec.default : [spec.default];
22
+ const wrong = values.find((v) => typeof v !== spec.type);
23
+ if (wrong !== undefined)
24
+ errors.push(`Expected "${name}" default value to be of type "${String(spec.type)}", got "${typeof wrong}"`);
25
+ }
26
+ if (errors.length > 0)
27
+ throw new Error(`${errors.join('\n')}`);
28
+ }
29
+ export function requireImportMeta(importMeta) {
30
+ if (importMeta === undefined || typeof importMeta !== 'object' || typeof importMeta.url !== 'string') {
31
+ throw new TypeError('The `importMeta` option is required. Its value must be `import.meta`.');
32
+ }
33
+ try {
34
+ fileURLToPath(importMeta.url);
35
+ }
36
+ catch {
37
+ throw new TypeError('The `importMeta` option is required. Its value must be `import.meta`.');
38
+ }
39
+ }
40
+ export function validateCommands(commands) {
41
+ if (commands === undefined)
42
+ return;
43
+ if (!Array.isArray(commands))
44
+ throw new TypeError('The `commands` option must be an array of strings.');
45
+ if (commands.length === 0)
46
+ throw new TypeError('The `commands` option must contain at least one command.');
47
+ const bad = commands.some((c) => typeof c !== 'string' || c === '' || /\s/u.test(c) || c.startsWith('-'));
48
+ if (bad)
49
+ throw new TypeError('The `commands` option must be an array of non-empty strings without whitespace that do not start with `-`.');
50
+ }
51
+ export function checkChoices(specs, flags) {
52
+ const errors = [];
53
+ const badDefaults = Object.entries(specs).filter(([, spec]) => {
54
+ if (spec.default === undefined || !Array.isArray(spec.choices))
55
+ return false;
56
+ return (Array.isArray(spec.default) ? spec.default : [spec.default]).some((d) => !spec.choices?.includes(d));
57
+ });
58
+ if (badDefaults.length > 0) {
59
+ throw new Error(`Each value of the option \`default\` must exist within the option \`choices\`. Invalid flags: ${badDefaults.map(([n]) => `\`--${n}\``).join(', ')}`);
60
+ }
61
+ for (const [name, spec] of Object.entries(specs)) {
62
+ if (spec.choices === undefined || !Array.isArray(spec.choices))
63
+ continue;
64
+ const label = `--${decamelize(name, '-')}`;
65
+ const allowed = `[${spec.choices.map((c) => `\`${String(c)}\``).join(', ')}]`;
66
+ const value = flags[name];
67
+ const required = typeof spec.isRequired === 'function' ? true : spec.isRequired === true;
68
+ if (value === undefined || value === '') {
69
+ if (required)
70
+ errors.push(`Flag \`${label}\` has no value. Value must be one of: ${allowed}`);
71
+ continue;
72
+ }
73
+ const values = Array.isArray(value) ? value : [value];
74
+ const bad = values.filter((v) => !spec.choices?.includes(v));
75
+ if (bad.length > 0) {
76
+ errors.push(`Unknown value${bad.length > 1 ? 's' : ''} for flag \`${label}\`: ${bad.map((b) => `\`${String(b)}\``).join(', ')}. Value must be one of: ${allowed}`);
77
+ }
78
+ }
79
+ if (errors.length > 0)
80
+ throw new Error(`${errors.join('\n')}`);
81
+ }
82
+ export function checkRequired(specs, flags, input) {
83
+ const missing = [];
84
+ for (const [name, spec] of Object.entries(specs)) {
85
+ let required = spec.isRequired;
86
+ if (typeof spec.isRequired === 'function') {
87
+ required = spec.isRequired(flags, input);
88
+ if (typeof required !== 'boolean') {
89
+ throw new TypeError(`Return value for isRequired callback should be of type boolean, but ${typeof required} was returned.`);
90
+ }
91
+ }
92
+ if (required !== true)
93
+ continue;
94
+ const value = flags[name];
95
+ if (value !== undefined && value !== '' && !(Array.isArray(value) && value.length === 0))
96
+ continue;
97
+ const short = typeof spec.shortFlag === 'string' ? `, -${spec.shortFlag}` : '';
98
+ missing.push(`--${decamelize(name, '-')}${short}`);
99
+ }
100
+ if (missing.length > 0) {
101
+ reportAndExit(`Missing required flag${missing.length > 1 ? 's' : ''}\n${missing.map((m) => `\t${m}`).join('\n')}`);
102
+ }
103
+ }
104
+ export function checkUnknown(specs, parsedFlags, argv, opts) {
105
+ const known = new Set(['--']);
106
+ if (opts.autoHelp !== false)
107
+ known.add('help');
108
+ if (opts.autoVersion !== false)
109
+ known.add('version');
110
+ for (const [name, spec] of Object.entries(specs)) {
111
+ known.add(name);
112
+ known.add(decamelize(name, '-'));
113
+ if (typeof spec.shortFlag === 'string')
114
+ known.add(spec.shortFlag);
115
+ if (typeof spec.alias === 'string')
116
+ known.add(spec.alias);
117
+ }
118
+ const unknown = Object.keys(parsedFlags).filter((k) => !known.has(k) && !known.has(camelCase(k)) && !known.has(decamelize(k, '-')));
119
+ if (unknown.length > 0) {
120
+ const names = unknown.map((u) => (u.length === 1 ? `-${u}` : `--${decamelize(u, '-')}`));
121
+ reportAndExit(`Unknown flag${names.length > 1 ? 's' : ''}\n${names.join('\n')}`);
122
+ }
123
+ void argv;
124
+ }
125
+ export function checkInput(opts, input, flags) {
126
+ if (typeof opts.input !== 'object' || opts.input === null)
127
+ return;
128
+ const spec = opts.input;
129
+ const required = typeof spec.isRequired === 'function' ? spec.isRequired(flags, input) : spec.isRequired === true;
130
+ if (required && input.length === 0)
131
+ reportAndExit('Missing required input');
132
+ }
133
+ export function checkSetOnce(specs, parsed) {
134
+ for (const [name, spec] of Object.entries(specs)) {
135
+ if (spec.isMultiple === true || name === '--')
136
+ continue;
137
+ if (Array.isArray(parsed[name]))
138
+ throw new Error(`The flag --${decamelize(name, '-')} can only be set once.`);
139
+ }
140
+ }
141
+ export function reportAndExit(message) {
142
+ host.stderr.write(`${message}\n`);
143
+ return host.exit(ExitCode.USAGE);
144
+ }
package/dist/meow.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ import { type Options, type Result } from './meow/types.js';
2
+ export { type AnyFlag, type Options, type Result } from './meow/types.js';
3
+ /** meow, over burgee's parser. */
4
+ declare function meow(helpText: string | Options, options?: Options): Result;
5
+ declare const meowFacade: typeof meow;
6
+ export default meowFacade;