UNPKG

8.07 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 // eslint-disable-next-line @typescript-eslint/ban-types
201 readonly booleanDefault?: boolean | null | undefined;
202
203 /**
204 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.
205
206 @default true
207 */
208 readonly hardRejection?: boolean;
209
210 /**
211 Whether to allow unknown flags or not.
212
213 @default true
214 */
215 readonly allowUnknownFlags?: boolean;
216}
217
218type TypedFlag<Flag extends AnyFlag> =
219 Flag extends {type: 'number'}
220 ? number
221 : Flag extends {type: 'string'}
222 ? string
223 : Flag extends {type: 'boolean'}
224 ? boolean
225 : unknown;
226
227type PossiblyOptionalFlag<Flag extends AnyFlag, FlagType> =
228 Flag extends {isRequired: true}
229 ? FlagType
230 : Flag extends {default: any}
231 ? FlagType
232 : FlagType | undefined;
233
234export type TypedFlags<Flags extends AnyFlags> = {
235 [F in keyof Flags]: Flags[F] extends {isMultiple: true}
236 ? PossiblyOptionalFlag<Flags[F], Array<TypedFlag<Flags[F]>>>
237 : PossiblyOptionalFlag<Flags[F], TypedFlag<Flags[F]>>
238};
239
240export interface Result<Flags extends AnyFlags> {
241 /**
242 Non-flag arguments.
243 */
244 input: string[];
245
246 /**
247 Flags converted to camelCase excluding aliases.
248 */
249 flags: TypedFlags<Flags> & Record<string, unknown>;
250
251 /**
252 Flags converted camelCase including aliases.
253 */
254 unnormalizedFlags: TypedFlags<Flags> & Record<string, unknown>;
255
256 /**
257 The `package.json` object.
258 */
259 pkg: PackageJson;
260
261 /**
262 The help text used with `--help`.
263 */
264 help: string;
265
266 /**
267 Show the help text and exit with code.
268
269 @param exitCode - The exit code to use. Default: `2`.
270 */
271 showHelp: (exitCode?: number) => never;
272
273 /**
274 Show the version text and exit.
275 */
276 showVersion: () => void;
277}
278/**
279@param helpMessage - Shortcut for the `help` option.
280
281@example
282```
283#!/usr/bin/env node
284import meow from 'meow';
285import foo from './index.js';
286
287const cli = meow(`
288 Usage
289 $ foo <input>
290
291 Options
292 --rainbow, -r Include a rainbow
293
294 Examples
295 $ foo unicorns --rainbow
296 🌈 unicorns 🌈
297`, {
298 importMeta: import.meta,
299 flags: {
300 rainbow: {
301 type: 'boolean',
302 alias: 'r'
303 }
304 }
305});
306
307//{
308// input: ['unicorns'],
309// flags: {rainbow: true},
310// ...
311//}
312
313foo(cli.input[0], cli.flags);
314```
315*/
316export default function meow<Flags extends AnyFlags>(helpMessage: string, options?: Options<Flags>): Result<Flags>;
317export default function meow<Flags extends AnyFlags>(options?: Options<Flags>): Result<Flags>;