Comparing version 1.0.0 to 2.0.0
261
index.js
@@ -1,120 +0,201 @@ | ||
'use strict' | ||
const Path = require('path') | ||
const co = require('co') | ||
const isGeneratorFunction = require('is-generator-function') | ||
const minimist = require('minimist') | ||
const camelcaseKeys = require('camelcase-keys') | ||
const readPkgUp = require('read-pkg-up') | ||
const assign = require('deep-assign') | ||
'use strict'; | ||
const parentDir = Path.dirname(module.parent.filename) | ||
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } | ||
function formatArgv(argv) { | ||
const input = argv._ | ||
delete argv._ | ||
return { | ||
input, | ||
flags: camelcaseKeys(argv, {exclude: ['--']}) | ||
var minimist = _interopDefault(require('minimist')); | ||
var table = _interopDefault(require('text-table')); | ||
var indent = _interopDefault(require('indent-string')); | ||
var chalk = _interopDefault(require('chalk')); | ||
var camelcase = _interopDefault(require('camelcase-keys')); | ||
var readPkg = _interopDefault(require('read-pkg-up')); | ||
var prefixedOption = function (option, aliasOptions) { | ||
var options = [option] | ||
if (aliasOptions[option]) { | ||
options.push(aliasOptions[option]) | ||
} | ||
return options | ||
.map(function (name) { return name.length > 1 ? ("--" + name) : ("-" + name); }) | ||
.join(', ') | ||
} | ||
function printWrap(pkg, text) { | ||
const header = pkg.description | ||
? `\n ${pkg.description}\n` | ||
: '' | ||
console.log(header + text) | ||
var showDefaultValue = function (value) { | ||
return (typeof value === 'undefined') ? | ||
'' : | ||
chalk.grey(("[default: " + value + "]")) | ||
} | ||
const Cac = function (help, options) { | ||
if (!(this instanceof Cac)) { | ||
return new Cac(help, options) | ||
var parseNames = function (names) { | ||
if (names === '*') { | ||
return {name: '*'} | ||
} | ||
this.commands = {} | ||
this.rawCommands = [] | ||
this.help = help || '' | ||
this.options = options || {} | ||
this.pkg = readPkgUp.sync({ | ||
cwd: parentDir, | ||
normalize: false | ||
}).pkg | ||
var splitNames = names | ||
.match(/([\w\.]+)\s*,?\s*([\w\.]*)/) | ||
.slice(1, 3) | ||
.sort() | ||
.reverse() | ||
return { | ||
name: splitNames[0], | ||
alias: splitNames[1] | ||
} | ||
} | ||
const _ = Cac.prototype | ||
_.command = function (name, fn) { | ||
name.split(',').forEach(val => { | ||
val = val.trim() | ||
this.commands[val] = fn | ||
this.rawCommands.push(val) | ||
var parseArgv = function (argv, options) { | ||
var result = {} | ||
var args = minimist(argv, options) | ||
var input = args._ | ||
delete args._ | ||
result.input = input | ||
result.flags = args | ||
return camelcase(result, { | ||
excludeKeys: ['--'] | ||
}) | ||
} | ||
_.parse = function (argv) { | ||
argv = argv || process.argv.slice(2) | ||
var defaultOptions = { | ||
help: { | ||
description: 'Output usage information' | ||
}, | ||
version: { | ||
description: 'Output version number' | ||
} | ||
} | ||
const options = assign({}, { | ||
alias: { | ||
v: 'version', | ||
h: 'help' | ||
} | ||
}, this.options) | ||
var CAC = function CAC() { | ||
var this$1 = this; | ||
this.argv = formatArgv(minimist(argv, options)) | ||
this.bootstrap() | ||
} | ||
if (!(this instanceof CAC)) { | ||
return new CAC() | ||
} | ||
this.commands = {} | ||
this.aliasCommands = {} | ||
this.defaultValues = {} | ||
this.options = defaultOptions | ||
this.aliasOptions = {} | ||
this.handleError = function (err) { | ||
throw err | ||
} | ||
this.pkg = readPkg.sync().pkg | ||
_.bootstrap = function () { | ||
const title = this.pkg.bin | ||
? Object.keys(this.pkg.bin)[0] | ||
: this.pkg.name | ||
process.title = title | ||
this | ||
.addAliasOption('version', 'v') | ||
.addAliasOption('help', 'h') | ||
if (this.argv.flags.help) { | ||
this.showHelp() | ||
return | ||
this | ||
.command('help', 'Display help', function () { return this$1.showHelp(); }) | ||
}; | ||
CAC.prototype.onError = function onError (fn) { | ||
this.handleError = fn | ||
return this | ||
}; | ||
CAC.prototype.addAliasOption = function addAliasOption (long, short) { | ||
this.aliasOptions[long] = short | ||
return this | ||
}; | ||
CAC.prototype.aliasCommand = function aliasCommand (long, short) { | ||
this.aliasCommands[long] = short | ||
if (long && short) { | ||
this.commands[short] = this.commands[long] | ||
} | ||
}; | ||
if (this.argv.flags.version && this.pkg.version) { | ||
console.log(this.pkg.version) | ||
return | ||
CAC.prototype.option = function option (names, description, defaultValue) { | ||
var ref = parseNames(names); | ||
var name = ref.name; | ||
var alias = ref.alias; | ||
this.options[name] = { | ||
description: description, | ||
defaultValue: defaultValue | ||
} | ||
if (typeof defaultValue !== 'undefined') { | ||
this.defaultValues[name] = defaultValue | ||
} | ||
const command = this.argv.input[0] | ||
if (this.rawCommands.indexOf(command) === -1) { | ||
this.runCommand(this.commands['*']) | ||
} else { | ||
this.runCommand(this.commands[command]) | ||
if (alias) { | ||
this.addAliasOption(name, alias) | ||
} | ||
} | ||
_.runCommand = function (commandFn) { | ||
if (commandFn) { | ||
const context = { | ||
input: this.argv.input, | ||
flags: this.argv.flags, | ||
showHelp: this.showHelp.bind(this), | ||
rawCommands: this.rawCommands | ||
return this | ||
}; | ||
CAC.prototype.showHelp = function showHelp () { | ||
var this$1 = this; | ||
var optionsTable = table(Object.keys(this.options).map(function (option) { return [ | ||
chalk.yellow(prefixedOption(option, this$1.aliasOptions)), | ||
chalk.grey(this$1.options[option].description), | ||
showDefaultValue(this$1.options[option].defaultValue) | ||
]; })) | ||
var commandsTable = table(Object.keys(this.aliasCommands).map(function (command) { | ||
var alias = this$1.aliasCommands[command] | ||
return [ | ||
chalk.yellow(("" + command + (alias ? (", " + alias) : ''))), | ||
chalk.grey(this$1.commands[command].description) | ||
] | ||
})) | ||
var help = (this.pkg.description ? ("\n" + (this.pkg.description) + "\n") : '') + "\nUsage: " + (chalk.yellow(this.pkg.name)) + " " + (chalk.grey('[options] [commands]')) + "\n\nCommands:\n\n" + (indent(commandsTable, 2)) + "\n\nOptions:\n\n" + (indent(optionsTable, 2)) + "\n" | ||
console.log(indent(help, 2)) | ||
process.exit(0) | ||
}; | ||
CAC.prototype.command = function command (names, description, fn) { | ||
var ref = parseNames(names); | ||
var name = ref.name; | ||
var alias = ref.alias; | ||
this.commands[name] = { | ||
description: description, | ||
fn: fn | ||
} | ||
this.aliasCommand(name, alias) | ||
return this | ||
}; | ||
CAC.prototype.runCommand = function runCommand (command) { | ||
var commandFn = command && command.fn | ||
if (typeof commandFn === 'function') { | ||
var result | ||
try { | ||
result = commandFn(this.argv.input, this.argv.flags) | ||
} catch (err) { | ||
this.handleError(err) | ||
} | ||
if (isGeneratorFunction(commandFn)) { | ||
co(commandFn.bind(context)).catch(this.onError.bind(context)) | ||
} else { | ||
commandFn.call(context) | ||
if (result && result.then) { | ||
result.catch(this.handleError) | ||
} | ||
} | ||
} | ||
_.showHelp = function () { | ||
if (this.help) { | ||
if (Array.isArray(this.help)) { | ||
printWrap.call(this.pkg, this.help.join('\n')) | ||
} else { | ||
printWrap(this.pkg, this.help) | ||
} | ||
return this | ||
}; | ||
CAC.prototype.showVersion = function showVersion () { | ||
console.log(this.pkg.version) | ||
process.exit(0) | ||
}; | ||
CAC.prototype.parse = function parse (argv) { | ||
argv = argv || process.argv.slice(2) | ||
this.argv = parseArgv(argv, { | ||
alias: this.aliasOptions, | ||
default: this.defaultValues | ||
}) | ||
if (this.argv.flags.help) { | ||
this.showHelp() | ||
} | ||
} | ||
if (this.argv.flags.version) { | ||
this.showVersion() | ||
} | ||
_.onError = function (e) { | ||
console.log(e.stack || e.message || e.name) | ||
} | ||
var command = this.commands[this.argv.input[0] || '*'] | ||
this.runCommand(command) | ||
module.exports = Cac | ||
return this | ||
}; | ||
module.exports = CAC; |
{ | ||
"name": "cac", | ||
"version": "1.0.0", | ||
"description": "Command And Conquer.", | ||
"version": "2.0.0", | ||
"description": "Command & Conquer, the command-line queen.", | ||
"license": "MIT", | ||
"repository": "egoist/cac", | ||
"author": { | ||
"name": "EGOIST", | ||
"name": "egoist", | ||
"email": "0x142857@gmail.com", | ||
@@ -16,5 +16,5 @@ "url": "github.com/egoist" | ||
"scripts": { | ||
"test": "xo && nyc ava", | ||
"example:help": "node examples/help -h", | ||
"example:alias-command": "node examples/alias-command r" | ||
"test": "xo src/index.js", | ||
"test2": "npm run build && npm test", | ||
"build": "bubleup" | ||
}, | ||
@@ -27,2 +27,4 @@ "files": [ | ||
"commander", | ||
"yargs", | ||
"args", | ||
"meow", | ||
@@ -32,6 +34,2 @@ "minimist" | ||
"devDependencies": { | ||
"ava": "latest", | ||
"coveralls": "^2.11.9", | ||
"nyc": "^6.4.0", | ||
"then-sleep": "^1.0.1", | ||
"xo": "latest" | ||
@@ -43,25 +41,21 @@ }, | ||
"rules": { | ||
"operator-linebreak": [ | ||
2, | ||
"before" | ||
], | ||
"no-warning-comments": [ | ||
2, | ||
{ | ||
"terms": [ | ||
"fixme" | ||
], | ||
"location": "start" | ||
} | ||
] | ||
"xo/no-process-exit": 0 | ||
} | ||
}, | ||
"dependencies": { | ||
"camelcase-keys": "^2.1.0", | ||
"co": "^4.6.0", | ||
"deep-assign": "^2.0.0", | ||
"is-generator-function": "^1.0.3", | ||
"camelcase-keys": "^3.0.0", | ||
"chalk": "^1.1.3", | ||
"indent-string": "^3.0.0", | ||
"minimist": "^1.2.0", | ||
"read-pkg-up": "^1.0.1" | ||
"read-pkg-up": "^1.0.1", | ||
"text-table": "^0.2.0" | ||
}, | ||
"bubleup": { | ||
"transforms": { | ||
"dangerousForOf": true | ||
} | ||
}, | ||
"kanpai": { | ||
"testScript": "test2" | ||
} | ||
} |
@@ -1,15 +0,7 @@ | ||
# CAC [![NPM version](https://img.shields.io/npm/v/cac.svg)](https://npmjs.com/package/cac) [![NPM downloads](https://img.shields.io/npm/dm/cac.svg)](https://npmjs.com/package/cac) [![Build Status](https://img.shields.io/circleci/project/egoist/cac/master.svg)](https://circleci.com/gh/egoist/cac) [![Coveralls branch](https://img.shields.io/coveralls/egoist/cac/master.svg)](https://github.com/egoist/cac) | ||
# cac [![NPM version](https://img.shields.io/npm/v/cac.svg)](https://npmjs.com/package/cac) [![NPM downloads](https://img.shields.io/npm/dm/cac.svg)](https://npmjs.com/package/cac) [![Build Status](https://img.shields.io/circleci/project/egoist/cac/master.svg)](https://circleci.com/gh/egoist/cac) | ||
**C**ommand **A**nd **C**onquer, the queen living in your command line. | ||
## Features | ||
<img src="http://i.giphy.com/v3FeH4swox9mg.gif" width="400"/> | ||
- [x] Simplified [commander.js](https://github.com/tj/commander.js) | ||
- [x] Camelcased keys, eg `--disable-input` => `disableInput` | ||
- [x] Automatically read `package.json`, parse package meta | ||
- [x] Automatically print related data when `--version` and `--help` | ||
- [x] Change `process.title` for you | ||
- [x] Support [co](https://github.com/tj/co) flow | ||
- [x] Well tested | ||
## Install | ||
@@ -23,62 +15,50 @@ | ||
Start your first CLI app in `example.js`: | ||
```js | ||
const cac = require('cac') | ||
const fs = require('fs-promise') | ||
const cli = cac(` | ||
Usage: | ||
node example.js create <filename> -m [content] | ||
Commands: | ||
c, create Create a file with specific content | ||
Options: | ||
-m, --message File content | ||
-h, --help Print help (You are here!) | ||
`, { | ||
alias: { | ||
m: message, | ||
h: help | ||
} | ||
}) | ||
// initialize your cli program | ||
const cli = cac() | ||
cli.command('c, create', function* () { | ||
const fileName = this.input[1] | ||
const content = this.flags.message | ||
yield fs.createFile(fileName, 'hello') | ||
console.log('Done!') | ||
// add your very first command | ||
cli.command('hi', 'Say hi!', (input) => { | ||
console.log(`hi ${input[1] || 'boy'}!`) | ||
}) | ||
cli.command('*', function () { | ||
console.log('Everything else') | ||
}} | ||
// use .parse() to bootstrap the CLI | ||
// parse arguments and bootstrap | ||
cli.parse() | ||
``` | ||
All set! Just run: | ||
<img src="http://ww4.sinaimg.cn/large/a15b4afegw1f79ix3vc2uj20p00akjsj.jpg" width="400" /> | ||
```bash | ||
$ node example.js create lol.txt -m "just lol 😂" | ||
``` | ||
### Default commands and options | ||
- Options: `--help` `-h` `--version` `-v` | ||
- Commands: `help` | ||
<img src="http://ww4.sinaimg.cn/large/a15b4afegw1f79k0eifspj20ug0g0mz3.jpg" width="400" /> | ||
## API | ||
### cac([help], [options]) | ||
## .option(options, description, defaultValue) | ||
#### help | ||
- **options**: `string`, it could be `option` or `option, alias` or `alias, option`, the order does not matter. eg: `.option('install, i')` | ||
- **description**: `string`, option description, will be used to output cli usage | ||
- **defaultValue**: `any`, give a default value to this option | ||
Type: `string` `array` | ||
## .command(commands, description, fn) | ||
The help info. | ||
- **commands**: `string`, it could be `command` or `command, alias` or `alias, command`, the order does not matter. eg: `.command('clone, c')`. It can also be a wildcard symbol `*`, which means always been triggered if no command was specified by user. | ||
- **description**: `string`, command description, will be used to output cli usage | ||
- **fn**: `function`, command function, will be triggered when this command matches user's input | ||
#### options | ||
## .parse(argv) | ||
The [minimist](https://github.com/substack/minimist) options. | ||
- **argv**: `array`, default is `process.argv.slice(2)` | ||
## .onError(handleError) | ||
- **handleError**: `function`, triggered when your program throws an error or was rejected by a Promise call. | ||
## License | ||
MIT © [EGOIST](https://github.com/egoist) | ||
MIT © [egoist](https://github.com/egoist) |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
9197
1
169
64
1
+ Addedchalk@^1.1.3
+ Addedindent-string@^3.0.0
+ Addedtext-table@^0.2.0
+ Addedansi-regex@2.1.1(transitive)
+ Addedansi-styles@2.2.1(transitive)
+ Addedcamelcase@3.0.0(transitive)
+ Addedcamelcase-keys@3.0.0(transitive)
+ Addedchalk@1.1.3(transitive)
+ Addedescape-string-regexp@1.0.5(transitive)
+ Addedhas-ansi@2.0.0(transitive)
+ Addedindent-string@3.2.0(transitive)
+ Addedstrip-ansi@3.0.1(transitive)
+ Addedsupports-color@2.0.0(transitive)
+ Addedtext-table@0.2.0(transitive)
- Removedco@^4.6.0
- Removeddeep-assign@^2.0.0
- Removedis-generator-function@^1.0.3
- Removedcamelcase@2.1.1(transitive)
- Removedcamelcase-keys@2.1.0(transitive)
- Removedco@4.6.0(transitive)
- Removeddeep-assign@2.0.0(transitive)
- Removedhas-symbols@1.0.3(transitive)
- Removedhas-tostringtag@1.0.2(transitive)
- Removedis-generator-function@1.0.10(transitive)
- Removedis-obj@1.0.1(transitive)
Updatedcamelcase-keys@^3.0.0