dragonfly_chrome_headless 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }