UNPKG

14.2 kBMarkdownView Raw
1<img width="945" alt="2017-07-26 9 27 05" src="https://user-images.githubusercontent.com/8784712/28623641-373450f4-7249-11e7-854d-1b076dab274d.png">
2
3[![NPM version](https://img.shields.io/npm/v/cac.svg?style=flat)](https://npmjs.com/package/cac) [![NPM downloads](https://img.shields.io/npm/dm/cac.svg?style=flat)](https://npmjs.com/package/cac) [![CircleCI](https://circleci.com/gh/cacjs/cac/tree/master.svg?style=shield)](https://circleci.com/gh/cacjs/cac/tree/master) [![Codecov](https://badgen.net/codecov/c/github/cacjs/cac/master)](https://codecov.io/gh/cacjs/cac) [![donate](https://img.shields.io/badge/$-donate-ff69b4.svg?maxAge=2592000&style=flat)](https://github.com/egoist/donate) [![chat](https://img.shields.io/badge/chat-on%20discord-7289DA.svg?style=flat)](https://chat.egoist.moe) [![install size](https://badgen.net/packagephobia/install/cac)](https://packagephobia.now.sh/result?p=cac)
4
5## Introduction
6
7**C**ommand **A**nd **C**onquer is a JavaScript library for building CLI apps.
8
9## Features
10
11- **Super light-weight**: No dependency, just a single file.
12- **Easy to learn**. There're only 4 APIs you need to learn for building simple CLIs: `cli.option` `cli.version` `cli.help` `cli.parse`.
13- **Yet so powerful**. Enable features like default command, git-like subcommands, validation for required arguments and options, variadic arguments, dot-nested options, automated help message generation and so on.
14- **Developer friendly**. Written in TypeScript.
15
16## Table of Contents
17
18<!-- toc -->
19
20- [Install](#install)
21- [Usage](#usage)
22 - [Simple Parsing](#simple-parsing)
23 - [Display Help Message and Version](#display-help-message-and-version)
24 - [Command-specific Options](#command-specific-options)
25 - [Brackets](#brackets)
26 - [Variadic Arguments](#variadic-arguments)
27 - [Dot-nested Options](#dot-nested-options)
28 - [Default Command](#default-command)
29 - [Supply an array as option value](#supply-an-array-as-option-value)
30 - [With TypeScript](#with-typescript)
31- [Projects Using CAC](#projects-using-cac)
32- [References](#references)
33 - [CLI Instance](#cli-instance)
34 - [cac(name?)](#cacname)
35 - [cli.command(name, description, config?)](#clicommandname-description-config)
36 - [cli.option(name, description, config?)](#clioptionname-description-config)
37 - [cli.parse(argv?)](#cliparseargv)
38 - [cli.version(version, customFlags?)](#cliversionversion-customflags)
39 - [cli.help(callback?)](#clihelpcallback)
40 - [cli.outputHelp(subCommand?)](#clioutputhelpsubcommand)
41 - [Command Instance](#command-instance)
42 - [command.option()](#commandoption)
43 - [command.action(callback)](#commandactioncallback)
44 - [command.alias(name)](#commandaliasname)
45 - [command.allowUnknownOptions()](#commandallowunknownoptions)
46 - [command.example(example)](#commandexampleexample)
47 - [Events](#events)
48- [FAQ](#faq)
49 - [How is the name written and pronounced?](#how-is-the-name-written-and-pronounced)
50 - [Why not use Commander.js?](#why-not-use-commanderjs)
51- [Contributing](#contributing)
52- [Author](#author)
53
54<!-- tocstop -->
55
56## Install
57
58```bash
59yarn add cac
60```
61
62## Usage
63
64### Simple Parsing
65
66Use CAC as simple argument parser:
67
68```js
69// examples/basic-usage.js
70const cli = require('cac')()
71
72cli.option('--type <type>', 'Choose a project type', {
73 default: 'node'
74})
75
76const parsed = cli.parse()
77
78console.log(JSON.stringify(parsed, null, 2))
79```
80
81<img width="500" alt="2018-11-26 12 28 03" src="https://user-images.githubusercontent.com/8784712/48981576-2a871000-f112-11e8-8151-80f61e9b9908.png">
82
83### Display Help Message and Version
84
85```js
86// examples/help.js
87const cli = require('cac')()
88
89cli.option('--eslint [config]', 'Choose an ESLint config', {
90 default: 'standard'
91})
92cli.option('--name <name>', 'Provide your name')
93
94cli.command('lint [...files]', 'Lint files').action((files, options) => {
95 console.log(files, options)
96})
97
98// Display help message when `-h` or `--help` appears
99cli.help()
100// Display version number when `-v` or `--version` appears
101// It's also used in help message
102cli.version('0.0.0')
103
104cli.parse()
105```
106
107<img width="500" alt="2018-11-25 8 21 14" src="https://user-images.githubusercontent.com/8784712/48979012-acb20d00-f0ef-11e8-9cc6-8ffca00ab78a.png">
108
109### Command-specific Options
110
111You can attach options to a command.
112
113```js
114const cli = require('cac')()
115
116cli
117 .command('rm <dir>', 'Remove a dir')
118 .option('-r, --recursive', 'Remove recursively')
119 .action((dir, options) => {
120 console.log('remove ' + dir + (options.recursive ? ' recursively' : ''))
121 })
122
123cli.help()
124
125cli.parse()
126```
127
128A command's options are validated when the command is used. Any unknown options will be reported as an error. However, if an action-based command does not define an action, then the options are not validated. If you really want to use unknown options, use [`command.allowUnknownOptions`](#commandallowunknownoptions).
129
130<img alt="command options" width="500" src="https://user-images.githubusercontent.com/8784712/49065552-49dc8500-f259-11e8-9c7b-a7c32d70920e.png">
131
132### Brackets
133
134When using brackets in command name, angled brackets indicate required command arguments, while square bracket indicate optional arguments.
135
136When using brackets in option name, angled brackets indicate that a string / number value is required, while square bracket indicate that the value can also be `true`.
137
138```js
139const cli = require('cac')()
140
141cli
142 .command('deploy <folder>', 'Deploy a folder to AWS')
143 .option('--scale [level]', 'Scaling level')
144 .action((folder, options) => {
145 // ...
146 })
147
148cli
149 .command('build [project]', 'Build a project')
150 .option('--out <dir>', 'Output directory')
151 .action((folder, options) => {
152 // ...
153 })
154
155cli.parse()
156```
157
158To allow an option whose value is `false`, you need to manually speicfy a negated option:
159
160```js
161cli
162 .command('build [project]', 'Build a project')
163 .option('--no-config', 'Disable config file')
164 .option('--config <path>', 'Use a custom config file')
165```
166
167This will let CAC set the default value of `config` to true, and you can use `--no-config` flag to set it to `false`.
168
169### Variadic Arguments
170
171The last argument of a command can be variadic, and only the last argument. To make an argument variadic you have to add `...` to the start of argument name, just like the rest operator in JavaScript. Here is an example:
172
173```js
174const cli = require('cac')()
175
176cli
177 .command('build <entry> [...otherFiles]', 'Build your app')
178 .option('--foo', 'Foo option')
179 .action((entry, otherFiles, options) => {
180 console.log(entry)
181 console.log(otherFiles)
182 console.log(options)
183 })
184
185cli.help()
186
187cli.parse()
188```
189
190<img width="500" alt="2018-11-25 8 25 30" src="https://user-images.githubusercontent.com/8784712/48979056-47125080-f0f0-11e8-9d8f-3219e0beb0ed.png">
191
192### Dot-nested Options
193
194Dot-nested options will be merged into a single option.
195
196```js
197const cli = require('cac')()
198
199cli
200 .command('build', 'desc')
201 .option('--env <env>', 'Set envs')
202 .example('--env.API_SECRET xxx')
203 .action(options => {
204 console.log(options)
205 })
206
207cli.help()
208
209cli.parse()
210```
211
212<img width="500" alt="2018-11-25 9 37 53" src="https://user-images.githubusercontent.com/8784712/48979771-6ada9400-f0fa-11e8-8192-e541b2cfd9da.png">
213
214### Default Command
215
216Register a command that will be used when no other command is matched.
217
218```js
219const cli = require('cac')()
220
221cli
222 // Simply omit the command name, just brackets
223 .command('[...files]', 'Build files')
224 .option('--minimize', 'Minimize output')
225 .action((files, options) => {
226 console.log(files)
227 console.log(options.minimize)
228 })
229
230cli.parse()
231```
232
233### Supply an array as option value
234
235```bash
236node cli.js --include project-a
237# The parsed options will be:
238# { include: 'project-a' }
239
240node cli.js --include project-a --include project-b
241# The parsed options will be:
242# { include: ['project-a', 'project-b'] }
243```
244
245### With TypeScript
246
247First you need `@types/node` to be installed as a dev dependency in your project:
248
249```bash
250yarn add @types/node --dev
251```
252
253Then everything just works out of the box:
254
255```js
256const cac = require('cac')
257// OR ES modules
258import * as cac from 'cac'
259```
260
261## Projects Using CAC
262
263Projects that use **CAC**:
264
265- [VuePress](https://github.com/vuejs/vuepress): :memo: Minimalistic Vue-powered static site generator.
266- [SAO](https://github.com/egoist/sao): ⚔️ Futuristic scaffolding tool.
267- [DocPad](https://github.com/docpad/docpad): 🏹 Powerful Static Site Generator.
268- [Poi](https://github.com/egoist/poi): ⚡️ Delightful web development.
269- [bili](https://github.com/egoist/bili): 🥂 Schweizer Armeemesser for bundling JavaScript libraries.
270- [lass](https://github.com/lassjs/lass): 💁🏻 Scaffold a modern package boilerplate for Node.js.
271- [Foy](https://github.com/zaaack/foy): 🏗 A lightweight and modern task runner and build tool for general purpose.
272- Feel free to add yours here...
273
274## References
275
276**💁 Check out [the generated docs](https://cac-api-doc.egoist.sh/classes/_cac_.cac.html) from source code if you want a more in-depth API references.**
277
278Below is a brief overview.
279
280### CLI Instance
281
282CLI instance is created by invoking the `cac` function:
283
284```js
285const cac = require('cac')
286const cli = cac()
287```
288
289#### cac(name?)
290
291Create a CLI instance, optionally specify the program name which will be used to display in help and version message. When not set we use the basename of `argv[1]`.
292
293#### cli.command(name, description, config?)
294
295- Type: `(name: string, description: string) => Command`
296
297Create a command instance.
298
299The option also accepts a third argument `config` for addtional command config:
300
301- `config.allowUnknownOptions`: `boolean` Allow unknown options in this command.
302- `config.ignoreOptionDefaultValue`: `boolean` Don't use the options's default value in parsed options, only display them in help message.
303
304#### cli.option(name, description, config?)
305
306- Type: `(name: string, description: string, config?: OptionConfig) => CLI`
307
308Add a global option.
309
310The option also accepts a third argument `config` for addtional option config:
311
312- `config.default`: Default value for the option.
313- `config.type`: `any[]` When set to `[]`, the option value returns an array type. You can also use a conversion function such as `[String]`, which will invoke the option value with `String`.
314
315#### cli.parse(argv?)
316
317- Type: `(argv = process.argv) => ParsedArgv`
318
319```ts
320interface ParsedArgv {
321 args: string[]
322 options: {
323 [k: string]: any
324 }
325}
326```
327
328When this method is called, `cli.rawArgs` `cli.args` `cli.options` `cli.matchedCommand` will also be available.
329
330#### cli.version(version, customFlags?)
331
332- Type: `(version: string, customFlags = '-v, --version') => CLI`
333
334Output version number when `-v, --version` flag appears.
335
336#### cli.help(callback?)
337
338- Type: `(callback?: HelpCallback) => CLI`
339
340Output help message when `-h, --help` flag appears.
341
342Optional `callback` allows post-processing of help text before it is displayed:
343
344```ts
345type HelpCallback = (sections: HelpSection[]) => void
346
347interface HelpSection {
348 title?: string
349 body: string
350}
351```
352
353#### cli.outputHelp(subCommand?)
354
355- Type: `(subCommand?: boolean) => CLI`
356
357Output help message. Optional `subCommand` argument if you want to output the help message for the matched sub-command instead of the global help message.
358
359### Command Instance
360
361Command instance is created by invoking the `cli.command` method:
362
363```js
364const command = cli.command('build [...files]', 'Build given files')
365```
366
367#### command.option()
368
369Basically the same as `cli.option` but this adds the option to specific command.
370
371#### command.action(callback)
372
373- Type: `(callback: ActionCallback) => Command`
374
375Use a callback function as the command action when the command matches user inputs.
376
377```ts
378type ActionCallback = (
379 // Parsed CLI args
380 // The last arg will be an array if it's an varadic argument
381 ...args: string | string[] | number | number[]
382 // Parsed CLI options
383 options: Options
384) => any
385
386interface Options {
387 [k: string]: any
388}
389```
390
391#### command.alias(name)
392
393- Type: `(name: string) => Command`
394
395Add an alias name to this command, the `name` here can't contain brackets.
396
397#### command.allowUnknownOptions()
398
399- Type: `() => Command`
400
401Allow unknown options in this command, by default CAC will log an error when unknown options are used.
402
403#### command.example(example)
404
405- Type: `(example: CommandExample) => Command`
406
407Add an example which will be displayed at the end of help message.
408
409```ts
410type CommandExample = ((name: string) => string) | string
411```
412
413### Events
414
415Listen to commands:
416
417```js
418// Listen to the `foo` command
419cli.on('command:foo', () => {
420 // Do something
421})
422
423// Listen to the default command
424cli.on('command:!', () => {
425 // Do something
426})
427
428// Listen to unknown commands
429cli.on('command:*', () => {
430 console.error('Invalid command: %', cli.args.join(' '))
431 process.exit(1)
432})
433```
434
435## FAQ
436
437### How is the name written and pronounced?
438
439CAC, or cac, pronounced `C-A-C`.
440
441This project is dedicated to our lovely C.C. sama. Maybe CAC stands for C&C as well :P
442
443<img src="http://i.giphy.com/v3FeH4swox9mg.gif" width="400"/>
444
445### Why not use Commander.js?
446
447CAC is very similar to Commander.js, while the latter does not support dot nested options, i.e. something like `--env.API_SECRET foo`. Besides, you can't use unknown options in Commander.js either.
448
449_And maybe more..._
450
451Basically I made CAC to fulfill my own needs for building CLI apps like [Poi](https://poi.js.org), [SAO](https://saojs.org) and all my CLI apps. It's small, simple but powerful :P
452
453## Contributing
454
4551. Fork it!
4562. Create your feature branch: `git checkout -b my-new-feature`
4573. Commit your changes: `git commit -am 'Add some feature'`
4584. Push to the branch: `git push origin my-new-feature`
4595. Submit a pull request :D
460
461## Author
462
463**CAC** © [EGOIST](https://github.com/egoist), Released under the [MIT](./LICENSE) License.<br>
464Authored and maintained by egoist with help from contributors ([list](https://github.com/cacjs/cac/contributors)).
465
466> [Website](https://egoist.sh) · GitHub [@egoist](https://github.com/egoist) · Twitter [@\_egoistlily](https://twitter.com/_egoistlily)