0
# User Interaction
1
2
Interactive utilities for user input, output formatting, visual feedback, and data processing in command-line scripts.
3
4
## Capabilities
5
6
### Output Functions
7
8
Display formatted output and information to users.
9
10
```typescript { .api }
11
/**
12
* Print formatted output to console
13
* @param args - Values to print (or template literal with interpolations)
14
*/
15
function echo(...args: any[]): void;
16
function echo(pieces: TemplateStringsArray, ...args: any[]): void;
17
```
18
19
**Usage Examples:**
20
21
```typescript
22
import { echo, $ } from "zx";
23
24
// Simple output
25
echo('Hello World');
26
echo('Deployment status:', 'success');
27
28
// Template literal format
29
const status = 'completed';
30
const time = new Date().toISOString();
31
echo`Deployment ${status} at ${time}`;
32
33
// With ProcessOutput
34
const result = await $`git branch --show-current`;
35
echo`Current branch: ${result}`;
36
37
// Multiple values
38
echo('Server:', 'production', 'Port:', 8080);
39
```
40
41
### User Input
42
43
Get interactive input from users with optional choices and completion.
44
45
```typescript { .api }
46
/**
47
* Prompt user for input with optional choices and completion
48
* @param query - Question to ask the user
49
* @param options - Configuration options
50
* @returns Promise resolving to user's input
51
*/
52
function question(
53
query?: string,
54
options?: {
55
/** Array of suggested choices for tab completion */
56
choices?: string[];
57
/** Input stream (default: process.stdin) */
58
input?: NodeJS.ReadStream;
59
/** Output stream (default: process.stdout) */
60
output?: NodeJS.WriteStream;
61
}
62
): Promise<string>;
63
```
64
65
**Usage Examples:**
66
67
```typescript
68
import { question, echo } from "zx";
69
70
// Simple question
71
const name = await question('What is your name? ');
72
echo`Hello, ${name}!`;
73
74
// With choices (tab completion)
75
const environment = await question('Deploy to which environment? ', {
76
choices: ['development', 'staging', 'production']
77
});
78
79
// Confirmation prompt
80
const proceed = await question('Continue with deployment? (y/n) ');
81
if (proceed.toLowerCase() !== 'y') {
82
echo('Deployment cancelled');
83
process.exit(0);
84
}
85
86
// Custom streams
87
import fs from 'fs';
88
const input = fs.createReadStream('./input.txt');
89
const response = await question('Question: ', { input });
90
```
91
92
### Standard Input Processing
93
94
Read and process data from standard input streams.
95
96
```typescript { .api }
97
/**
98
* Read all data from standard input
99
* @param stream - Input stream (default: process.stdin)
100
* @returns Promise resolving to input content as string
101
*/
102
function stdin(stream?: Readable): Promise<string>;
103
```
104
105
**Usage Examples:**
106
107
```typescript
108
import { stdin, echo, $ } from "zx";
109
110
// Read from standard input
111
echo('Please enter your data (Ctrl+D to finish):');
112
const input = await stdin();
113
echo`You entered: ${input}`;
114
115
// Process piped input
116
const data = await stdin();
117
const lines = data.trim().split('\n');
118
echo`Received ${lines.length} lines`;
119
120
// Use with custom stream
121
import fs from 'fs';
122
const fileStream = fs.createReadStream('./data.txt');
123
const fileContent = await stdin(fileStream);
124
echo`File content: ${fileContent}`;
125
126
// Combine with shell commands
127
const logData = await $`tail -f /var/log/system.log`.pipe(process.stdout);
128
```
129
130
### Visual Feedback
131
132
Provide visual feedback during long-running operations.
133
134
```typescript { .api }
135
/**
136
* Show a spinner during async operation execution
137
* @param title - Spinner text (optional)
138
* @param callback - Async function to execute
139
* @returns Promise resolving to callback result
140
*/
141
function spinner<T>(title: string, callback: () => T): Promise<T>;
142
function spinner<T>(callback: () => T): Promise<T>;
143
```
144
145
**Usage Examples:**
146
147
```typescript
148
import { spinner, $, sleep } from "zx";
149
150
// Simple spinner
151
const result = await spinner('Deploying application...', async () => {
152
await $`docker build -t myapp .`;
153
await $`docker push myapp`;
154
return 'success';
155
});
156
157
// Spinner without title
158
await spinner(async () => {
159
await sleep('2s');
160
await $`npm install`;
161
});
162
163
// Complex operations
164
const deployment = await spinner('Setting up infrastructure...', async () => {
165
// Multiple operations
166
await $`terraform init`;
167
await $`terraform plan -out=plan.out`;
168
await $`terraform apply plan.out`;
169
170
return {
171
status: 'deployed',
172
timestamp: new Date().toISOString()
173
};
174
});
175
176
echo`Deployment completed: ${deployment.status}`;
177
178
// Conditional spinner (disabled in CI)
179
const buildResult = await spinner('Building project...', async () => {
180
return await $`npm run build`;
181
});
182
// Spinner automatically disabled if process.env.CI is set
183
```
184
185
### Argument Processing
186
187
Parse and process command-line arguments.
188
189
```typescript { .api }
190
/**
191
* Parse command-line arguments with options
192
* @param args - Arguments array (default: process.argv.slice(2))
193
* @param opts - Parsing options
194
* @param defs - Default values
195
* @returns Parsed arguments object
196
*/
197
function parseArgv(
198
args?: string[],
199
opts?: ArgvOpts,
200
defs?: Record<string, any>
201
): minimist.ParsedArgs;
202
203
/**
204
* Update the global argv object with new arguments
205
* @param args - New arguments to parse
206
* @param opts - Parsing options
207
*/
208
function updateArgv(args?: string[], opts?: ArgvOpts): void;
209
210
/**
211
* Global parsed arguments object
212
*/
213
declare const argv: minimist.ParsedArgs;
214
215
interface ArgvOpts extends minimist.Opts {
216
/** Convert kebab-case to camelCase */
217
camelCase?: boolean;
218
/** Parse string 'true'/'false' to boolean */
219
parseBoolean?: boolean;
220
}
221
```
222
223
**Usage Examples:**
224
225
```typescript
226
import { parseArgv, argv, echo } from "zx";
227
228
// Using global argv
229
echo`Script called with:`, argv;
230
console.log('Environment:', argv.env || 'development');
231
console.log('Verbose mode:', argv.verbose || false);
232
233
// Custom argument parsing
234
const args = parseArgv(['--port', '3000', '--host', 'localhost', '--verbose'], {
235
default: { port: 8080 },
236
boolean: ['verbose'],
237
string: ['host']
238
});
239
console.log(args); // { port: 3000, host: 'localhost', verbose: true, _: [] }
240
241
// With camelCase conversion
242
const camelArgs = parseArgv(['--api-key', 'secret', '--max-retries', '3'], {
243
camelCase: true,
244
parseBoolean: true
245
});
246
console.log(camelArgs.apiKey); // 'secret'
247
console.log(camelArgs.maxRetries); // 3
248
249
// Update global argv
250
updateArgv(['--env', 'production'], { camelCase: true });
251
echo`Environment: ${argv.env}`;
252
253
// Default values
254
const config = parseArgv(process.argv.slice(2), {
255
default: {
256
port: 8080,
257
host: '0.0.0.0',
258
env: 'development'
259
},
260
boolean: ['verbose', 'debug'],
261
string: ['host', 'env'],
262
number: ['port']
263
});
264
```
265
266
### Sleep and Timing
267
268
Asynchronous delays and timing utilities.
269
270
```typescript { .api }
271
/**
272
* Asynchronous sleep/delay
273
* @param duration - Sleep duration (string like '2s', '500ms' or number in ms)
274
* @returns Promise that resolves after the specified duration
275
*/
276
function sleep(duration: Duration): Promise<void>;
277
278
type Duration = string | number;
279
```
280
281
**Usage Examples:**
282
283
```typescript
284
import { sleep, echo, $ } from "zx";
285
286
// String duration formats
287
await sleep('2s'); // 2 seconds
288
await sleep('500ms'); // 500 milliseconds
289
await sleep('1m'); // 1 minute
290
await sleep('1.5s'); // 1.5 seconds
291
292
// Numeric duration (milliseconds)
293
await sleep(1000); // 1 second
294
295
// In scripts
296
echo('Starting deployment...');
297
await sleep('1s');
298
299
await $`docker build -t myapp .`;
300
echo('Build complete, waiting before push...');
301
await sleep('2s');
302
303
await $`docker push myapp`;
304
echo('Deployment complete!');
305
306
// Retry with delays
307
for (let i = 0; i < 3; i++) {
308
try {
309
await $`curl -f https://api.example.com/health`;
310
echo('Service is healthy');
311
break;
312
} catch (error) {
313
echo(`Health check failed (attempt ${i + 1}), retrying...`);
314
await sleep('5s');
315
}
316
}
317
```
318
319
## Types
320
321
```typescript { .api }
322
/**
323
* Duration specification as string or milliseconds
324
*/
325
type Duration = string | number;
326
327
/**
328
* Parsed command-line arguments
329
*/
330
interface ParsedArgs {
331
/** Non-option arguments */
332
_: string[];
333
/** Named arguments */
334
[key: string]: any;
335
}
336
337
/**
338
* minimist parsing options extended with zx-specific options
339
*/
340
interface ArgvOpts extends minimist.Opts {
341
/** Convert kebab-case to camelCase */
342
camelCase?: boolean;
343
/** Parse 'true'/'false' strings to booleans */
344
parseBoolean?: boolean;
345
/** Default values for arguments */
346
default?: Record<string, any>;
347
/** Keys that should be treated as booleans */
348
boolean?: string | string[];
349
/** Keys that should be treated as strings */
350
string?: string | string[];
351
/** Keys that should be treated as numbers */
352
number?: string | string[];
353
/** Argument aliases */
354
alias?: Record<string, string | string[]>;
355
}
356
357
/**
358
* Node.js readable stream interface
359
*/
360
interface Readable extends NodeJS.ReadableStream {
361
setEncoding(encoding: BufferEncoding): this;
362
[Symbol.asyncIterator](): AsyncIterableIterator<any>;
363
}
364
```