Skip to content

Commit f071c62

Browse files
committed
feat(inquirerer): add core CLI utilities and re-exports
- Add cli/argv.ts with extractFirst function for command routing - Add cli/error.ts with cliExitWithError function for error handling - Re-export ParsedArgs type from minimist - Re-export findAndRequirePackageJson for convenience This allows CLI tools to import all common utilities from 'inquirerer' instead of requiring separate imports from @inquirerer/utils, find-and-require-package-json, and minimist.
1 parent f8ad3c8 commit f071c62

File tree

4 files changed

+90
-0
lines changed

4 files changed

+90
-0
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { ParsedArgs } from 'minimist';
2+
3+
/**
4+
* Extracts the first positional argument from argv and returns it along with the remaining argv.
5+
* This is useful for command routing in CLI applications where the first argument is a subcommand.
6+
*
7+
* @example
8+
* ```typescript
9+
* const { first: command, newArgv } = extractFirst(argv);
10+
* if (command === 'init') {
11+
* await handleInit(newArgv);
12+
* }
13+
* ```
14+
*/
15+
export const extractFirst = (argv: Partial<ParsedArgs>) => {
16+
const first = argv._?.[0];
17+
const newArgv = {
18+
...argv,
19+
_: argv._?.slice(1) ?? []
20+
};
21+
return { first, newArgv };
22+
};
23+
24+
export type { ParsedArgs } from 'minimist';
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
export interface CliExitOptions {
2+
context?: Record<string, any>;
3+
beforeExit?: () => Promise<void>;
4+
logger?: {
5+
error: (message: string, ...args: any[]) => void;
6+
debug: (message: string, ...args: any[]) => void;
7+
warn: (message: string, ...args: any[]) => void;
8+
};
9+
}
10+
11+
/**
12+
* Exits the CLI with an error message and optional cleanup.
13+
* Supports a beforeExit hook for cleanup operations (e.g., closing database connections).
14+
*
15+
* @example
16+
* ```typescript
17+
* await cliExitWithError('Invalid configuration file');
18+
*
19+
* // With cleanup
20+
* await cliExitWithError(error, {
21+
* beforeExit: async () => {
22+
* await db.close();
23+
* }
24+
* });
25+
* ```
26+
*/
27+
export const cliExitWithError = async (
28+
error: Error | string,
29+
options: CliExitOptions = {}
30+
): Promise<never> => {
31+
const { context, beforeExit, logger = console } = options;
32+
33+
if (error instanceof Error) {
34+
logger.error(`Error: ${error.message}`);
35+
if (context) {
36+
logger.debug('Context:', context);
37+
}
38+
} else if (typeof error === 'string') {
39+
logger.error(`Error: ${error}`);
40+
if (context) {
41+
logger.debug('Context:', context);
42+
}
43+
}
44+
45+
if (beforeExit) {
46+
try {
47+
await beforeExit();
48+
logger.debug('Cleanup completed');
49+
} catch (cleanupError) {
50+
logger.warn('Failed to complete cleanup:', cleanupError);
51+
}
52+
}
53+
54+
process.exit(1);
55+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export { extractFirst } from './argv';
2+
export type { ParsedArgs } from './argv';
3+
4+
export { cliExitWithError } from './error';
5+
export type { CliExitOptions } from './error';

packages/inquirerer/src/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,9 @@ export * from './prompt';
33
export * from './question';
44
export * from './resolvers';
55
export * from './ui';
6+
7+
// CLI utilities for building command-line applications
8+
export * from './cli';
9+
10+
// Re-export package.json finder for convenience
11+
export { findAndRequirePackageJson } from 'find-and-require-package-json';

0 commit comments

Comments
 (0)