UNPKG

12.5 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.parse()
121```
122
123A 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).
124
125### Brackets
126
127When using brackets in command name, angled brackets indicate required command arguments, while sqaure bracket indicate optional arguments.
128
129When using brackets in option name, angled brackets indicate that the option value is required, while sqaure bracket indicate that the value is optional.
130
131```js
132const cli = require('cac')()
133
134cli
135 .command('deploy <folder>', 'Deploy a folder to AWS')
136 .option('--scale [level]', 'Scaling level')
137 .action((folder, options) => {
138 console.log(folder)
139 console.log(options)
140 })
141
142cli.parse()
143```
144
145### Variadic Arguments
146
147The 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:
148
149```js
150const cli = require('cac')()
151
152cli
153 .command('build <entry> [...otherFiles]', 'Build your app')
154 .option('--foo', 'Foo option')
155 .action((entry, otherFiles, options) => {
156 console.log(entry)
157 console.log(otherFiles)
158 console.log(options)
159 })
160
161cli.help()
162
163cli.parse()
164```
165
166<img width="500" alt="2018-11-25 8 25 30" src="https://user-images.githubusercontent.com/8784712/48979056-47125080-f0f0-11e8-9d8f-3219e0beb0ed.png">
167
168### Dot-nested Options
169
170Dot-nested options will be merged into a single option.
171
172```js
173const cli = require('cac')()
174
175cli
176 .command('build', 'desc')
177 .option('--env <env>', 'Set envs')
178 .example('--env.API_SECRET xxx')
179 .action(options => {
180 console.log(options)
181 })
182
183cli.help()
184
185cli.parse()
186```
187
188<img width="500" alt="2018-11-25 9 37 53" src="https://user-images.githubusercontent.com/8784712/48979771-6ada9400-f0fa-11e8-8192-e541b2cfd9da.png">
189
190### Default Command
191
192Register a command that will be used when no other command is matched.
193
194```js
195const cli = require('cac')()
196
197cli
198 // Simply omit the command name, just brackets
199 .command('[...files]', 'Build files')
200 .option('--minimize', 'Minimize output')
201 .action((files, options) => {
202 console.log(files)
203 console.log(options.minimize)
204 })
205
206cli.parse()
207```
208
209### With TypeScript
210
211First you need `@types/node` to be installed as a dev dependency in your project:
212
213```bash
214yarn add @types/node --dev
215```
216
217Then everything just works out of the box:
218
219```js
220const cac = require('cac')
221// OR ES modules
222import cac from 'cac'
223```
224
225## Projects Using CAC
226
227Projects that use **CAC**:
228
229- [SAO](https://github.com/egoist/sao): ⚔️ Futuristic scaffolding tool.
230- [DocPad](https://github.com/docpad/docpad): 🏹 Powerful Static Site Generator.
231- [Poi](https://github.com/egoist/poi): ⚡️ Delightful web development.
232- [bili](https://github.com/egoist/bili): 🥂 Schweizer Armeemesser for bundling JavaScript libraries.
233- [lass](https://github.com/lassjs/lass): 💁🏻 Scaffold a modern package boilerplate for Node.js.
234- Feel free to add yours here...
235
236## References
237
238**💁 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.**
239
240Below is a brief overview.
241
242### CLI Instance
243
244CLI instance is created by invoking the `cac` function:
245
246```js
247const cac = require('cac')
248const cli = cac()
249```
250
251#### cli.command(name, description, config?)
252
253- Type: `(name: string, description: string) => Command`
254
255Create a command instance.
256
257The option also accepts a third argument `config` for addtional command config:
258
259- `config.allowUnknownOptions`: `boolean` Allow unknown options in this command.
260- `config.ignoreOptionDefaultValue`: `boolean` Don't use the options's default value in parsed options, only display them in help message.
261
262#### cli.option(name, description, config?)
263
264- Type: `(name: string, description: string, config?: OptionConfig) => CLI`
265
266Add a global option.
267
268The option also accepts a third argument `config` for addtional option config:
269
270- `config.default`: Default value for the option.
271- `config.coerce`: `(value: any) => newValue` A function to process the option value.
272
273#### cli.parse(argv?)
274
275- Type: `(argv = process.argv) => ParsedArgv`
276
277```ts
278interface ParsedArgv {
279 args: string[]
280 options: {
281 [k: string]: any
282 }
283}
284```
285
286When this method is called, `cli.rawArgs` `cli.args` `cli.options` `cli.matchedCommand` will also be available.
287
288#### cli.version(version, customFlags?)
289
290- Type: `(version: string, customFlags = '-v, --version') => CLI`
291
292Output version number when `-v, --version` flag appears.
293
294#### cli.help(callback?)
295
296- Type: `(callback?: HelpCallback) => CLI`
297
298Output help message when `-h, --help` flag appears.
299
300Optional `callback` allows post-processing of help text before it is displayed:
301
302```ts
303type HelpCallback = (sections: HelpSection[]) => void
304
305interface HelpSection {
306 title?: string
307 body: string
308}
309```
310
311#### cli.outputHelp(subCommand?)
312
313- Type: `(subCommand?: boolean) => CLI`
314
315Output help message. Optional `subCommand` argument if you want to output the help message for the matched sub-command instead of the global help message.
316
317### Command Instance
318
319Command instance is created by invoking the `cli.command` method:
320
321```js
322const command = cli.command('build [...files]', 'Build given files')
323```
324
325#### command.option()
326
327Basically the same as `cli.option` but this adds the option to specific command.
328
329#### command.action(callback)
330
331- Type: `(callback: ActionCallback) => Command`
332
333Use a callback function as the command action when the command matches user inputs.
334
335```ts
336type ActionCallback = (
337 // Parsed CLI args
338 // The last arg will be an array if it's an varadic argument
339 ...args: string | string[] | number | number[]
340 // Parsed CLI options
341 options: Options
342) => any
343
344interface Options {
345 [k: string]: any
346}
347```
348
349#### command.alias(name)
350
351- Type: `(name: string) => Command`
352
353Add an alias name to this command, the `name` here can't contain brackets.
354
355#### command.allowUnknownOptions()
356
357- Type: `() => Command`
358
359Allow unknown options in this command, by default CAC will log an error when unknown options are used.
360
361#### command.example(example)
362
363- Type: `(example: CommandExample) => Command`
364
365Add an example which will be displayed at the end of help message.
366
367```ts
368type CommandExample = ((bin: string) => string) | string
369```
370
371### Events
372
373Listen to commands:
374
375```js
376// Listen to the `foo` command
377cli.on('command:foo', () => {
378 // Do something
379})
380
381// Listen to the default command
382cli.on('command:!', () => {
383 // Do something
384})
385
386// Listen to unknown commands
387cli.on('command:*', () => {
388 console.error('Invalid command: %', cli.args.join(' '))
389 process.exit(1)
390})
391```
392
393## FAQ
394
395### How is the name written and pronounced?
396
397CAC, or cac, pronounced `C-A-C`.
398
399This project is dedicated to our lovely C.C. sama. Maybe CAC stands for C&C as well :P
400
401<img src="http://i.giphy.com/v3FeH4swox9mg.gif" width="400"/>
402
403### Why not use Commander.js?
404
405CAC 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.
406
407_And maybe more..._
408
409Basically 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
410
411## Contributing
412
4131. Fork it!
4142. Create your feature branch: `git checkout -b my-new-feature`
4153. Commit your changes: `git commit -am 'Add some feature'`
4164. Push to the branch: `git push origin my-new-feature`
4175. Submit a pull request :D
418
419## Author
420
421**CAC** © [EGOIST](https://github.com/egoist), Released under the [MIT](./LICENSE) License.<br>
422Authored and maintained by egoist with help from contributors ([list](https://github.com/cacjs/cac/contributors)).
423
424> [Website](https://egoist.sh) · GitHub [@egoist](https://github.com/egoist) · Twitter [@\_egoistlily](https://twitter.com/_egoistlily)