UNPKG

12.6 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) [![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 - [With TypeScript](#with-typescript)
30- [Projects Using CAC](#projects-using-cac)
31- [References](#references)
32 - [CLI Instance](#cli-instance)
33 - [cli.command(name, description, config?)](#clicommandname-description-config)
34 - [cli.option(name, description, config?)](#clioptionname-description-config)
35 - [cli.parse(argv?)](#cliparseargv)
36 - [cli.version(version, customFlags?)](#cliversionversion-customflags)
37 - [cli.help(callback?)](#clihelpcallback)
38 - [cli.outputHelp(subCommand?)](#clioutputhelpsubcommand)
39 - [Command Instance](#command-instance)
40 - [command.option()](#commandoption)
41 - [command.action(callback)](#commandactioncallback)
42 - [command.alias(name)](#commandaliasname)
43 - [command.allowUnknownOptions()](#commandallowunknownoptions)
44 - [command.example(example)](#commandexampleexample)
45 - [Events](#events)
46- [FAQ](#faq)
47 - [How is the name written and pronounced?](#how-is-the-name-written-and-pronounced)
48 - [Why not use Commander.js?](#why-not-use-commanderjs)
49- [Contributing](#contributing)
50- [Author](#author)
51
52<!-- tocstop -->
53
54## Install
55
56```bash
57yarn add cac
58```
59
60## Usage
61
62### Simple Parsing
63
64Use CAC as simple argument parser:
65
66```js
67// examples/basic-usage.js
68const cli = require('cac')()
69
70cli.option('--type [type]', 'Choose a project type', {
71 default: 'node'
72})
73
74const parsed = cli.parse()
75
76console.log(JSON.stringify(parsed, null, 2))
77```
78
79<img width="500" alt="2018-11-26 12 28 03" src="https://user-images.githubusercontent.com/8784712/48981576-2a871000-f112-11e8-8151-80f61e9b9908.png">
80
81### Display Help Message and Version
82
83```js
84// examples/help.js
85const cli = require('cac')()
86
87cli.option('--type [type]', 'Choose a project type', {
88 default: 'node'
89})
90cli.option('--name <name>', 'Provide your name')
91
92cli.command('lint [...files]', 'Lint files').action((files, options) => {
93 console.log(files, options)
94})
95
96// Display help message when `-h` or `--help` appears
97cli.help()
98// Display version number when `-h` or `--help` appears
99cli.version('0.0.0')
100
101cli.parse()
102```
103
104<img width="500" alt="2018-11-25 8 21 14" src="https://user-images.githubusercontent.com/8784712/48979012-acb20d00-f0ef-11e8-9cc6-8ffca00ab78a.png">
105
106### Command-specific Options
107
108You can attach options to a command.
109
110```js
111const cli = require('cac')()
112
113cli
114 .command('rm <dir>', 'Remove a dir')
115 .option('-r, --recursive', 'Remove recursively')
116 .action((dir, options) => {
117 console.log('remove ' + dir + (options.recursive ? ' recursively' : ''))
118 })
119
120cli.help()
121
122cli.parse()
123```
124
125A 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).
126
127<img alt="command options" width="500" src="https://user-images.githubusercontent.com/8784712/49065552-49dc8500-f259-11e8-9c7b-a7c32d70920e.png">
128
129### Brackets
130
131When using brackets in command name, angled brackets indicate required command arguments, while sqaure bracket indicate optional arguments.
132
133When using brackets in option name, angled brackets indicate that the option value is required, while sqaure bracket indicate that the value is optional.
134
135```js
136const cli = require('cac')()
137
138cli
139 .command('deploy <folder>', 'Deploy a folder to AWS')
140 .option('--scale [level]', 'Scaling level')
141 .action((folder, options) => {
142 console.log(folder)
143 console.log(options)
144 })
145
146cli.parse()
147```
148
149### Variadic Arguments
150
151The 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:
152
153```js
154const cli = require('cac')()
155
156cli
157 .command('build <entry> [...otherFiles]', 'Build your app')
158 .option('--foo', 'Foo option')
159 .action((entry, otherFiles, options) => {
160 console.log(entry)
161 console.log(otherFiles)
162 console.log(options)
163 })
164
165cli.help()
166
167cli.parse()
168```
169
170<img width="500" alt="2018-11-25 8 25 30" src="https://user-images.githubusercontent.com/8784712/48979056-47125080-f0f0-11e8-9d8f-3219e0beb0ed.png">
171
172### Dot-nested Options
173
174Dot-nested options will be merged into a single option.
175
176```js
177const cli = require('cac')()
178
179cli
180 .command('build', 'desc')
181 .option('--env <env>', 'Set envs')
182 .example('--env.API_SECRET xxx')
183 .action(options => {
184 console.log(options)
185 })
186
187cli.help()
188
189cli.parse()
190```
191
192<img width="500" alt="2018-11-25 9 37 53" src="https://user-images.githubusercontent.com/8784712/48979771-6ada9400-f0fa-11e8-8192-e541b2cfd9da.png">
193
194### Default Command
195
196Register a command that will be used when no other command is matched.
197
198```js
199const cli = require('cac')()
200
201cli
202 // Simply omit the command name, just brackets
203 .command('[...files]', 'Build files')
204 .option('--minimize', 'Minimize output')
205 .action((files, options) => {
206 console.log(files)
207 console.log(options.minimize)
208 })
209
210cli.parse()
211```
212
213### With TypeScript
214
215First you need `@types/node` to be installed as a dev dependency in your project:
216
217```bash
218yarn add @types/node --dev
219```
220
221Then everything just works out of the box:
222
223```js
224const cac = require('cac')
225// OR ES modules
226import cac from 'cac'
227```
228
229## Projects Using CAC
230
231Projects that use **CAC**:
232
233- [SAO](https://github.com/egoist/sao): ⚔️ Futuristic scaffolding tool.
234- [DocPad](https://github.com/docpad/docpad): 🏹 Powerful Static Site Generator.
235- [Poi](https://github.com/egoist/poi): ⚡️ Delightful web development.
236- [bili](https://github.com/egoist/bili): 🥂 Schweizer Armeemesser for bundling JavaScript libraries.
237- [lass](https://github.com/lassjs/lass): 💁🏻 Scaffold a modern package boilerplate for Node.js.
238- Feel free to add yours here...
239
240## References
241
242**💁 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.**
243
244Below is a brief overview.
245
246### CLI Instance
247
248CLI instance is created by invoking the `cac` function:
249
250```js
251const cac = require('cac')
252const cli = cac()
253```
254
255#### cli.command(name, description, config?)
256
257- Type: `(name: string, description: string) => Command`
258
259Create a command instance.
260
261The option also accepts a third argument `config` for addtional command config:
262
263- `config.allowUnknownOptions`: `boolean` Allow unknown options in this command.
264- `config.ignoreOptionDefaultValue`: `boolean` Don't use the options's default value in parsed options, only display them in help message.
265
266#### cli.option(name, description, config?)
267
268- Type: `(name: string, description: string, config?: OptionConfig) => CLI`
269
270Add a global option.
271
272The option also accepts a third argument `config` for addtional option config:
273
274- `config.default`: Default value for the option.
275- `config.coerce`: `(value: any) => newValue` A function to process the option value.
276
277#### cli.parse(argv?)
278
279- Type: `(argv = process.argv) => ParsedArgv`
280
281```ts
282interface ParsedArgv {
283 args: string[]
284 options: {
285 [k: string]: any
286 }
287}
288```
289
290When this method is called, `cli.rawArgs` `cli.args` `cli.options` `cli.matchedCommand` will also be available.
291
292#### cli.version(version, customFlags?)
293
294- Type: `(version: string, customFlags = '-v, --version') => CLI`
295
296Output version number when `-v, --version` flag appears.
297
298#### cli.help(callback?)
299
300- Type: `(callback?: HelpCallback) => CLI`
301
302Output help message when `-h, --help` flag appears.
303
304Optional `callback` allows post-processing of help text before it is displayed:
305
306```ts
307type HelpCallback = (sections: HelpSection[]) => void
308
309interface HelpSection {
310 title?: string
311 body: string
312}
313```
314
315#### cli.outputHelp(subCommand?)
316
317- Type: `(subCommand?: boolean) => CLI`
318
319Output help message. Optional `subCommand` argument if you want to output the help message for the matched sub-command instead of the global help message.
320
321### Command Instance
322
323Command instance is created by invoking the `cli.command` method:
324
325```js
326const command = cli.command('build [...files]', 'Build given files')
327```
328
329#### command.option()
330
331Basically the same as `cli.option` but this adds the option to specific command.
332
333#### command.action(callback)
334
335- Type: `(callback: ActionCallback) => Command`
336
337Use a callback function as the command action when the command matches user inputs.
338
339```ts
340type ActionCallback = (
341 // Parsed CLI args
342 // The last arg will be an array if it's an varadic argument
343 ...args: string | string[] | number | number[]
344 // Parsed CLI options
345 options: Options
346) => any
347
348interface Options {
349 [k: string]: any
350}
351```
352
353#### command.alias(name)
354
355- Type: `(name: string) => Command`
356
357Add an alias name to this command, the `name` here can't contain brackets.
358
359#### command.allowUnknownOptions()
360
361- Type: `() => Command`
362
363Allow unknown options in this command, by default CAC will log an error when unknown options are used.
364
365#### command.example(example)
366
367- Type: `(example: CommandExample) => Command`
368
369Add an example which will be displayed at the end of help message.
370
371```ts
372type CommandExample = ((bin: string) => string) | string
373```
374
375### Events
376
377Listen to commands:
378
379```js
380// Listen to the `foo` command
381cli.on('command:foo', () => {
382 // Do something
383})
384
385// Listen to the default command
386cli.on('command:!', () => {
387 // Do something
388})
389
390// Listen to unknown commands
391cli.on('command:*', () => {
392 console.error('Invalid command: %', cli.args.join(' '))
393 process.exit(1)
394})
395```
396
397## FAQ
398
399### How is the name written and pronounced?
400
401CAC, or cac, pronounced `C-A-C`.
402
403This project is dedicated to our lovely C.C. sama. Maybe CAC stands for C&C as well :P
404
405<img src="http://i.giphy.com/v3FeH4swox9mg.gif" width="400"/>
406
407### Why not use Commander.js?
408
409CAC 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.
410
411_And maybe more..._
412
413Basically 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
414
415## Contributing
416
4171. Fork it!
4182. Create your feature branch: `git checkout -b my-new-feature`
4193. Commit your changes: `git commit -am 'Add some feature'`
4204. Push to the branch: `git push origin my-new-feature`
4215. Submit a pull request :D
422
423## Author
424
425**CAC** © [EGOIST](https://github.com/egoist), Released under the [MIT](./LICENSE) License.<br>
426Authored and maintained by egoist with help from contributors ([list](https://github.com/cacjs/cac/contributors)).
427
428> [Website](https://egoist.sh) · GitHub [@egoist](https://github.com/egoist) · Twitter [@\_egoistlily](https://twitter.com/_egoistlily)