UNPKG

12.7 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- [VuePress](https://github.com/vuejs/vuepress): :memo: Minimalistic Vue-powered static site generator.
234- [SAO](https://github.com/egoist/sao): ⚔️ Futuristic scaffolding tool.
235- [DocPad](https://github.com/docpad/docpad): 🏹 Powerful Static Site Generator.
236- [Poi](https://github.com/egoist/poi): ⚡️ Delightful web development.
237- [bili](https://github.com/egoist/bili): 🥂 Schweizer Armeemesser for bundling JavaScript libraries.
238- [lass](https://github.com/lassjs/lass): 💁🏻 Scaffold a modern package boilerplate for Node.js.
239- Feel free to add yours here...
240
241## References
242
243**💁 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.**
244
245Below is a brief overview.
246
247### CLI Instance
248
249CLI instance is created by invoking the `cac` function:
250
251```js
252const cac = require('cac')
253const cli = cac()
254```
255
256#### cli.command(name, description, config?)
257
258- Type: `(name: string, description: string) => Command`
259
260Create a command instance.
261
262The option also accepts a third argument `config` for addtional command config:
263
264- `config.allowUnknownOptions`: `boolean` Allow unknown options in this command.
265- `config.ignoreOptionDefaultValue`: `boolean` Don't use the options's default value in parsed options, only display them in help message.
266
267#### cli.option(name, description, config?)
268
269- Type: `(name: string, description: string, config?: OptionConfig) => CLI`
270
271Add a global option.
272
273The option also accepts a third argument `config` for addtional option config:
274
275- `config.default`: Default value for the option.
276- `config.coerce`: `(value: any) => newValue` A function to process the option value.
277
278#### cli.parse(argv?)
279
280- Type: `(argv = process.argv) => ParsedArgv`
281
282```ts
283interface ParsedArgv {
284 args: string[]
285 options: {
286 [k: string]: any
287 }
288}
289```
290
291When this method is called, `cli.rawArgs` `cli.args` `cli.options` `cli.matchedCommand` will also be available.
292
293#### cli.version(version, customFlags?)
294
295- Type: `(version: string, customFlags = '-v, --version') => CLI`
296
297Output version number when `-v, --version` flag appears.
298
299#### cli.help(callback?)
300
301- Type: `(callback?: HelpCallback) => CLI`
302
303Output help message when `-h, --help` flag appears.
304
305Optional `callback` allows post-processing of help text before it is displayed:
306
307```ts
308type HelpCallback = (sections: HelpSection[]) => void
309
310interface HelpSection {
311 title?: string
312 body: string
313}
314```
315
316#### cli.outputHelp(subCommand?)
317
318- Type: `(subCommand?: boolean) => CLI`
319
320Output help message. Optional `subCommand` argument if you want to output the help message for the matched sub-command instead of the global help message.
321
322### Command Instance
323
324Command instance is created by invoking the `cli.command` method:
325
326```js
327const command = cli.command('build [...files]', 'Build given files')
328```
329
330#### command.option()
331
332Basically the same as `cli.option` but this adds the option to specific command.
333
334#### command.action(callback)
335
336- Type: `(callback: ActionCallback) => Command`
337
338Use a callback function as the command action when the command matches user inputs.
339
340```ts
341type ActionCallback = (
342 // Parsed CLI args
343 // The last arg will be an array if it's an varadic argument
344 ...args: string | string[] | number | number[]
345 // Parsed CLI options
346 options: Options
347) => any
348
349interface Options {
350 [k: string]: any
351}
352```
353
354#### command.alias(name)
355
356- Type: `(name: string) => Command`
357
358Add an alias name to this command, the `name` here can't contain brackets.
359
360#### command.allowUnknownOptions()
361
362- Type: `() => Command`
363
364Allow unknown options in this command, by default CAC will log an error when unknown options are used.
365
366#### command.example(example)
367
368- Type: `(example: CommandExample) => Command`
369
370Add an example which will be displayed at the end of help message.
371
372```ts
373type CommandExample = ((bin: string) => string) | string
374```
375
376### Events
377
378Listen to commands:
379
380```js
381// Listen to the `foo` command
382cli.on('command:foo', () => {
383 // Do something
384})
385
386// Listen to the default command
387cli.on('command:!', () => {
388 // Do something
389})
390
391// Listen to unknown commands
392cli.on('command:*', () => {
393 console.error('Invalid command: %', cli.args.join(' '))
394 process.exit(1)
395})
396```
397
398## FAQ
399
400### How is the name written and pronounced?
401
402CAC, or cac, pronounced `C-A-C`.
403
404This project is dedicated to our lovely C.C. sama. Maybe CAC stands for C&C as well :P
405
406<img src="http://i.giphy.com/v3FeH4swox9mg.gif" width="400"/>
407
408### Why not use Commander.js?
409
410CAC 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.
411
412_And maybe more..._
413
414Basically 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
415
416## Contributing
417
4181. Fork it!
4192. Create your feature branch: `git checkout -b my-new-feature`
4203. Commit your changes: `git commit -am 'Add some feature'`
4214. Push to the branch: `git push origin my-new-feature`
4225. Submit a pull request :D
423
424## Author
425
426**CAC** © [EGOIST](https://github.com/egoist), Released under the [MIT](./LICENSE) License.<br>
427Authored and maintained by egoist with help from contributors ([list](https://github.com/cacjs/cac/contributors)).
428
429> [Website](https://egoist.sh) · GitHub [@egoist](https://github.com/egoist) · Twitter [@\_egoistlily](https://twitter.com/_egoistlily)