UNPKG

8.12 kBTypeScriptView Raw
1import type {
2 CamelCasedProperties,
3 PackageJson,
4} from 'type-fest';
5
6export type FlagType = 'string' | 'boolean' | 'number';
7
8/**
9Callback function to determine if a flag is required during runtime.
10
11@param flags - Contains the flags converted to camel-case excluding aliases.
12@param input - Contains the non-flag arguments.
13
14@returns True if the flag is required, otherwise false.
15*/
16export type IsRequiredPredicate = (flags: Readonly<AnyFlags>, input: readonly string[]) => boolean;
17
18export type Flag<Type extends FlagType, Default, IsMultiple = false> = {
19 readonly type?: Type;
20 readonly alias?: string;
21 readonly default?: Default;
22 readonly isRequired?: boolean | IsRequiredPredicate;
23 readonly isMultiple?: IsMultiple;
24};
25
26type StringFlag = Flag<'string', string> | Flag<'string', string[], true>;
27type BooleanFlag = Flag<'boolean', boolean> | Flag<'boolean', boolean[], true>;
28type NumberFlag = Flag<'number', number> | Flag<'number', number[], true>;
29type AnyFlag = StringFlag | BooleanFlag | NumberFlag;
30type AnyFlags = Record<string, AnyFlag>;
31
32export type Options<Flags extends AnyFlags> = {
33 /**
34 Pass in [`import.meta`](https://nodejs.org/dist/latest/docs/api/esm.html#esm_import_meta). This is used to find the correct package.json file.
35 */
36 readonly importMeta: ImportMeta;
37
38 /**
39 Define argument flags.
40
41 The key is the flag name in camel-case and the value is an object with any of:
42
43 - `type`: Type of value. (Possible values: `string` `boolean` `number`)
44 - `alias`: Usually used to define a short flag alias.
45 - `default`: Default value when the flag is not specified.
46 - `isRequired`: Determine if the flag is required.
47 If it's only known at runtime whether the flag is required or not you can pass a Function instead of a boolean, which based on the given flags and other non-flag arguments should decide if the flag is required.
48 - `isMultiple`: Indicates a flag can be set multiple times. Values are turned into an array. (Default: false)
49 Multiple values are provided by specifying the flag multiple times, for example, `$ foo -u rainbow -u cat`. Space- or comma-separated values are *not* supported.
50
51 Note that flags are always defined using a camel-case key (`myKey`), but will match arguments in kebab-case (`--my-key`).
52
53 @example
54 ```
55 flags: {
56 unicorn: {
57 type: 'string',
58 alias: 'u',
59 default: ['rainbow', 'cat'],
60 isMultiple: true,
61 isRequired: (flags, input) => {
62 if (flags.otherFlag) {
63 return true;
64 }
65
66 return false;
67 }
68 }
69 }
70 ```
71 */
72 readonly flags?: Flags;
73
74 /**
75 Description to show above the help text. Default: The package.json `"description"` property.
76
77 Set it to `false` to disable it altogether.
78 */
79 readonly description?: string | false;
80
81 /**
82 The help text you want shown.
83
84 The input is reindented and starting/ending newlines are trimmed which means you can use a [template literal](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/template_strings) without having to care about using the correct amount of indent.
85
86 The description will be shown above your help text automatically.
87
88 Set it to `false` to disable it altogether.
89 */
90 readonly help?: string | false;
91
92 /**
93 Set a custom version output. Default: The package.json `"version"` property.
94
95 Set it to `false` to disable it altogether.
96 */
97 readonly version?: string | false;
98
99 /**
100 Automatically show the help text when the `--help` flag is present. Useful to set this value to `false` when a CLI manages child CLIs with their own help text.
101
102 This option is only considered when there is only one argument in `process.argv`.
103 */
104 readonly autoHelp?: boolean;
105
106 /**
107 Automatically show the version text when the `--version` flag is present. Useful to set this value to `false` when a CLI manages child CLIs with their own version text.
108
109 This option is only considered when there is only one argument in `process.argv`.
110 */
111 readonly autoVersion?: boolean;
112
113 /**
114 `package.json` as an `Object`. Default: Closest `package.json` upwards.
115
116 _You most likely don't need this option._
117 */
118 readonly pkg?: Record<string, unknown>;
119
120 /**
121 Custom arguments object.
122
123 @default process.argv.slice(2)
124 */
125 readonly argv?: readonly string[];
126
127 /**
128 Infer the argument type.
129
130 By default, the argument `5` in `$ foo 5` becomes a string. Enabling this would infer it as a number.
131
132 @default false
133 */
134 readonly inferType?: boolean;
135
136 /**
137 Value of `boolean` flags not defined in `argv`.
138
139 If set to `undefined`, the flags not defined in `argv` will be excluded from the result. The `default` value set in `boolean` flags take precedence over `booleanDefault`.
140
141 _Note: If used in conjunction with `isMultiple`, the default flag value is set to `[]`._
142
143 __Caution: Explicitly specifying `undefined` for `booleanDefault` has different meaning from omitting key itself.__
144
145 @example
146 ```
147 import meow from 'meow';
148
149 const cli = meow(`
150 Usage
151 $ foo
152
153 Options
154 --rainbow, -r Include a rainbow
155 --unicorn, -u Include a unicorn
156 --no-sparkles Exclude sparkles
157
158 Examples
159 $ foo
160 🌈 unicorns✨🌈
161 `, {
162 importMeta: import.meta,
163 booleanDefault: undefined,
164 flags: {
165 rainbow: {
166 type: 'boolean',
167 default: true,
168 alias: 'r'
169 },
170 unicorn: {
171 type: 'boolean',
172 default: false,
173 alias: 'u'
174 },
175 cake: {
176 type: 'boolean',
177 alias: 'c'
178 },
179 sparkles: {
180 type: 'boolean',
181 default: true
182 }
183 }
184 });
185
186 //{
187 // flags: {
188 // rainbow: true,
189 // unicorn: false,
190 // sparkles: true
191 // },
192 // unnormalizedFlags: {
193 // rainbow: true,
194 // r: true,
195 // unicorn: false,
196 // u: false,
197 // sparkles: true
198 // },
199 // …
200 //}
201 ```
202 */
203 // eslint-disable-next-line @typescript-eslint/ban-types
204 readonly booleanDefault?: boolean | null | undefined;
205
206 /**
207 Whether to use [hard-rejection](https://github.com/sindresorhus/hard-rejection) or not. Disabling this can be useful if you need to handle `process.on('unhandledRejection')` yourself.
208
209 @default true
210 */
211 readonly hardRejection?: boolean;
212
213 /**
214 Whether to allow unknown flags or not.
215
216 @default true
217 */
218 readonly allowUnknownFlags?: boolean;
219};
220
221type TypedFlag<Flag extends AnyFlag> =
222 Flag extends {type: 'number'}
223 ? number
224 : Flag extends {type: 'string'}
225 ? string
226 : Flag extends {type: 'boolean'}
227 ? boolean
228 : unknown;
229
230type PossiblyOptionalFlag<Flag extends AnyFlag, FlagType> =
231 Flag extends {isRequired: true}
232 ? FlagType
233 : Flag extends {default: any}
234 ? FlagType
235 : FlagType | undefined;
236
237export type TypedFlags<Flags extends AnyFlags> = {
238 [F in keyof Flags]: Flags[F] extends {isMultiple: true}
239 ? PossiblyOptionalFlag<Flags[F], Array<TypedFlag<Flags[F]>>>
240 : PossiblyOptionalFlag<Flags[F], TypedFlag<Flags[F]>>
241};
242
243export type Result<Flags extends AnyFlags> = {
244 /**
245 Non-flag arguments.
246 */
247 input: string[];
248
249 /**
250 Flags converted to camelCase excluding aliases.
251 */
252 flags: CamelCasedProperties<TypedFlags<Flags>> & Record<string, unknown>;
253
254 /**
255 Flags converted camelCase including aliases.
256 */
257 unnormalizedFlags: TypedFlags<Flags> & Record<string, unknown>;
258
259 /**
260 The `package.json` object.
261 */
262 pkg: PackageJson;
263
264 /**
265 The help text used with `--help`.
266 */
267 help: string;
268
269 /**
270 Show the help text and exit with code.
271
272 @param exitCode - The exit code to use. Default: `2`.
273 */
274 showHelp: (exitCode?: number) => never;
275
276 /**
277 Show the version text and exit.
278 */
279 showVersion: () => void;
280};
281/**
282@param helpMessage - Shortcut for the `help` option.
283
284@example
285```
286#!/usr/bin/env node
287import meow from 'meow';
288import foo from './index.js';
289
290const cli = meow(`
291 Usage
292 $ foo <input>
293
294 Options
295 --rainbow, -r Include a rainbow
296
297 Examples
298 $ foo unicorns --rainbow
299 🌈 unicorns 🌈
300`, {
301 importMeta: import.meta,
302 flags: {
303 rainbow: {
304 type: 'boolean',
305 alias: 'r'
306 }
307 }
308});
309
310//{
311// input: ['unicorns'],
312// flags: {rainbow: true},
313// ...
314//}
315
316foo(cli.input[0], cli.flags);
317```
318*/
319export default function meow<Flags extends AnyFlags>(helpMessage: string, options?: Options<Flags>): Result<Flags>;
320export default function meow<Flags extends AnyFlags>(options?: Options<Flags>): Result<Flags>;