-
Notifications
You must be signed in to change notification settings - Fork 66
Expand file tree
/
Copy pathdefine-subcommand-group.mts
More file actions
118 lines (110 loc) · 3.94 KB
/
Copy pathdefine-subcommand-group.mts
File metadata and controls
118 lines (110 loc) · 3.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/**
* Factory for "subcommand group" routers like `socket scan`, `socket package`,
* `socket manifest`, `socket organization`. These commands are pure routers:
* they delegate to a static map of child subcommands and optional aliases.
*
* Pre-factory the four router files used three subtly different shapes — one
* declared a top-level `config` object whose flags were never consumed, another
* inlined the meow call, the third had a `hidden: false` field that only
* existed to satisfy the CliSubcommand type. This helper unifies the shape into
* a single declarative spec:
*
* Export const cmdScan = defineSubcommandGroup({ name: 'scan', description:
* 'Manage Socket scans', subcommands: { create: cmdScanCreate, … }, aliases: {
* meta: { argv: ['metadata'], hidden: true, … } }, })
*/
import { commonFlags } from '../../flags.mts'
import { defineFlags } from '../../meow.mts'
import { meowWithSubcommands } from './with-subcommands.mts'
import type { MeowFlags } from '../../flags.mts'
import type { CliAliases, CliSubcommand } from './with-subcommands-shared.mts'
export interface DefineSubcommandGroupConfig<CommandName extends string> {
/**
* Group name as it appears under `socket`. Used as the second token of the
* usage string (`socket <name> <subcommand>`).
*/
name: string
/**
* One-line description for the parent command's help bucket and the `socket
* --help` listing.
*/
description: string
/**
* Hide the group from `socket --help`. Defaults to false.
*/
hidden?: boolean | undefined
/**
* Map of subcommand name → CliSubcommand. The router routes the first
* positional arg to the matching entry.
*/
subcommands: Record<CommandName, CliSubcommand>
/**
* Optional aliases. Each key is an alternative name for the group; its `argv`
* is the canonical command tokens to invoke (e.g. `aliases: { deps: { argv:
* ['dependencies'], … } }`).
*/
aliases?: CliAliases | undefined
/**
* If true, pass the standard `commonFlags` (--dry-run, --help, --json,
* --markdown, etc.) to meowWithSubcommands so the group's `--help` page lists
* them. Defaults to false, no flags surface.
*
* Routers that previously declared `config = { flags: defineFlags({
* ...commonFlags }) }` should pass `passCommonFlags: true` to preserve the
* existing help output and any test assertions that inspect the outgoing
* `config.flags`.
*/
passCommonFlags?: boolean | undefined
/**
* Override the flags passed to meowWithSubcommands. Takes precedence over
* `passCommonFlags`. Useful for groups that need extra flags beyond the
* common set.
*/
flags?: MeowFlags | undefined
}
/**
* Define a subcommand-group router. Returns a CliSubcommand-shaped object ready
* to plug into the parent meow router.
*
* The returned object only includes a `hidden` field when the caller explicitly
* passes one — this preserves the shape of the pre-refactor routers (which
* never had a `hidden` field at all) and keeps existing test assertions about
* object identity / strict shape working.
*/
export function defineSubcommandGroup<CommandName extends string>(
config: DefineSubcommandGroupConfig<CommandName>,
): CliSubcommand {
const {
aliases,
description,
flags,
hidden,
name,
passCommonFlags,
subcommands,
} = { __proto__: null, ...config } as typeof config
const effectiveFlags =
flags ?? (passCommonFlags ? defineFlags({ ...commonFlags }) : undefined)
const result: CliSubcommand = {
description,
async run(argv, importMeta, { parentName }) {
await meowWithSubcommands(
{
argv,
name: `${parentName} ${name}`,
importMeta,
subcommands,
},
{
...(aliases ? { aliases } : {}),
description,
...(effectiveFlags ? { flags: effectiveFlags } : {}),
},
)
},
}
if (hidden !== undefined) {
result.hidden = hidden
}
return result
}