cac
Advanced tools
Comparing version 4.0.0 to 4.1.0
@@ -14,2 +14,9 @@ 'use strict'; | ||
class CacError extends Error { | ||
constructor(message) { | ||
super(message); | ||
this.name = 'CacError'; | ||
} | ||
} | ||
function parseType(type) { | ||
@@ -45,2 +52,8 @@ if (typeof type === 'string' || type instanceof String) { | ||
function invariant(exp, message) { | ||
if (!exp) { | ||
throw new CacError(message) | ||
} | ||
} | ||
class Options { | ||
@@ -124,2 +137,6 @@ constructor() { | ||
} | ||
invariant(typeof name === 'string', 'Expect command name to be a string.'); | ||
invariant(option.desc, 'Expect command to have a description.'); | ||
const command = { | ||
@@ -130,3 +147,5 @@ name, | ||
}; | ||
command.names = orderNames([command.name].concat(command.alias)); | ||
this.command = command; | ||
@@ -226,19 +245,9 @@ this.options = new Options(); | ||
alias: 'v', | ||
type: Boolean, | ||
type: 'boolean', | ||
desc: 'Display version' | ||
}) | ||
.option('help', { | ||
alias: 'h', | ||
type: Boolean, | ||
desc: `Display help (You're already here)` | ||
}) | ||
.option('quiet', { | ||
type: Boolean, | ||
desc: 'Quiet mode - only display warn and error messages' | ||
}) | ||
.option('verbose', { | ||
alias: 'V', | ||
type: Boolean, | ||
desc: 'Verbose mode - will always output debug messages' | ||
}); | ||
}).option('help', { | ||
alias: 'h', | ||
type: 'boolean', | ||
desc: `Display help (You're already here)` | ||
}); | ||
} | ||
@@ -375,20 +384,9 @@ | ||
} else if (command && command.handler) { | ||
const winston = require('winston'); | ||
const logger = new winston.Logger({ | ||
level: flags.verbose ? 'debug' : flags.quiet ? 'warn' : 'info', | ||
transports: [ | ||
new winston.transports.Console({ | ||
handleExceptions: true | ||
}) | ||
] | ||
}); | ||
try { | ||
const res = command.handler(input, flags, logger); | ||
const res = command.handler(input, flags); | ||
if (res && res.catch) { | ||
res.catch(err => this.handleError(err, logger)); | ||
res.catch(err => this.handleError(err)); | ||
} | ||
} catch (err) { | ||
this.handleError(err, logger); | ||
this.handleError(err); | ||
} | ||
@@ -398,8 +396,8 @@ } | ||
handleError(err, logger) { | ||
process.exitCode = process.exitCode || 1; | ||
handleError(err) { | ||
if (EventEmitter.listenerCount(this, 'error') === 0) { | ||
logger.error(err); | ||
console.error(err); | ||
process.exitCode = process.exitCode || 1; | ||
} else { | ||
this.emit('error', err, logger); | ||
this.emit('error', err); | ||
} | ||
@@ -406,0 +404,0 @@ } |
{ | ||
"name": "cac", | ||
"version": "4.0.0", | ||
"version": "4.1.0", | ||
"description": "Command-line queen.", | ||
@@ -23,6 +23,7 @@ "repository": { | ||
"scripts": { | ||
"test": "echo 'no tests!' && npm run lint", | ||
"test": "npm run lint && ava", | ||
"lint": "xo", | ||
"build": "bili --buble.target.node 4", | ||
"prepublish": "npm run build" | ||
"prepublish": "npm run build", | ||
"toc": "markdown-toc -i README.md" | ||
}, | ||
@@ -34,9 +35,10 @@ "author": "egoist <0x142857@gmail.com>", | ||
"minimost": "^1.0.0", | ||
"mri": "^1.1.0", | ||
"read-pkg-up": "^2.0.0", | ||
"redent": "^2.0.0", | ||
"string-width": "^2.1.1", | ||
"text-table": "^0.2.0", | ||
"winston": "^2.3.1" | ||
"text-table": "^0.2.0" | ||
}, | ||
"devDependencies": { | ||
"ava": "^0.21.0", | ||
"babel-plugin-transform-object-rest-spread": "^6.23.0", | ||
@@ -47,4 +49,11 @@ "babel-preset-env": "^1.6.0", | ||
"eslint-config-rem": "^3.0.0", | ||
"markdown-toc": "^1.1.0", | ||
"xo": "^0.18.0" | ||
}, | ||
"ava": { | ||
"babel": "inherit", | ||
"require": [ | ||
"babel-register" | ||
] | ||
}, | ||
"xo": { | ||
@@ -51,0 +60,0 @@ "extends": "rem/prettier", |
127
README.md
@@ -1,3 +0,4 @@ | ||
# cac | ||
<img width="945" alt="2017-07-26 9 27 05" src="https://user-images.githubusercontent.com/8784712/28623641-373450f4-7249-11e7-854d-1b076dab274d.png"> | ||
[![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/egoist/cac/tree/master.svg?style=shield)](https://circleci.com/gh/egoist/cac/tree/master) [![donate](https://img.shields.io/badge/$-donate-ff69b4.svg?maxAge=2592000&style=flat)](https://github.com/egoist/donate) | ||
@@ -7,4 +8,2 @@ | ||
<img src="http://i.giphy.com/v3FeH4swox9mg.gif" width="400"/> | ||
## Install | ||
@@ -16,2 +15,27 @@ | ||
## Table of contents | ||
<!-- toc --> | ||
- [Usage](#usage) | ||
* [No-command app](#no-command-app) | ||
- [Friends](#friends) | ||
- [Documentation](#documentation) | ||
* [cli.option(name, [option])](#clioptionname-option) | ||
* [cli.command(name, [option], [handler])](#clicommandname-option-handler) | ||
+ [command](#command) | ||
- [command.option(name, [option])](#commandoptionname-option) | ||
* [cli.parse([argv], [option])](#cliparseargv-option) | ||
* [cli.showHelp()](#clishowhelp) | ||
* [cli.argv](#cliargv) | ||
* [Events](#events) | ||
* [error](#error) | ||
- [FAQ](#faq) | ||
* [Why not `commander.js` `yargs` `caporal.js` or `meow`?](#why-not-commanderjs-yargs-caporaljs-or-meow) | ||
* [How is the name written and pronounced?](#how-is-the-name-written-and-pronounced) | ||
- [Contributing](#contributing) | ||
- [Author](#author) | ||
<!-- tocstop --> | ||
## Usage | ||
@@ -52,11 +76,41 @@ | ||
<img width="403" alt="2017-07-26 2 29 46" src="https://user-images.githubusercontent.com/8784712/28607539-f016218c-720e-11e7-8552-af88c183ad7f.png"> | ||
<img width="303" alt="2017-07-26 2 29 46" src="https://i.loli.net/2017/07/26/5978a1a7c72f5.png"> | ||
And the **Help Documentation** is ready out of the box: | ||
<img width="854" alt="2017-07-26 4 29 36" src="https://user-images.githubusercontent.com/8784712/28611814-a8da742e-721f-11e7-8b52-17bda78809fe.png"> | ||
<img width="600" alt="2017-07-26 4 29 36" src="https://ooo.0o0.ooo/2017/07/26/5978a121886c4.png"> | ||
### No-command app | ||
## Documentations | ||
In many cases your app is small and doesn't even need a *command*: | ||
```js | ||
const cli = require('cac')() | ||
// Use default command symbol '*' | ||
cli.command('*', option, runMyApp) | ||
cli.parse() | ||
``` | ||
Instead of using a default command, you can skip adding and running command by: | ||
```js | ||
const cli = require('cac')() | ||
// cli.argv is a getter | ||
// bascially it's the return value of cli.parse(null, { run: false }) | ||
const { input, flags } = cli.argv | ||
runMyApp(input, flags) | ||
``` | ||
## Friends | ||
Projects that use **CAC**: | ||
- [SAO](https://github.com/egoist/sao): ⚔️ Futuristic scaffolding tool. | ||
- [Poi](https://github.com/egoist/poi): ⚡️ Delightful web development. | ||
- [bili](https://github.com/egoist/bili): 🥂 Schweizer Armeemesser for bundling JavaScript libraries. | ||
- Feel free to add yours here... | ||
## Documentation | ||
### cli.option(name, [option]) | ||
@@ -70,3 +124,3 @@ | ||
- alias: `string` `Array<string>` option name alias | ||
- type: `string` option type, valid values: `boolean` `number` | ||
- type: `string` option type, valid values: `boolean` `string` | ||
- default: `any` option default value | ||
@@ -85,3 +139,3 @@ | ||
```js | ||
const command = cli.command('init', 'init a new project', (input, flags, logger) => { | ||
const command = cli.command('init', 'init a new project', (input, flags) => { | ||
const folderName = input[0] | ||
@@ -98,14 +152,4 @@ console.log(`init project in folder ${folderName}`) | ||
Same as [cli.option](clioptionnameoption) but it adds options for specified command. | ||
Same as [cli.option](#clioptionname-option) but it adds options for specified command. | ||
#### logger | ||
The third argument of command `handler` is a `logger` object which is a [winston](https://github.com/winstonjs/winston) instance. | ||
It's set to different level in different cases: | ||
- when `--verbose`: it's set to `debug` | ||
- when `--quiet`: it's set to `warn` | ||
- by default it's `info` | ||
### cli.parse([argv], [option]) | ||
@@ -117,2 +161,47 @@ | ||
### cli.showHelp() | ||
Display cli helps, must be called after `cli.parse()` | ||
### cli.argv | ||
A getter which simply returns `cli.parse(null, { run: false })` | ||
### Events | ||
### error | ||
Error handler for errors in your command handler: | ||
```js | ||
cli.on('error', err => { | ||
console.error('command failed:', err) | ||
process.exit(1) | ||
}) | ||
``` | ||
## FAQ | ||
### Why not `commander.js` `yargs` `caporal.js` or `meow`? | ||
Commander.js and Caporal.js do not allow unknown options, Commander.js does not support [chaining option](https://github.com/tj/commander.js/issues/606). | ||
Yargs has a powerful API, but it's so massive that my brain trembles. Meow is simple and elegant but I have to manully construct the *help* message, which will be annoying. And I want it to support *sub-command* too. | ||
**So why creating a new thing instead of pull request?** | ||
I would ask me myself why there's `preact` instead of PR to `react`, and why `yarn` instead of PR to `npm`? It's obvious. | ||
**CAC** is kind of like a combination of the simplicity of Meow and the powerful features of the rest. And our *help* log is inspired by Caporal.js, I guess it might be the most elegant one out there? | ||
<img alt="preview" src="https://i.loli.net/2017/07/26/59789ed2112f6.png" width="500"> | ||
### How is the name written and pronounced? | ||
CAC, not Cac or cac, [Pronounced `/kɑk/`](https://www.howtopronounce.com/cac/). | ||
And this project is dedicated to our lovely C.C. sama. Maybe CAC stands for C&C as well :P | ||
<img src="http://i.giphy.com/v3FeH4swox9mg.gif" width="400"/> | ||
## Contributing | ||
@@ -119,0 +208,0 @@ |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
18555
1
215
0
8
332
+ Addedmri@^1.1.0
+ Addedmri@1.2.0(transitive)
- Removedwinston@^2.3.1
- Removedasync@2.6.4(transitive)
- Removedcolors@1.0.3(transitive)
- Removedcycle@1.0.3(transitive)
- Removedeyes@0.1.8(transitive)
- Removedisstream@0.1.2(transitive)
- Removedlodash@4.17.21(transitive)
- Removedstack-trace@0.0.10(transitive)
- Removedwinston@2.4.7(transitive)