|
| 1 | +# Creating Commands |
| 2 | + |
| 3 | +## Command Structure |
| 4 | + |
| 5 | +Commands in `doc-kit` are defined as modules that export a command object conforming to the `Command` interface: |
| 6 | + |
| 7 | +```typescript |
| 8 | +interface Command { |
| 9 | + name: string; |
| 10 | + description: string; |
| 11 | + options: { [key: string]: Option }; |
| 12 | + action: (options: any) => Promise<void>; |
| 13 | +} |
| 14 | +``` |
| 15 | + |
| 16 | +Each command consists of: |
| 17 | + |
| 18 | +- **name**: The command name used in the CLI (e.g., `generate`, `interactive`) |
| 19 | +- **description**: A short description shown in help text |
| 20 | +- **options**: An object mapping option names to their definitions |
| 21 | +- **action**: The async function that executes when the command is run |
| 22 | + |
| 23 | +## Creating a New Command |
| 24 | + |
| 25 | +### Step 1: Create the Command File |
| 26 | + |
| 27 | +Create a new file in `bin/commands/` with your command name: |
| 28 | + |
| 29 | +```javascript |
| 30 | +// bin/commands/my-command.mjs |
| 31 | +import logger from '../../src/logger/index.mjs'; |
| 32 | + |
| 33 | +/** |
| 34 | + * @type {import('./types').Command} |
| 35 | + */ |
| 36 | +export default { |
| 37 | + name: 'my-command', |
| 38 | + description: 'Does something useful', |
| 39 | + |
| 40 | + options: { |
| 41 | + // Define your options here (see next section) |
| 42 | + }, |
| 43 | + |
| 44 | + async action(opts) { |
| 45 | + logger.info('Starting my-command', opts); |
| 46 | + |
| 47 | + // Your command logic here |
| 48 | + |
| 49 | + logger.info('Completed my-command'); |
| 50 | + }, |
| 51 | +}; |
| 52 | +``` |
| 53 | + |
| 54 | +### Step 2: Register the Command |
| 55 | + |
| 56 | +Add your command to the exports in `bin/commands/index.mjs`: |
| 57 | + |
| 58 | +```javascript |
| 59 | +import generate from './generate.mjs'; |
| 60 | +import interactive from './interactive.mjs'; |
| 61 | +import myCommand from './my-command.mjs'; // Add this |
| 62 | + |
| 63 | +export default [ |
| 64 | + generate, |
| 65 | + interactive, |
| 66 | + myCommand, // Add this |
| 67 | +]; |
| 68 | +``` |
| 69 | + |
| 70 | +### Step 3: Update CLI Entry Point |
| 71 | + |
| 72 | +The CLI in `bin/cli.mjs` automatically loads commands from `bin/commands/index.mjs`, so no changes are needed there if you followed step 2. |
| 73 | + |
| 74 | +## Command Options |
| 75 | + |
| 76 | +Options define the flags and parameters your command accepts. Each option has: |
| 77 | + |
| 78 | +```typescript |
| 79 | +interface Option { |
| 80 | + flags: string[]; // CLI flags (e.g., ['-i', '--input <value>']) |
| 81 | + desc: string; // Description for help text |
| 82 | + prompt?: PromptConfig; // Interactive mode configuration |
| 83 | +} |
| 84 | +``` |
| 85 | + |
| 86 | +### Defining Options |
| 87 | + |
| 88 | +```javascript |
| 89 | +options: { |
| 90 | + input: { |
| 91 | + flags: ['-i', '--input <patterns...>'], |
| 92 | + desc: 'Input file patterns (glob)', |
| 93 | + prompt: { |
| 94 | + type: 'text', |
| 95 | + message: 'Enter input glob patterns', |
| 96 | + variadic: true, |
| 97 | + required: true, |
| 98 | + }, |
| 99 | + }, |
| 100 | + |
| 101 | + force: { |
| 102 | + flags: ['-f', '--force'], |
| 103 | + desc: 'Force overwrite existing files', |
| 104 | + prompt: { |
| 105 | + type: 'confirm', |
| 106 | + message: 'Overwrite existing files?', |
| 107 | + initialValue: false, |
| 108 | + }, |
| 109 | + }, |
| 110 | + |
| 111 | + mode: { |
| 112 | + flags: ['-m', '--mode <mode>'], |
| 113 | + desc: 'Operation mode', |
| 114 | + prompt: { |
| 115 | + type: 'select', |
| 116 | + message: 'Choose operation mode', |
| 117 | + options: [ |
| 118 | + { label: 'Fast', value: 'fast' }, |
| 119 | + { label: 'Thorough', value: 'thorough' }, |
| 120 | + ], |
| 121 | + }, |
| 122 | + }, |
| 123 | +} |
| 124 | +``` |
| 125 | + |
| 126 | +### Flag Syntax |
| 127 | + |
| 128 | +- `<value>` - Required argument |
| 129 | +- `[value]` - Optional argument |
| 130 | +- `<values...>` - Variadic (multiple values) |
| 131 | +- `[values...]` - Optional variadic |
| 132 | + |
| 133 | +### Option Types |
| 134 | + |
| 135 | +#### `text` |
| 136 | +Single-line text input. |
| 137 | + |
| 138 | +```javascript |
| 139 | +prompt: { |
| 140 | + type: 'text', |
| 141 | + message: 'Enter a value', |
| 142 | + initialValue: 'default', |
| 143 | + required: true, |
| 144 | +} |
| 145 | +``` |
| 146 | + |
| 147 | +#### `confirm` |
| 148 | +Yes/no confirmation. |
| 149 | + |
| 150 | +```javascript |
| 151 | +prompt: { |
| 152 | + type: 'confirm', |
| 153 | + message: 'Are you sure?', |
| 154 | + initialValue: false, |
| 155 | +} |
| 156 | +``` |
| 157 | + |
| 158 | +#### `select` |
| 159 | +Single choice from a list. |
| 160 | + |
| 161 | +```javascript |
| 162 | +prompt: { |
| 163 | + type: 'select', |
| 164 | + message: 'Choose one', |
| 165 | + options: [ |
| 166 | + { label: 'Option 1', value: 'opt1' }, |
| 167 | + { label: 'Option 2', value: 'opt2' }, |
| 168 | + ], |
| 169 | +} |
| 170 | +``` |
| 171 | + |
| 172 | +#### `multiselect` |
| 173 | +Multiple choices from a list. |
| 174 | + |
| 175 | +```javascript |
| 176 | +prompt: { |
| 177 | + type: 'multiselect', |
| 178 | + message: 'Choose multiple', |
| 179 | + options: [ |
| 180 | + { label: 'Choice A', value: 'a' }, |
| 181 | + { label: 'Choice B', value: 'b' }, |
| 182 | + ], |
| 183 | +} |
| 184 | +``` |
| 185 | + |
| 186 | +## Interactive Prompts |
| 187 | + |
| 188 | +The `interactive` command automatically uses the `prompt` configuration from your options. When users run: |
| 189 | + |
| 190 | +```bash |
| 191 | +doc-kit interactive |
| 192 | +``` |
| 193 | + |
| 194 | +They'll be prompted to select a command, then guided through all required options. |
| 195 | + |
| 196 | +### Prompt Configuration |
| 197 | + |
| 198 | +- **message**: Question to ask the user |
| 199 | +- **type**: Input type (`text`, `confirm`, `select`, `multiselect`) |
| 200 | +- **required**: Whether the field must have a value |
| 201 | +- **initialValue**: Default value |
| 202 | +- **variadic**: Whether multiple values can be entered (for `text` type) |
| 203 | +- **options**: Choices for `select`/`multiselect` types |
| 204 | + |
| 205 | +### Making Options Interactive-Friendly |
| 206 | + |
| 207 | +Always provide helpful messages and sensible defaults: |
| 208 | + |
| 209 | +```javascript |
| 210 | +threads: { |
| 211 | + flags: ['-p', '--threads <number>'], |
| 212 | + desc: 'Number of threads to use (minimum: 1)', |
| 213 | + prompt: { |
| 214 | + type: 'text', |
| 215 | + message: 'How many threads to allow', |
| 216 | + initialValue: String(cpus().length), // Smart default |
| 217 | + }, |
| 218 | +}, |
| 219 | +``` |
0 commit comments