dragonfly_chrome_headless 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (228) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.travis.yml +12 -0
  4. data/Gemfile +4 -0
  5. data/README.md +53 -0
  6. data/Rakefile +10 -0
  7. data/bin/console +14 -0
  8. data/bin/setup +8 -0
  9. data/dragonfly_chrome_headless.gemspec +27 -0
  10. data/lib/dragonfly_chrome_headless.rb +9 -0
  11. data/lib/dragonfly_chrome_headless/plugin.rb +17 -0
  12. data/lib/dragonfly_chrome_headless/processors/rasterize.rb +33 -0
  13. data/lib/dragonfly_chrome_headless/version.rb +3 -0
  14. data/node_modules/.bin/chrome-remote-interface +1 -0
  15. data/node_modules/.bin/mkdirp +1 -0
  16. data/node_modules/.bin/rimraf +1 -0
  17. data/node_modules/@types/core-js/LICENSE +21 -0
  18. data/node_modules/@types/core-js/README.md +16 -0
  19. data/node_modules/@types/core-js/index.d.ts +2452 -0
  20. data/node_modules/@types/core-js/package.json +85 -0
  21. data/node_modules/@types/mkdirp/README.md +18 -0
  22. data/node_modules/@types/mkdirp/index.d.ts +14 -0
  23. data/node_modules/@types/mkdirp/package.json +77 -0
  24. data/node_modules/@types/mkdirp/types-metadata.json +25 -0
  25. data/node_modules/@types/node/README.md +16 -0
  26. data/node_modules/@types/node/index.d.ts +4132 -0
  27. data/node_modules/@types/node/package.json +84 -0
  28. data/node_modules/balanced-match/.npmignore +5 -0
  29. data/node_modules/balanced-match/LICENSE.md +21 -0
  30. data/node_modules/balanced-match/README.md +91 -0
  31. data/node_modules/balanced-match/index.js +59 -0
  32. data/node_modules/balanced-match/package.json +112 -0
  33. data/node_modules/brace-expansion/README.md +123 -0
  34. data/node_modules/brace-expansion/index.js +201 -0
  35. data/node_modules/brace-expansion/package.json +114 -0
  36. data/node_modules/chrome-launcher/.clang-format +6 -0
  37. data/node_modules/chrome-launcher/.npmignore +11 -0
  38. data/node_modules/chrome-launcher/README.md +123 -0
  39. data/node_modules/chrome-launcher/ask.js +32 -0
  40. data/node_modules/chrome-launcher/ask.ts +35 -0
  41. data/node_modules/chrome-launcher/chrome-finder.js +157 -0
  42. data/node_modules/chrome-launcher/chrome-finder.ts +186 -0
  43. data/node_modules/chrome-launcher/chrome-launcher.js +245 -0
  44. data/node_modules/chrome-launcher/chrome-launcher.ts +312 -0
  45. data/node_modules/chrome-launcher/compiled-check.js +14 -0
  46. data/node_modules/chrome-launcher/flags.js +27 -0
  47. data/node_modules/chrome-launcher/flags.ts +26 -0
  48. data/node_modules/chrome-launcher/index.js +7 -0
  49. data/node_modules/chrome-launcher/index.ts +1 -0
  50. data/node_modules/chrome-launcher/manual-chrome-launcher.js +30 -0
  51. data/node_modules/chrome-launcher/package.json +116 -0
  52. data/node_modules/chrome-launcher/random-port.js +24 -0
  53. data/node_modules/chrome-launcher/random-port.ts +23 -0
  54. data/node_modules/chrome-launcher/tsconfig.json +19 -0
  55. data/node_modules/chrome-launcher/utils.js +52 -0
  56. data/node_modules/chrome-launcher/utils.ts +44 -0
  57. data/node_modules/chrome-launcher/yarn.lock +1486 -0
  58. data/node_modules/chrome-remote-interface/LICENSE +18 -0
  59. data/node_modules/chrome-remote-interface/README.md +849 -0
  60. data/node_modules/chrome-remote-interface/bin/client.js +337 -0
  61. data/node_modules/chrome-remote-interface/chrome-remote-interface.js +11 -0
  62. data/node_modules/chrome-remote-interface/index.js +39 -0
  63. data/node_modules/chrome-remote-interface/lib/api.js +84 -0
  64. data/node_modules/chrome-remote-interface/lib/chrome.js +307 -0
  65. data/node_modules/chrome-remote-interface/lib/defaults.js +4 -0
  66. data/node_modules/chrome-remote-interface/lib/devtools.js +245 -0
  67. data/node_modules/chrome-remote-interface/lib/external-request.js +28 -0
  68. data/node_modules/chrome-remote-interface/lib/protocol.json +13780 -0
  69. data/node_modules/chrome-remote-interface/lib/websocket-wrapper.js +32 -0
  70. data/node_modules/chrome-remote-interface/package.json +128 -0
  71. data/node_modules/chrome-remote-interface/webpack.config.js +55 -0
  72. data/node_modules/commander/Readme.md +195 -0
  73. data/node_modules/commander/index.js +851 -0
  74. data/node_modules/commander/package.json +92 -0
  75. data/node_modules/concat-map/.travis.yml +4 -0
  76. data/node_modules/concat-map/LICENSE +18 -0
  77. data/node_modules/concat-map/README.markdown +62 -0
  78. data/node_modules/concat-map/example/map.js +6 -0
  79. data/node_modules/concat-map/index.js +13 -0
  80. data/node_modules/concat-map/package.json +117 -0
  81. data/node_modules/concat-map/test/map.js +39 -0
  82. data/node_modules/debug/.coveralls.yml +1 -0
  83. data/node_modules/debug/.eslintrc +11 -0
  84. data/node_modules/debug/.npmignore +9 -0
  85. data/node_modules/debug/.travis.yml +14 -0
  86. data/node_modules/debug/CHANGELOG.md +357 -0
  87. data/node_modules/debug/LICENSE +19 -0
  88. data/node_modules/debug/Makefile +50 -0
  89. data/node_modules/debug/Readme.md +312 -0
  90. data/node_modules/debug/component.json +19 -0
  91. data/node_modules/debug/karma.conf.js +70 -0
  92. data/node_modules/debug/node.js +1 -0
  93. data/node_modules/debug/package.json +124 -0
  94. data/node_modules/debug/src/browser.js +185 -0
  95. data/node_modules/debug/src/debug.js +202 -0
  96. data/node_modules/debug/src/index.js +10 -0
  97. data/node_modules/debug/src/node.js +246 -0
  98. data/node_modules/fs.realpath/LICENSE +43 -0
  99. data/node_modules/fs.realpath/README.md +33 -0
  100. data/node_modules/fs.realpath/index.js +66 -0
  101. data/node_modules/fs.realpath/old.js +303 -0
  102. data/node_modules/fs.realpath/package.json +94 -0
  103. data/node_modules/glob/LICENSE +15 -0
  104. data/node_modules/glob/README.md +368 -0
  105. data/node_modules/glob/changelog.md +67 -0
  106. data/node_modules/glob/common.js +240 -0
  107. data/node_modules/glob/glob.js +790 -0
  108. data/node_modules/glob/package.json +112 -0
  109. data/node_modules/glob/sync.js +486 -0
  110. data/node_modules/html-pdf-chrome/.npmignore +9 -0
  111. data/node_modules/html-pdf-chrome/LICENSE +21 -0
  112. data/node_modules/html-pdf-chrome/README.md +165 -0
  113. data/node_modules/html-pdf-chrome/lib/src/ChromePrintOptions.d.ts +87 -0
  114. data/node_modules/html-pdf-chrome/lib/src/ChromePrintOptions.js +4 -0
  115. data/node_modules/html-pdf-chrome/lib/src/ChromePrintOptions.js.map +1 -0
  116. data/node_modules/html-pdf-chrome/lib/src/CompletionTrigger.d.ts +120 -0
  117. data/node_modules/html-pdf-chrome/lib/src/CompletionTrigger.js +206 -0
  118. data/node_modules/html-pdf-chrome/lib/src/CompletionTrigger.js.map +1 -0
  119. data/node_modules/html-pdf-chrome/lib/src/CreateResult.d.ts +70 -0
  120. data/node_modules/html-pdf-chrome/lib/src/CreateResult.js +98 -0
  121. data/node_modules/html-pdf-chrome/lib/src/CreateResult.js.map +1 -0
  122. data/node_modules/html-pdf-chrome/lib/src/index.d.ts +72 -0
  123. data/node_modules/html-pdf-chrome/lib/src/index.js +123 -0
  124. data/node_modules/html-pdf-chrome/lib/src/index.js.map +1 -0
  125. data/node_modules/html-pdf-chrome/package.json +133 -0
  126. data/node_modules/html-pdf-chrome/src/ChromePrintOptions.ts +99 -0
  127. data/node_modules/html-pdf-chrome/src/CompletionTrigger.ts +201 -0
  128. data/node_modules/html-pdf-chrome/src/CreateResult.ts +100 -0
  129. data/node_modules/html-pdf-chrome/src/index.ts +179 -0
  130. data/node_modules/inflight/LICENSE +15 -0
  131. data/node_modules/inflight/README.md +37 -0
  132. data/node_modules/inflight/inflight.js +54 -0
  133. data/node_modules/inflight/package.json +105 -0
  134. data/node_modules/inherits/LICENSE +16 -0
  135. data/node_modules/inherits/README.md +42 -0
  136. data/node_modules/inherits/inherits.js +7 -0
  137. data/node_modules/inherits/inherits_browser.js +23 -0
  138. data/node_modules/inherits/package.json +97 -0
  139. data/node_modules/lighthouse-logger/README.md +4 -0
  140. data/node_modules/lighthouse-logger/index.js +212 -0
  141. data/node_modules/lighthouse-logger/package.json +69 -0
  142. data/node_modules/lighthouse-logger/yarn.lock +13 -0
  143. data/node_modules/minimatch/LICENSE +15 -0
  144. data/node_modules/minimatch/README.md +209 -0
  145. data/node_modules/minimatch/minimatch.js +923 -0
  146. data/node_modules/minimatch/package.json +99 -0
  147. data/node_modules/minimist/.travis.yml +4 -0
  148. data/node_modules/minimist/LICENSE +18 -0
  149. data/node_modules/minimist/example/parse.js +2 -0
  150. data/node_modules/minimist/index.js +187 -0
  151. data/node_modules/minimist/package.json +101 -0
  152. data/node_modules/minimist/readme.markdown +73 -0
  153. data/node_modules/minimist/test/dash.js +24 -0
  154. data/node_modules/minimist/test/default_bool.js +20 -0
  155. data/node_modules/minimist/test/dotted.js +16 -0
  156. data/node_modules/minimist/test/long.js +31 -0
  157. data/node_modules/minimist/test/parse.js +318 -0
  158. data/node_modules/minimist/test/parse_modified.js +9 -0
  159. data/node_modules/minimist/test/short.js +67 -0
  160. data/node_modules/minimist/test/whitespace.js +8 -0
  161. data/node_modules/mkdirp/.travis.yml +8 -0
  162. data/node_modules/mkdirp/LICENSE +21 -0
  163. data/node_modules/mkdirp/bin/cmd.js +33 -0
  164. data/node_modules/mkdirp/bin/usage.txt +12 -0
  165. data/node_modules/mkdirp/examples/pow.js +6 -0
  166. data/node_modules/mkdirp/index.js +98 -0
  167. data/node_modules/mkdirp/package.json +93 -0
  168. data/node_modules/mkdirp/readme.markdown +100 -0
  169. data/node_modules/mkdirp/test/chmod.js +41 -0
  170. data/node_modules/mkdirp/test/clobber.js +38 -0
  171. data/node_modules/mkdirp/test/mkdirp.js +28 -0
  172. data/node_modules/mkdirp/test/opts_fs.js +29 -0
  173. data/node_modules/mkdirp/test/opts_fs_sync.js +27 -0
  174. data/node_modules/mkdirp/test/perm.js +32 -0
  175. data/node_modules/mkdirp/test/perm_sync.js +36 -0
  176. data/node_modules/mkdirp/test/race.js +37 -0
  177. data/node_modules/mkdirp/test/rel.js +32 -0
  178. data/node_modules/mkdirp/test/return.js +25 -0
  179. data/node_modules/mkdirp/test/return_sync.js +24 -0
  180. data/node_modules/mkdirp/test/root.js +19 -0
  181. data/node_modules/mkdirp/test/sync.js +32 -0
  182. data/node_modules/mkdirp/test/umask.js +28 -0
  183. data/node_modules/mkdirp/test/umask_sync.js +32 -0
  184. data/node_modules/ms/README.md +51 -0
  185. data/node_modules/ms/index.js +152 -0
  186. data/node_modules/ms/license.md +21 -0
  187. data/node_modules/ms/package.json +109 -0
  188. data/node_modules/once/LICENSE +15 -0
  189. data/node_modules/once/README.md +79 -0
  190. data/node_modules/once/once.js +42 -0
  191. data/node_modules/once/package.json +101 -0
  192. data/node_modules/path-is-absolute/index.js +20 -0
  193. data/node_modules/path-is-absolute/license +21 -0
  194. data/node_modules/path-is-absolute/package.json +111 -0
  195. data/node_modules/path-is-absolute/readme.md +59 -0
  196. data/node_modules/rimraf/LICENSE +15 -0
  197. data/node_modules/rimraf/README.md +101 -0
  198. data/node_modules/rimraf/bin.js +50 -0
  199. data/node_modules/rimraf/package.json +99 -0
  200. data/node_modules/rimraf/rimraf.js +363 -0
  201. data/node_modules/ultron/LICENSE +22 -0
  202. data/node_modules/ultron/index.js +138 -0
  203. data/node_modules/ultron/package.json +112 -0
  204. data/node_modules/wrappy/LICENSE +15 -0
  205. data/node_modules/wrappy/README.md +36 -0
  206. data/node_modules/wrappy/package.json +97 -0
  207. data/node_modules/wrappy/wrappy.js +33 -0
  208. data/node_modules/ws/LICENSE +21 -0
  209. data/node_modules/ws/README.md +259 -0
  210. data/node_modules/ws/SECURITY.md +33 -0
  211. data/node_modules/ws/index.js +15 -0
  212. data/node_modules/ws/lib/BufferUtil.fallback.js +56 -0
  213. data/node_modules/ws/lib/BufferUtil.js +15 -0
  214. data/node_modules/ws/lib/ErrorCodes.js +28 -0
  215. data/node_modules/ws/lib/EventTarget.js +158 -0
  216. data/node_modules/ws/lib/Extensions.js +69 -0
  217. data/node_modules/ws/lib/PerMessageDeflate.js +339 -0
  218. data/node_modules/ws/lib/Receiver.js +520 -0
  219. data/node_modules/ws/lib/Sender.js +438 -0
  220. data/node_modules/ws/lib/Validation.fallback.js +9 -0
  221. data/node_modules/ws/lib/Validation.js +17 -0
  222. data/node_modules/ws/lib/WebSocket.js +705 -0
  223. data/node_modules/ws/lib/WebSocketServer.js +336 -0
  224. data/node_modules/ws/package.json +122 -0
  225. data/package.json +26 -0
  226. data/samples/sample.html +13 -0
  227. data/script/rasterize.js +18 -0
  228. metadata +325 -0
@@ -0,0 +1,32 @@
1
+ const EventEmitter = require('events');
2
+
3
+ // wrapper around the Node.js ws module
4
+ // for use in browsers
5
+ class WebSocketWrapper extends EventEmitter {
6
+ constructor(url) {
7
+ super();
8
+ this._ws = new WebSocket(url);
9
+ this._ws.onopen = () => {
10
+ this.emit('open');
11
+ };
12
+ this._ws.onclose = () => {
13
+ this.emit('close');
14
+ };
15
+ this._ws.onmessage = (event) => {
16
+ this.emit('message', event.data);
17
+ };
18
+ this._ws.onerror = () => {
19
+ this.emit('error', new Error('WebSocket error'));
20
+ };
21
+ }
22
+
23
+ close() {
24
+ this._ws.close();
25
+ }
26
+
27
+ send(data) {
28
+ this._ws.send(data);
29
+ }
30
+ }
31
+
32
+ module.exports = WebSocketWrapper;
@@ -0,0 +1,128 @@
1
+ {
2
+ "_args": [
3
+ [
4
+ {
5
+ "raw": "chrome-remote-interface@^0.24.1",
6
+ "scope": null,
7
+ "escapedName": "chrome-remote-interface",
8
+ "name": "chrome-remote-interface",
9
+ "rawSpec": "^0.24.1",
10
+ "spec": ">=0.24.1 <0.25.0",
11
+ "type": "range"
12
+ },
13
+ "/Users/tomascelizna/Devel/dragonfly_chrome_headless/node_modules/html-pdf-chrome"
14
+ ]
15
+ ],
16
+ "_from": "chrome-remote-interface@>=0.24.1 <0.25.0",
17
+ "_id": "chrome-remote-interface@0.24.2",
18
+ "_inCache": true,
19
+ "_location": "/chrome-remote-interface",
20
+ "_nodeVersion": "8.1.4",
21
+ "_npmOperationalInternal": {
22
+ "host": "s3://npm-registry-packages",
23
+ "tmp": "tmp/chrome-remote-interface-0.24.2.tgz_1500028321222_0.3025570046156645"
24
+ },
25
+ "_npmUser": {
26
+ "name": "cyrus-and",
27
+ "email": "cyrus.and@gmail.com"
28
+ },
29
+ "_npmVersion": "5.0.3",
30
+ "_phantomChildren": {},
31
+ "_requested": {
32
+ "raw": "chrome-remote-interface@^0.24.1",
33
+ "scope": null,
34
+ "escapedName": "chrome-remote-interface",
35
+ "name": "chrome-remote-interface",
36
+ "rawSpec": "^0.24.1",
37
+ "spec": ">=0.24.1 <0.25.0",
38
+ "type": "range"
39
+ },
40
+ "_requiredBy": [
41
+ "/html-pdf-chrome"
42
+ ],
43
+ "_resolved": "https://registry.npmjs.org/chrome-remote-interface/-/chrome-remote-interface-0.24.2.tgz",
44
+ "_shasum": "43a05440a1fa60b73769e72f3e7892ac11d66eba",
45
+ "_shrinkwrap": null,
46
+ "_spec": "chrome-remote-interface@^0.24.1",
47
+ "_where": "/Users/tomascelizna/Devel/dragonfly_chrome_headless/node_modules/html-pdf-chrome",
48
+ "author": {
49
+ "name": "Andrea Cardaci",
50
+ "email": "cyrus.and@gmail.com"
51
+ },
52
+ "bin": {
53
+ "chrome-remote-interface": "./bin/client.js"
54
+ },
55
+ "browser": "chrome-remote-interface.js",
56
+ "bugs": {
57
+ "url": "http://github.com/cyrus-and/chrome-remote-interface/issues"
58
+ },
59
+ "contributors": [
60
+ {
61
+ "name": "Andrey Sidorov",
62
+ "email": "sidoares@yandex.ru"
63
+ },
64
+ {
65
+ "name": "Greg Cochard",
66
+ "email": "greg@gregcochard.com"
67
+ }
68
+ ],
69
+ "dependencies": {
70
+ "commander": "2.1.x",
71
+ "ws": "2.0.x"
72
+ },
73
+ "description": "Chrome Debugging Protocol interface",
74
+ "devDependencies": {
75
+ "babel-core": "^6.18.2",
76
+ "babel-loader": "^6.2.8",
77
+ "babel-preset-es2015": "^6.18.0",
78
+ "eslint": "3.12.x",
79
+ "json-loader": "^0.5.4",
80
+ "mocha": "3.1.x",
81
+ "webpack": "^1.13.3"
82
+ },
83
+ "directories": {},
84
+ "dist": {
85
+ "integrity": "sha512-KmG2wHqlnTEPwdmc0baW4qpSEldN6zAHrkwCquo6wsFnOFkmvYZRv4Kbko7GylFyrLjbyUQzUCMwfxNIftIhvA==",
86
+ "shasum": "43a05440a1fa60b73769e72f3e7892ac11d66eba",
87
+ "tarball": "https://registry.npmjs.org/chrome-remote-interface/-/chrome-remote-interface-0.24.2.tgz"
88
+ },
89
+ "engines": {
90
+ "node": ">=4"
91
+ },
92
+ "files": [
93
+ "lib",
94
+ "bin",
95
+ "index.js",
96
+ "chrome-remote-interface.js",
97
+ "webpack.config.js"
98
+ ],
99
+ "gitHead": "217b18986be0f836dee40cfb68401991dfa35634",
100
+ "homepage": "https://github.com/cyrus-and/chrome-remote-interface",
101
+ "keywords": [
102
+ "chrome",
103
+ "debug",
104
+ "protocol",
105
+ "remote",
106
+ "interface"
107
+ ],
108
+ "license": "MIT",
109
+ "maintainers": [
110
+ {
111
+ "name": "cyrus-and",
112
+ "email": "cyrus.and@gmail.com"
113
+ }
114
+ ],
115
+ "name": "chrome-remote-interface",
116
+ "optionalDependencies": {},
117
+ "readme": "ERROR: No README data found!",
118
+ "repository": {
119
+ "type": "git",
120
+ "url": "git://github.com/cyrus-and/chrome-remote-interface.git"
121
+ },
122
+ "scripts": {
123
+ "prepublish": "webpack",
124
+ "test": "./scripts/run-tests.sh",
125
+ "webpack": "webpack"
126
+ },
127
+ "version": "0.24.2"
128
+ }
@@ -0,0 +1,55 @@
1
+ 'use strict';
2
+
3
+ const webpack = require('webpack');
4
+
5
+ function criWrapper(_, options, callback) {
6
+ window.criRequest(options, callback);
7
+ }
8
+
9
+ const webpackConfig = {
10
+ resolve: {
11
+ alias: {
12
+ 'ws': './websocket-wrapper.js'
13
+ }
14
+ },
15
+ externals: [
16
+ {
17
+ './external-request.js': `var (${criWrapper})`
18
+ }
19
+ ],
20
+ module: {
21
+ loaders: [
22
+ {
23
+ test: /\.js$/,
24
+ exclude: /node_modules/,
25
+ loader: 'babel-loader'
26
+ },
27
+ {
28
+ test: /\.json$/,
29
+ loader: 'json'
30
+ }
31
+ ]
32
+ },
33
+ plugins: [
34
+ ],
35
+ entry: './index.js',
36
+ output: {
37
+ libraryTarget: process.env.TARGET || 'commonjs2',
38
+ library: 'CDP',
39
+ filename: 'chrome-remote-interface.js'
40
+ }
41
+ };
42
+
43
+ if (process.env.DEBUG !== 'true') {
44
+ webpackConfig.plugins.push(new webpack.optimize.UglifyJsPlugin({
45
+ mangle: true,
46
+ compress: {
47
+ warnings: false
48
+ },
49
+ output: {
50
+ comments: false
51
+ }
52
+ }));
53
+ }
54
+
55
+ module.exports = webpackConfig;
@@ -0,0 +1,195 @@
1
+ # Commander.js
2
+
3
+ The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/visionmedia/commander).
4
+
5
+ [![Build Status](https://secure.travis-ci.org/visionmedia/commander.js.png)](http://travis-ci.org/visionmedia/commander.js)
6
+
7
+ ## Installation
8
+
9
+ $ npm install commander
10
+
11
+ ## Option parsing
12
+
13
+ Options with commander are defined with the `.option()` method, also serving as documentation for the options. The example below parses args and options from `process.argv`, leaving remaining args as the `program.args` array which were not consumed by options.
14
+
15
+ ```js
16
+ #!/usr/bin/env node
17
+
18
+ /**
19
+ * Module dependencies.
20
+ */
21
+
22
+ var program = require('commander');
23
+
24
+ program
25
+ .version('0.0.1')
26
+ .option('-p, --peppers', 'Add peppers')
27
+ .option('-P, --pineapple', 'Add pineapple')
28
+ .option('-b, --bbq', 'Add bbq sauce')
29
+ .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble')
30
+ .parse(process.argv);
31
+
32
+ console.log('you ordered a pizza with:');
33
+ if (program.peppers) console.log(' - peppers');
34
+ if (program.pineapple) console.log(' - pineapple');
35
+ if (program.bbq) console.log(' - bbq');
36
+ console.log(' - %s cheese', program.cheese);
37
+ ```
38
+
39
+ Short flags may be passed as a single arg, for example `-abc` is equivalent to `-a -b -c`. Multi-word options such as "--template-engine" are camel-cased, becoming `program.templateEngine` etc.
40
+
41
+ ## Automated --help
42
+
43
+ The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free:
44
+
45
+ ```
46
+ $ ./examples/pizza --help
47
+
48
+ Usage: pizza [options]
49
+
50
+ Options:
51
+
52
+ -V, --version output the version number
53
+ -p, --peppers Add peppers
54
+ -P, --pineapple Add pineapple
55
+ -b, --bbq Add bbq sauce
56
+ -c, --cheese <type> Add the specified type of cheese [marble]
57
+ -h, --help output usage information
58
+
59
+ ```
60
+
61
+ ## Coercion
62
+
63
+ ```js
64
+ function range(val) {
65
+ return val.split('..').map(Number);
66
+ }
67
+
68
+ function list(val) {
69
+ return val.split(',');
70
+ }
71
+
72
+ program
73
+ .version('0.0.1')
74
+ .usage('[options] <file ...>')
75
+ .option('-i, --integer <n>', 'An integer argument', parseInt)
76
+ .option('-f, --float <n>', 'A float argument', parseFloat)
77
+ .option('-r, --range <a>..<b>', 'A range', range)
78
+ .option('-l, --list <items>', 'A list', list)
79
+ .option('-o, --optional [value]', 'An optional value')
80
+ .parse(process.argv);
81
+
82
+ console.log(' int: %j', program.integer);
83
+ console.log(' float: %j', program.float);
84
+ console.log(' optional: %j', program.optional);
85
+ program.range = program.range || [];
86
+ console.log(' range: %j..%j', program.range[0], program.range[1]);
87
+ console.log(' list: %j', program.list);
88
+ console.log(' args: %j', program.args);
89
+ ```
90
+
91
+ ## Custom help
92
+
93
+ You can display arbitrary `-h, --help` information
94
+ by listening for "--help". Commander will automatically
95
+ exit once you are done so that the remainder of your program
96
+ does not execute causing undesired behaviours, for example
97
+ in the following executable "stuff" will not output when
98
+ `--help` is used.
99
+
100
+ ```js
101
+ #!/usr/bin/env node
102
+
103
+ /**
104
+ * Module dependencies.
105
+ */
106
+
107
+ var program = require('../');
108
+
109
+ function list(val) {
110
+ return val.split(',').map(Number);
111
+ }
112
+
113
+ program
114
+ .version('0.0.1')
115
+ .option('-f, --foo', 'enable some foo')
116
+ .option('-b, --bar', 'enable some bar')
117
+ .option('-B, --baz', 'enable some baz');
118
+
119
+ // must be before .parse() since
120
+ // node's emit() is immediate
121
+
122
+ program.on('--help', function(){
123
+ console.log(' Examples:');
124
+ console.log('');
125
+ console.log(' $ custom-help --help');
126
+ console.log(' $ custom-help -h');
127
+ console.log('');
128
+ });
129
+
130
+ program.parse(process.argv);
131
+
132
+ console.log('stuff');
133
+ ```
134
+
135
+ yielding the following help output:
136
+
137
+ ```
138
+
139
+ Usage: custom-help [options]
140
+
141
+ Options:
142
+
143
+ -h, --help output usage information
144
+ -V, --version output the version number
145
+ -f, --foo enable some foo
146
+ -b, --bar enable some bar
147
+ -B, --baz enable some baz
148
+
149
+ Examples:
150
+
151
+ $ custom-help --help
152
+ $ custom-help -h
153
+
154
+ ```
155
+
156
+ ## .outputHelp()
157
+
158
+ Output help information without exiting.
159
+
160
+ ## .help()
161
+
162
+ Output help information and exit immediately.
163
+
164
+ ## Links
165
+
166
+ - [API documentation](http://visionmedia.github.com/commander.js/)
167
+ - [ascii tables](https://github.com/LearnBoost/cli-table)
168
+ - [progress bars](https://github.com/visionmedia/node-progress)
169
+ - [more progress bars](https://github.com/substack/node-multimeter)
170
+ - [examples](https://github.com/visionmedia/commander.js/tree/master/examples)
171
+
172
+ ## License
173
+
174
+ (The MIT License)
175
+
176
+ Copyright (c) 2011 TJ Holowaychuk &lt;tj@vision-media.ca&gt;
177
+
178
+ Permission is hereby granted, free of charge, to any person obtaining
179
+ a copy of this software and associated documentation files (the
180
+ 'Software'), to deal in the Software without restriction, including
181
+ without limitation the rights to use, copy, modify, merge, publish,
182
+ distribute, sublicense, and/or sell copies of the Software, and to
183
+ permit persons to whom the Software is furnished to do so, subject to
184
+ the following conditions:
185
+
186
+ The above copyright notice and this permission notice shall be
187
+ included in all copies or substantial portions of the Software.
188
+
189
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
190
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
191
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
192
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
193
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
194
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
195
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,851 @@
1
+
2
+ /**
3
+ * Module dependencies.
4
+ */
5
+
6
+ var EventEmitter = require('events').EventEmitter;
7
+ var spawn = require('child_process').spawn;
8
+ var fs = require('fs');
9
+ var exists = fs.existsSync;
10
+ var path = require('path');
11
+ var dirname = path.dirname;
12
+ var basename = path.basename;
13
+
14
+ /**
15
+ * Expose the root command.
16
+ */
17
+
18
+ exports = module.exports = new Command;
19
+
20
+ /**
21
+ * Expose `Command`.
22
+ */
23
+
24
+ exports.Command = Command;
25
+
26
+ /**
27
+ * Expose `Option`.
28
+ */
29
+
30
+ exports.Option = Option;
31
+
32
+ /**
33
+ * Initialize a new `Option` with the given `flags` and `description`.
34
+ *
35
+ * @param {String} flags
36
+ * @param {String} description
37
+ * @api public
38
+ */
39
+
40
+ function Option(flags, description) {
41
+ this.flags = flags;
42
+ this.required = ~flags.indexOf('<');
43
+ this.optional = ~flags.indexOf('[');
44
+ this.bool = !~flags.indexOf('-no-');
45
+ flags = flags.split(/[ ,|]+/);
46
+ if (flags.length > 1 && !/^[[<]/.test(flags[1])) this.short = flags.shift();
47
+ this.long = flags.shift();
48
+ this.description = description || '';
49
+ }
50
+
51
+ /**
52
+ * Return option name.
53
+ *
54
+ * @return {String}
55
+ * @api private
56
+ */
57
+
58
+ Option.prototype.name = function(){
59
+ return this.long
60
+ .replace('--', '')
61
+ .replace('no-', '');
62
+ };
63
+
64
+ /**
65
+ * Check if `arg` matches the short or long flag.
66
+ *
67
+ * @param {String} arg
68
+ * @return {Boolean}
69
+ * @api private
70
+ */
71
+
72
+ Option.prototype.is = function(arg){
73
+ return arg == this.short
74
+ || arg == this.long;
75
+ };
76
+
77
+ /**
78
+ * Initialize a new `Command`.
79
+ *
80
+ * @param {String} name
81
+ * @api public
82
+ */
83
+
84
+ function Command(name) {
85
+ this.commands = [];
86
+ this.options = [];
87
+ this._execs = [];
88
+ this._args = [];
89
+ this._name = name;
90
+ }
91
+
92
+ /**
93
+ * Inherit from `EventEmitter.prototype`.
94
+ */
95
+
96
+ Command.prototype.__proto__ = EventEmitter.prototype;
97
+
98
+ /**
99
+ * Add command `name`.
100
+ *
101
+ * The `.action()` callback is invoked when the
102
+ * command `name` is specified via __ARGV__,
103
+ * and the remaining arguments are applied to the
104
+ * function for access.
105
+ *
106
+ * When the `name` is "*" an un-matched command
107
+ * will be passed as the first arg, followed by
108
+ * the rest of __ARGV__ remaining.
109
+ *
110
+ * Examples:
111
+ *
112
+ * program
113
+ * .version('0.0.1')
114
+ * .option('-C, --chdir <path>', 'change the working directory')
115
+ * .option('-c, --config <path>', 'set config path. defaults to ./deploy.conf')
116
+ * .option('-T, --no-tests', 'ignore test hook')
117
+ *
118
+ * program
119
+ * .command('setup')
120
+ * .description('run remote setup commands')
121
+ * .action(function(){
122
+ * console.log('setup');
123
+ * });
124
+ *
125
+ * program
126
+ * .command('exec <cmd>')
127
+ * .description('run the given remote command')
128
+ * .action(function(cmd){
129
+ * console.log('exec "%s"', cmd);
130
+ * });
131
+ *
132
+ * program
133
+ * .command('*')
134
+ * .description('deploy the given env')
135
+ * .action(function(env){
136
+ * console.log('deploying "%s"', env);
137
+ * });
138
+ *
139
+ * program.parse(process.argv);
140
+ *
141
+ * @param {String} name
142
+ * @param {String} [desc]
143
+ * @return {Command} the new command
144
+ * @api public
145
+ */
146
+
147
+ Command.prototype.command = function(name, desc){
148
+ var args = name.split(/ +/);
149
+ var cmd = new Command(args.shift());
150
+ if (desc) cmd.description(desc);
151
+ if (desc) this.executables = true;
152
+ if (desc) this._execs[cmd._name] = true;
153
+ this.commands.push(cmd);
154
+ cmd.parseExpectedArgs(args);
155
+ cmd.parent = this;
156
+ if (desc) return this;
157
+ return cmd;
158
+ };
159
+
160
+ /**
161
+ * Add an implicit `help [cmd]` subcommand
162
+ * which invokes `--help` for the given command.
163
+ *
164
+ * @api private
165
+ */
166
+
167
+ Command.prototype.addImplicitHelpCommand = function() {
168
+ this.command('help [cmd]', 'display help for [cmd]');
169
+ };
170
+
171
+ /**
172
+ * Parse expected `args`.
173
+ *
174
+ * For example `["[type]"]` becomes `[{ required: false, name: 'type' }]`.
175
+ *
176
+ * @param {Array} args
177
+ * @return {Command} for chaining
178
+ * @api public
179
+ */
180
+
181
+ Command.prototype.parseExpectedArgs = function(args){
182
+ if (!args.length) return;
183
+ var self = this;
184
+ args.forEach(function(arg){
185
+ switch (arg[0]) {
186
+ case '<':
187
+ self._args.push({ required: true, name: arg.slice(1, -1) });
188
+ break;
189
+ case '[':
190
+ self._args.push({ required: false, name: arg.slice(1, -1) });
191
+ break;
192
+ }
193
+ });
194
+ return this;
195
+ };
196
+
197
+ /**
198
+ * Register callback `fn` for the command.
199
+ *
200
+ * Examples:
201
+ *
202
+ * program
203
+ * .command('help')
204
+ * .description('display verbose help')
205
+ * .action(function(){
206
+ * // output help here
207
+ * });
208
+ *
209
+ * @param {Function} fn
210
+ * @return {Command} for chaining
211
+ * @api public
212
+ */
213
+
214
+ Command.prototype.action = function(fn){
215
+ var self = this;
216
+ this.parent.on(this._name, function(args, unknown){
217
+ // Parse any so-far unknown options
218
+ unknown = unknown || [];
219
+ var parsed = self.parseOptions(unknown);
220
+
221
+ // Output help if necessary
222
+ outputHelpIfNecessary(self, parsed.unknown);
223
+
224
+ // If there are still any unknown options, then we simply
225
+ // die, unless someone asked for help, in which case we give it
226
+ // to them, and then we die.
227
+ if (parsed.unknown.length > 0) {
228
+ self.unknownOption(parsed.unknown[0]);
229
+ }
230
+
231
+ // Leftover arguments need to be pushed back. Fixes issue #56
232
+ if (parsed.args.length) args = parsed.args.concat(args);
233
+
234
+ self._args.forEach(function(arg, i){
235
+ if (arg.required && null == args[i]) {
236
+ self.missingArgument(arg.name);
237
+ }
238
+ });
239
+
240
+ // Always append ourselves to the end of the arguments,
241
+ // to make sure we match the number of arguments the user
242
+ // expects
243
+ if (self._args.length) {
244
+ args[self._args.length] = self;
245
+ } else {
246
+ args.push(self);
247
+ }
248
+
249
+ fn.apply(this, args);
250
+ });
251
+ return this;
252
+ };
253
+
254
+ /**
255
+ * Define option with `flags`, `description` and optional
256
+ * coercion `fn`.
257
+ *
258
+ * The `flags` string should contain both the short and long flags,
259
+ * separated by comma, a pipe or space. The following are all valid
260
+ * all will output this way when `--help` is used.
261
+ *
262
+ * "-p, --pepper"
263
+ * "-p|--pepper"
264
+ * "-p --pepper"
265
+ *
266
+ * Examples:
267
+ *
268
+ * // simple boolean defaulting to false
269
+ * program.option('-p, --pepper', 'add pepper');
270
+ *
271
+ * --pepper
272
+ * program.pepper
273
+ * // => Boolean
274
+ *
275
+ * // simple boolean defaulting to false
276
+ * program.option('-C, --no-cheese', 'remove cheese');
277
+ *
278
+ * program.cheese
279
+ * // => true
280
+ *
281
+ * --no-cheese
282
+ * program.cheese
283
+ * // => true
284
+ *
285
+ * // required argument
286
+ * program.option('-C, --chdir <path>', 'change the working directory');
287
+ *
288
+ * --chdir /tmp
289
+ * program.chdir
290
+ * // => "/tmp"
291
+ *
292
+ * // optional argument
293
+ * program.option('-c, --cheese [type]', 'add cheese [marble]');
294
+ *
295
+ * @param {String} flags
296
+ * @param {String} description
297
+ * @param {Function|Mixed} fn or default
298
+ * @param {Mixed} defaultValue
299
+ * @return {Command} for chaining
300
+ * @api public
301
+ */
302
+
303
+ Command.prototype.option = function(flags, description, fn, defaultValue){
304
+ var self = this
305
+ , option = new Option(flags, description)
306
+ , oname = option.name()
307
+ , name = camelcase(oname);
308
+
309
+ // default as 3rd arg
310
+ if ('function' != typeof fn) defaultValue = fn, fn = null;
311
+
312
+ // preassign default value only for --no-*, [optional], or <required>
313
+ if (false == option.bool || option.optional || option.required) {
314
+ // when --no-* we make sure default is true
315
+ if (false == option.bool) defaultValue = true;
316
+ // preassign only if we have a default
317
+ if (undefined !== defaultValue) self[name] = defaultValue;
318
+ }
319
+
320
+ // register the option
321
+ this.options.push(option);
322
+
323
+ // when it's passed assign the value
324
+ // and conditionally invoke the callback
325
+ this.on(oname, function(val){
326
+ // coercion
327
+ if (null != val && fn) val = fn(val);
328
+
329
+ // unassigned or bool
330
+ if ('boolean' == typeof self[name] || 'undefined' == typeof self[name]) {
331
+ // if no value, bool true, and we have a default, then use it!
332
+ if (null == val) {
333
+ self[name] = option.bool
334
+ ? defaultValue || true
335
+ : false;
336
+ } else {
337
+ self[name] = val;
338
+ }
339
+ } else if (null !== val) {
340
+ // reassign
341
+ self[name] = val;
342
+ }
343
+ });
344
+
345
+ return this;
346
+ };
347
+
348
+ /**
349
+ * Parse `argv`, settings options and invoking commands when defined.
350
+ *
351
+ * @param {Array} argv
352
+ * @return {Command} for chaining
353
+ * @api public
354
+ */
355
+
356
+ Command.prototype.parse = function(argv){
357
+ // implicit help
358
+ if (this.executables) this.addImplicitHelpCommand();
359
+
360
+ // store raw args
361
+ this.rawArgs = argv;
362
+
363
+ // guess name
364
+ this._name = this._name || basename(argv[1]);
365
+
366
+ // process argv
367
+ var parsed = this.parseOptions(this.normalize(argv.slice(2)));
368
+ var args = this.args = parsed.args;
369
+
370
+ var result = this.parseArgs(this.args, parsed.unknown);
371
+
372
+ // executable sub-commands
373
+ var name = result.args[0];
374
+ if (this._execs[name]) return this.executeSubCommand(argv, args, parsed.unknown);
375
+
376
+ return result;
377
+ };
378
+
379
+ /**
380
+ * Execute a sub-command executable.
381
+ *
382
+ * @param {Array} argv
383
+ * @param {Array} args
384
+ * @param {Array} unknown
385
+ * @api private
386
+ */
387
+
388
+ Command.prototype.executeSubCommand = function(argv, args, unknown) {
389
+ args = args.concat(unknown);
390
+
391
+ if (!args.length) this.help();
392
+ if ('help' == args[0] && 1 == args.length) this.help();
393
+
394
+ // <cmd> --help
395
+ if ('help' == args[0]) {
396
+ args[0] = args[1];
397
+ args[1] = '--help';
398
+ }
399
+
400
+ // executable
401
+ var dir = dirname(argv[1]);
402
+ var bin = basename(argv[1]) + '-' + args[0];
403
+
404
+ // check for ./<bin> first
405
+ var local = path.join(dir, bin);
406
+
407
+ // run it
408
+ args = args.slice(1);
409
+ var proc = spawn(local, args, { stdio: 'inherit', customFds: [0, 1, 2] });
410
+ proc.on('error', function(err){
411
+ if (err.code == "ENOENT") {
412
+ console.error('\n %s(1) does not exist, try --help\n', bin);
413
+ } else if (err.code == "EACCES") {
414
+ console.error('\n %s(1) not executable. try chmod or run with root\n', bin);
415
+ }
416
+ });
417
+
418
+ this.runningCommand = proc;
419
+ };
420
+
421
+ /**
422
+ * Normalize `args`, splitting joined short flags. For example
423
+ * the arg "-abc" is equivalent to "-a -b -c".
424
+ * This also normalizes equal sign and splits "--abc=def" into "--abc def".
425
+ *
426
+ * @param {Array} args
427
+ * @return {Array}
428
+ * @api private
429
+ */
430
+
431
+ Command.prototype.normalize = function(args){
432
+ var ret = []
433
+ , arg
434
+ , lastOpt
435
+ , index;
436
+
437
+ for (var i = 0, len = args.length; i < len; ++i) {
438
+ arg = args[i];
439
+ i > 0 && (lastOpt = this.optionFor(args[i-1]));
440
+
441
+ if (lastOpt && lastOpt.required) {
442
+ ret.push(arg);
443
+ } else if (arg.length > 1 && '-' == arg[0] && '-' != arg[1]) {
444
+ arg.slice(1).split('').forEach(function(c){
445
+ ret.push('-' + c);
446
+ });
447
+ } else if (/^--/.test(arg) && ~(index = arg.indexOf('='))) {
448
+ ret.push(arg.slice(0, index), arg.slice(index + 1));
449
+ } else {
450
+ ret.push(arg);
451
+ }
452
+ }
453
+
454
+ return ret;
455
+ };
456
+
457
+ /**
458
+ * Parse command `args`.
459
+ *
460
+ * When listener(s) are available those
461
+ * callbacks are invoked, otherwise the "*"
462
+ * event is emitted and those actions are invoked.
463
+ *
464
+ * @param {Array} args
465
+ * @return {Command} for chaining
466
+ * @api private
467
+ */
468
+
469
+ Command.prototype.parseArgs = function(args, unknown){
470
+ var cmds = this.commands
471
+ , len = cmds.length
472
+ , name;
473
+
474
+ if (args.length) {
475
+ name = args[0];
476
+ if (this.listeners(name).length) {
477
+ this.emit(args.shift(), args, unknown);
478
+ } else {
479
+ this.emit('*', args);
480
+ }
481
+ } else {
482
+ outputHelpIfNecessary(this, unknown);
483
+
484
+ // If there were no args and we have unknown options,
485
+ // then they are extraneous and we need to error.
486
+ if (unknown.length > 0) {
487
+ this.unknownOption(unknown[0]);
488
+ }
489
+ }
490
+
491
+ return this;
492
+ };
493
+
494
+ /**
495
+ * Return an option matching `arg` if any.
496
+ *
497
+ * @param {String} arg
498
+ * @return {Option}
499
+ * @api private
500
+ */
501
+
502
+ Command.prototype.optionFor = function(arg){
503
+ for (var i = 0, len = this.options.length; i < len; ++i) {
504
+ if (this.options[i].is(arg)) {
505
+ return this.options[i];
506
+ }
507
+ }
508
+ };
509
+
510
+ /**
511
+ * Parse options from `argv` returning `argv`
512
+ * void of these options.
513
+ *
514
+ * @param {Array} argv
515
+ * @return {Array}
516
+ * @api public
517
+ */
518
+
519
+ Command.prototype.parseOptions = function(argv){
520
+ var args = []
521
+ , len = argv.length
522
+ , literal
523
+ , option
524
+ , arg;
525
+
526
+ var unknownOptions = [];
527
+
528
+ // parse options
529
+ for (var i = 0; i < len; ++i) {
530
+ arg = argv[i];
531
+
532
+ // literal args after --
533
+ if ('--' == arg) {
534
+ literal = true;
535
+ continue;
536
+ }
537
+
538
+ if (literal) {
539
+ args.push(arg);
540
+ continue;
541
+ }
542
+
543
+ // find matching Option
544
+ option = this.optionFor(arg);
545
+
546
+ // option is defined
547
+ if (option) {
548
+ // requires arg
549
+ if (option.required) {
550
+ arg = argv[++i];
551
+ if (null == arg) return this.optionMissingArgument(option);
552
+ this.emit(option.name(), arg);
553
+ // optional arg
554
+ } else if (option.optional) {
555
+ arg = argv[i+1];
556
+ if (null == arg || ('-' == arg[0] && '-' != arg)) {
557
+ arg = null;
558
+ } else {
559
+ ++i;
560
+ }
561
+ this.emit(option.name(), arg);
562
+ // bool
563
+ } else {
564
+ this.emit(option.name());
565
+ }
566
+ continue;
567
+ }
568
+
569
+ // looks like an option
570
+ if (arg.length > 1 && '-' == arg[0]) {
571
+ unknownOptions.push(arg);
572
+
573
+ // If the next argument looks like it might be
574
+ // an argument for this option, we pass it on.
575
+ // If it isn't, then it'll simply be ignored
576
+ if (argv[i+1] && '-' != argv[i+1][0]) {
577
+ unknownOptions.push(argv[++i]);
578
+ }
579
+ continue;
580
+ }
581
+
582
+ // arg
583
+ args.push(arg);
584
+ }
585
+
586
+ return { args: args, unknown: unknownOptions };
587
+ };
588
+
589
+ /**
590
+ * Argument `name` is missing.
591
+ *
592
+ * @param {String} name
593
+ * @api private
594
+ */
595
+
596
+ Command.prototype.missingArgument = function(name){
597
+ console.error();
598
+ console.error(" error: missing required argument `%s'", name);
599
+ console.error();
600
+ process.exit(1);
601
+ };
602
+
603
+ /**
604
+ * `Option` is missing an argument, but received `flag` or nothing.
605
+ *
606
+ * @param {String} option
607
+ * @param {String} flag
608
+ * @api private
609
+ */
610
+
611
+ Command.prototype.optionMissingArgument = function(option, flag){
612
+ console.error();
613
+ if (flag) {
614
+ console.error(" error: option `%s' argument missing, got `%s'", option.flags, flag);
615
+ } else {
616
+ console.error(" error: option `%s' argument missing", option.flags);
617
+ }
618
+ console.error();
619
+ process.exit(1);
620
+ };
621
+
622
+ /**
623
+ * Unknown option `flag`.
624
+ *
625
+ * @param {String} flag
626
+ * @api private
627
+ */
628
+
629
+ Command.prototype.unknownOption = function(flag){
630
+ console.error();
631
+ console.error(" error: unknown option `%s'", flag);
632
+ console.error();
633
+ process.exit(1);
634
+ };
635
+
636
+
637
+ /**
638
+ * Set the program version to `str`.
639
+ *
640
+ * This method auto-registers the "-V, --version" flag
641
+ * which will print the version number when passed.
642
+ *
643
+ * @param {String} str
644
+ * @param {String} flags
645
+ * @return {Command} for chaining
646
+ * @api public
647
+ */
648
+
649
+ Command.prototype.version = function(str, flags){
650
+ if (0 == arguments.length) return this._version;
651
+ this._version = str;
652
+ flags = flags || '-V, --version';
653
+ this.option(flags, 'output the version number');
654
+ this.on('version', function(){
655
+ console.log(str);
656
+ process.exit(0);
657
+ });
658
+ return this;
659
+ };
660
+
661
+ /**
662
+ * Set the description `str`.
663
+ *
664
+ * @param {String} str
665
+ * @return {String|Command}
666
+ * @api public
667
+ */
668
+
669
+ Command.prototype.description = function(str){
670
+ if (0 == arguments.length) return this._description;
671
+ this._description = str;
672
+ return this;
673
+ };
674
+
675
+ /**
676
+ * Set / get the command usage `str`.
677
+ *
678
+ * @param {String} str
679
+ * @return {String|Command}
680
+ * @api public
681
+ */
682
+
683
+ Command.prototype.usage = function(str){
684
+ var args = this._args.map(function(arg){
685
+ return arg.required
686
+ ? '<' + arg.name + '>'
687
+ : '[' + arg.name + ']';
688
+ });
689
+
690
+ var usage = '[options'
691
+ + (this.commands.length ? '] [command' : '')
692
+ + ']'
693
+ + (this._args.length ? ' ' + args : '');
694
+
695
+ if (0 == arguments.length) return this._usage || usage;
696
+ this._usage = str;
697
+
698
+ return this;
699
+ };
700
+
701
+ /**
702
+ * Return the largest option length.
703
+ *
704
+ * @return {Number}
705
+ * @api private
706
+ */
707
+
708
+ Command.prototype.largestOptionLength = function(){
709
+ return this.options.reduce(function(max, option){
710
+ return Math.max(max, option.flags.length);
711
+ }, 0);
712
+ };
713
+
714
+ /**
715
+ * Return help for options.
716
+ *
717
+ * @return {String}
718
+ * @api private
719
+ */
720
+
721
+ Command.prototype.optionHelp = function(){
722
+ var width = this.largestOptionLength();
723
+
724
+ // Prepend the help information
725
+ return [pad('-h, --help', width) + ' ' + 'output usage information']
726
+ .concat(this.options.map(function(option){
727
+ return pad(option.flags, width)
728
+ + ' ' + option.description;
729
+ }))
730
+ .join('\n');
731
+ };
732
+
733
+ /**
734
+ * Return command help documentation.
735
+ *
736
+ * @return {String}
737
+ * @api private
738
+ */
739
+
740
+ Command.prototype.commandHelp = function(){
741
+ if (!this.commands.length) return '';
742
+ return [
743
+ ''
744
+ , ' Commands:'
745
+ , ''
746
+ , this.commands.map(function(cmd){
747
+ var args = cmd._args.map(function(arg){
748
+ return arg.required
749
+ ? '<' + arg.name + '>'
750
+ : '[' + arg.name + ']';
751
+ }).join(' ');
752
+
753
+ return pad(cmd._name
754
+ + (cmd.options.length
755
+ ? ' [options]'
756
+ : '') + ' ' + args, 22)
757
+ + (cmd.description()
758
+ ? ' ' + cmd.description()
759
+ : '');
760
+ }).join('\n').replace(/^/gm, ' ')
761
+ , ''
762
+ ].join('\n');
763
+ };
764
+
765
+ /**
766
+ * Return program help documentation.
767
+ *
768
+ * @return {String}
769
+ * @api private
770
+ */
771
+
772
+ Command.prototype.helpInformation = function(){
773
+ return [
774
+ ''
775
+ , ' Usage: ' + this._name + ' ' + this.usage()
776
+ , '' + this.commandHelp()
777
+ , ' Options:'
778
+ , ''
779
+ , '' + this.optionHelp().replace(/^/gm, ' ')
780
+ , ''
781
+ , ''
782
+ ].join('\n');
783
+ };
784
+
785
+ /**
786
+ * Output help information for this command
787
+ *
788
+ * @api public
789
+ */
790
+
791
+ Command.prototype.outputHelp = function(){
792
+ process.stdout.write(this.helpInformation());
793
+ this.emit('--help');
794
+ };
795
+
796
+ /**
797
+ * Output help information and exit.
798
+ *
799
+ * @api public
800
+ */
801
+
802
+ Command.prototype.help = function(){
803
+ this.outputHelp();
804
+ process.exit();
805
+ };
806
+
807
+ /**
808
+ * Camel-case the given `flag`
809
+ *
810
+ * @param {String} flag
811
+ * @return {String}
812
+ * @api private
813
+ */
814
+
815
+ function camelcase(flag) {
816
+ return flag.split('-').reduce(function(str, word){
817
+ return str + word[0].toUpperCase() + word.slice(1);
818
+ });
819
+ }
820
+
821
+ /**
822
+ * Pad `str` to `width`.
823
+ *
824
+ * @param {String} str
825
+ * @param {Number} width
826
+ * @return {String}
827
+ * @api private
828
+ */
829
+
830
+ function pad(str, width) {
831
+ var len = Math.max(0, width - str.length);
832
+ return str + Array(len + 1).join(' ');
833
+ }
834
+
835
+ /**
836
+ * Output help information if necessary
837
+ *
838
+ * @param {Command} command to output help for
839
+ * @param {Array} array of options to search for -h or --help
840
+ * @api private
841
+ */
842
+
843
+ function outputHelpIfNecessary(cmd, options) {
844
+ options = options || [];
845
+ for (var i = 0; i < options.length; i++) {
846
+ if (options[i] == '--help' || options[i] == '-h') {
847
+ cmd.outputHelp();
848
+ process.exit(0);
849
+ }
850
+ }
851
+ }