UNPKG

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