UNPKG

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