UNPKG

13.7 kBTypeScriptView Raw
1/// <reference types="node" />
2/// <reference types="node" />
3import { Readable, Writable } from 'stream';
4import { CommandBuilder } from '../core';
5import { ColorFormat } from '../format';
6import { CommandClass, Command, Definition } from './Command';
7import { CommandOption } from './options/utils';
8type MakeOptional<T, Keys extends keyof T> = Omit<T, Keys> & Partial<Pick<T, Keys>>;
9type VoidIfEmpty<T> = keyof T extends never ? void : never;
10/**
11 * The base context of the CLI.
12 *
13 * All Contexts have to extend it.
14 */
15export type BaseContext = {
16 /**
17 * Environment variables.
18 *
19 * @default
20 * process.env
21 */
22 env: Record<string, string | undefined>;
23 /**
24 * The input stream of the CLI.
25 *
26 * @default
27 * process.stdin
28 */
29 stdin: Readable;
30 /**
31 * The output stream of the CLI.
32 *
33 * @default
34 * process.stdout
35 */
36 stdout: Writable;
37 /**
38 * The error stream of the CLI.
39 *
40 * @default
41 * process.stderr
42 */
43 stderr: Writable;
44 /**
45 * Whether colors should be enabled.
46 */
47 colorDepth: number;
48};
49export type CliContext<Context extends BaseContext> = {
50 commandClass: CommandClass<Context>;
51};
52export type UserContextKeys<Context extends BaseContext> = Exclude<keyof Context, keyof BaseContext>;
53export type UserContext<Context extends BaseContext> = Pick<Context, UserContextKeys<Context>>;
54export type PartialContext<Context extends BaseContext> = UserContextKeys<Context> extends never ? Partial<Pick<Context, keyof BaseContext>> | undefined | void : Partial<Pick<Context, keyof BaseContext>> & UserContext<Context>;
55export type RunContext<Context extends BaseContext = BaseContext> = Partial<Pick<Context, keyof BaseContext>> & UserContext<Context>;
56export type RunCommand<Context extends BaseContext = BaseContext> = Array<CommandClass<Context>> | CommandClass<Context>;
57export type RunCommandNoContext<Context extends BaseContext = BaseContext> = UserContextKeys<Context> extends never ? RunCommand<Context> : never;
58export type CliOptions = Readonly<{
59 /**
60 * The label of the binary.
61 *
62 * Shown at the top of the usage information.
63 */
64 binaryLabel?: string;
65 /**
66 * The name of the binary.
67 *
68 * Included in the path and the examples of the definitions.
69 */
70 binaryName: string;
71 /**
72 * The version of the binary.
73 *
74 * Shown at the top of the usage information.
75 */
76 binaryVersion?: string;
77 /**
78 * If `true`, the Cli will hook into the process standard streams to catch
79 * the output produced by console.log and redirect them into the context
80 * streams. Note: stdin isn't captured at the moment.
81 *
82 * @default
83 * false
84 */
85 enableCapture: boolean;
86 /**
87 * If `true`, the Cli will use colors in the output. If `false`, it won't.
88 * If `undefined`, Clipanion will infer the correct value from the env.
89 */
90 enableColors?: boolean;
91}>;
92export type MiniCli<Context extends BaseContext> = CliOptions & {
93 /**
94 * Returns an Array representing the definitions of all registered commands.
95 */
96 definitions(): Array<Definition>;
97 /**
98 * Get the definition of a particular command.
99 */
100 definition(command: CommandClass<Context>): Definition | null;
101 /**
102 * Formats errors using colors.
103 *
104 * @param error The error to format. If `error.name` is `'Error'`, it is replaced with `'Internal Error'`.
105 * @param opts.command The command whose usage will be included in the formatted error.
106 */
107 error(error: Error, opts?: {
108 command?: Command<Context> | null;
109 }): string;
110 /**
111 * Returns a rich color format if colors are enabled, or a plain text format otherwise.
112 *
113 * @param colored Forcefully enable or disable colors.
114 */
115 format(colored?: boolean): ColorFormat;
116 /**
117 * Compiles a command and its arguments using the `CommandBuilder`.
118 *
119 * @param input An array containing the name of the command and its arguments
120 *
121 * @returns The compiled `Command`, with its properties populated with the arguments.
122 */
123 process(input: Array<string>, context?: Partial<Context>): Command<Context>;
124 /**
125 * Runs a command.
126 *
127 * @param input An array containing the name of the command and its arguments
128 * @param context Overrides the Context of the main `Cli` instance
129 *
130 * @returns The exit code of the command
131 */
132 run(input: Array<string>, context?: Partial<Context>): Promise<number>;
133 /**
134 * Returns the usage of a command.
135 *
136 * @param command The `Command` whose usage will be returned or `null` to return the usage of all commands.
137 * @param opts.detailed If `true`, the usage of a command will also include its description, details, and examples. Doesn't have any effect if `command` is `null` or doesn't have a `usage` property.
138 * @param opts.prefix The prefix displayed before each command. Defaults to `$`.
139 */
140 usage(command?: CommandClass<Context> | Command<Context> | null, opts?: {
141 detailed?: boolean;
142 prefix?: string;
143 }): string;
144};
145export type MandatoryContextKeys<Context extends BaseContext> = keyof MandatoryContext<Context>;
146export type MandatoryContext<Context extends BaseContext> = {
147 [K in Exclude<keyof Context, keyof BaseContext> as undefined extends Context[K] ? never : K]: Context[K];
148};
149export type UserProvidedContext<Context extends BaseContext> = MandatoryContext<Context> & Partial<Omit<Context, MandatoryContextKeys<Context>>>;
150export type MaybeProvidedContext<Context extends BaseContext> = MandatoryContextKeys<Context> extends never ? {
151 context?: UserProvidedContext<Context>;
152} : {
153 context: UserProvidedContext<Context>;
154};
155export type ProcessOptions<Context extends BaseContext> = MaybeProvidedContext<Context> & {
156 input: Array<string>;
157 /**
158 * @deprecated Experimental setting, exact behavior may change
159 */
160 partial?: boolean;
161};
162/**
163 * An all-in-one helper that simultaneously instantiate a CLI and immediately
164 * executes it. All parameters are optional except the command classes and
165 * will be filled by sensible values for the current environment (for example
166 * the argv argument will default to `process.argv`, etc).
167 *
168 * Just like `Cli#runExit`, this function will set the `process.exitCode` value
169 * before returning.
170 */
171export declare function runExit<Context extends BaseContext = BaseContext>(commandClasses: RunCommandNoContext<Context>): Promise<void>;
172export declare function runExit<Context extends BaseContext = BaseContext>(commandClasses: RunCommand<Context>, context: RunContext<Context>): Promise<void>;
173export declare function runExit<Context extends BaseContext = BaseContext>(options: Partial<CliOptions>, commandClasses: RunCommandNoContext<Context>): Promise<void>;
174export declare function runExit<Context extends BaseContext = BaseContext>(options: Partial<CliOptions>, commandClasses: RunCommand<Context>, context: RunContext<Context>): Promise<void>;
175export declare function runExit<Context extends BaseContext = BaseContext>(commandClasses: RunCommandNoContext<Context>, argv: Array<string>): Promise<void>;
176export declare function runExit<Context extends BaseContext = BaseContext>(commandClasses: RunCommand<Context>, argv: Array<string>, context: RunContext<Context>): Promise<void>;
177export declare function runExit<Context extends BaseContext = BaseContext>(options: Partial<CliOptions>, commandClasses: RunCommandNoContext<Context>, argv: Array<string>): Promise<void>;
178export declare function runExit<Context extends BaseContext = BaseContext>(options: Partial<CliOptions>, commandClasses: RunCommand<Context>, argv: Array<string>, context: RunContext<Context>): Promise<void>;
179/**
180 * An all-in-one helper that simultaneously instantiate a CLI and immediately
181 * executes it. All parameters are optional except the command classes and
182 * will be filled by sensible values for the current environment (for example
183 * the argv argument will default to `process.argv`, etc).
184 *
185 * Unlike `runExit`, this function won't set the `process.exitCode` value
186 * before returning.
187 */
188export declare function run<Context extends BaseContext = BaseContext>(commandClasses: RunCommandNoContext<Context>): Promise<number>;
189export declare function run<Context extends BaseContext = BaseContext>(commandClasses: RunCommand<Context>, context: RunContext<Context>): Promise<number>;
190export declare function run<Context extends BaseContext = BaseContext>(options: Partial<CliOptions>, commandClasses: RunCommandNoContext<Context>): Promise<number>;
191export declare function run<Context extends BaseContext = BaseContext>(options: Partial<CliOptions>, commandClasses: RunCommand<Context>, context: RunContext<Context>): Promise<number>;
192export declare function run<Context extends BaseContext = BaseContext>(commandClasses: RunCommandNoContext<Context>, argv: Array<string>): Promise<number>;
193export declare function run<Context extends BaseContext = BaseContext>(commandClasses: RunCommand<Context>, argv: Array<string>, context: RunContext<Context>): Promise<number>;
194export declare function run<Context extends BaseContext = BaseContext>(options: Partial<CliOptions>, commandClasses: RunCommandNoContext<Context>, argv: Array<string>): Promise<number>;
195export declare function run<Context extends BaseContext = BaseContext>(options: Partial<CliOptions>, commandClasses: RunCommand<Context>, argv: Array<string>, context: RunContext<Context>): Promise<number>;
196/**
197 * @template Context The context shared by all commands. Contexts are a set of values, defined when calling the `run`/`runExit` functions from the CLI instance, that will be made available to the commands via `this.context`.
198 */
199export declare class Cli<Context extends BaseContext = BaseContext> implements Omit<MiniCli<Context>, `process` | `run`> {
200 /**
201 * The default context of the CLI.
202 *
203 * Contains the stdio of the current `process`.
204 */
205 static defaultContext: {
206 env: NodeJS.ProcessEnv;
207 stdin: NodeJS.ReadStream & {
208 fd: 0;
209 };
210 stdout: NodeJS.WriteStream & {
211 fd: 1;
212 };
213 stderr: NodeJS.WriteStream & {
214 fd: 2;
215 };
216 colorDepth: number;
217 };
218 private readonly builder;
219 protected readonly registrations: Map<CommandClass<Context>, {
220 index: number;
221 builder: CommandBuilder<CliContext<Context>>;
222 specs: Map<string, CommandOption<unknown>>;
223 }>;
224 readonly binaryLabel?: string;
225 readonly binaryName: string;
226 readonly binaryVersion?: string;
227 readonly enableCapture: boolean;
228 readonly enableColors?: boolean;
229 /**
230 * Creates a new Cli and registers all commands passed as parameters.
231 *
232 * @param commandClasses The Commands to register
233 * @returns The created `Cli` instance
234 */
235 static from<Context extends BaseContext = BaseContext>(commandClasses: RunCommand<Context>, options?: Partial<CliOptions>): Cli<Context>;
236 constructor({ binaryLabel, binaryName: binaryNameOpt, binaryVersion, enableCapture, enableColors }?: Partial<CliOptions>);
237 /**
238 * Registers a command inside the CLI.
239 */
240 register(commandClass: CommandClass<Context>): void;
241 process(opts: ProcessOptions<Context>): Command<Context>;
242 process(input: Array<string>, context: VoidIfEmpty<Omit<Context, keyof BaseContext>>): Command<Context>;
243 process(input: Array<string>, context: MakeOptional<Context, keyof BaseContext>): Command<Context>;
244 run(input: Command<Context> | Array<string>, context: VoidIfEmpty<Omit<Context, keyof BaseContext>>): Promise<number>;
245 run(input: Command<Context> | Array<string>, context: MakeOptional<Context, keyof BaseContext>): Promise<number>;
246 /**
247 * Runs a command and exits the current `process` with the exit code returned by the command.
248 *
249 * @param input An array containing the name of the command and its arguments.
250 *
251 * @example
252 * cli.runExit(process.argv.slice(2))
253 */
254 runExit(input: Command<Context> | Array<string>, context: VoidIfEmpty<Omit<Context, keyof BaseContext>>): Promise<void>;
255 runExit(input: Command<Context> | Array<string>, context: MakeOptional<Context, keyof BaseContext>): Promise<void>;
256 definition(commandClass: CommandClass<Context>, { colored }?: {
257 colored?: boolean;
258 }): Definition | null;
259 definitions({ colored }?: {
260 colored?: boolean;
261 }): Array<Definition>;
262 usage(command?: CommandClass<Context> | Command<Context> | null, { colored, detailed, prefix }?: {
263 colored?: boolean;
264 detailed?: boolean;
265 prefix?: string;
266 }): string;
267 error(error: Error | any, { colored, command }?: {
268 colored?: boolean;
269 command?: Command<Context> | null;
270 }): string;
271 format(colored?: boolean): ColorFormat;
272 protected getUsageByRegistration(klass: CommandClass<Context>, opts?: {
273 detailed?: boolean;
274 inlineOptions?: boolean;
275 }): {
276 usage: string;
277 options: {
278 preferredName: string;
279 nameSet: string[];
280 definition: string;
281 description: string;
282 required: boolean;
283 }[];
284 };
285 protected getUsageByIndex(n: number, opts?: {
286 detailed?: boolean;
287 inlineOptions?: boolean;
288 }): {
289 usage: string;
290 options: {
291 preferredName: string;
292 nameSet: string[];
293 definition: string;
294 description: string;
295 required: boolean;
296 }[];
297 };
298}
299export {};