1 |
|
2 | 'use strict';
|
3 |
|
4 | var async = require('async');
|
5 | var util = require('util');
|
6 | var read = require('read');
|
7 | var _ = require('underscore');
|
8 | var Table = require('cli-table');
|
9 | var defaults = require('./defaults');
|
10 |
|
11 | var TableFormat = {
|
12 | chars: { 'top': '' , 'top-mid': '' , 'top-left': '' , 'top-right': ''
|
13 | , 'bottom': '' , 'bottom-mid': '' , 'bottom-left': '' , 'bottom-right': ''
|
14 | , 'left': '' , 'left-mid': '' , 'mid': '' , 'mid-mid': ''
|
15 | , 'right': '' , 'right-mid': '' , 'middle': ' ' },
|
16 | style: { 'padding-left': 0, 'padding-right': 0 }
|
17 | };
|
18 | module.exports.TableFormat = TableFormat;
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 | module.exports.getopts = function(argv, start, descriptor) {
|
26 | var opts = {};
|
27 | for (var i = start; i < argv.length; i++) {
|
28 | var longArg = /^--(.+)/.exec(argv[i]);
|
29 | if (longArg) {
|
30 | var longArgName = longArg[1];
|
31 | var ld = descriptor[longArgName];
|
32 | if (ld) {
|
33 | if (ld.toggle) {
|
34 | opts[longArgName] = true;
|
35 | } else if (i < (argv.length - 1)) {
|
36 | i++;
|
37 | opts[longArgName] = argv[i];
|
38 |
|
39 | if (ld.type === 'int') {
|
40 | opts[longArgName] = parseInt(opts[longArgName], 10);
|
41 | }
|
42 |
|
43 |
|
44 | if(ld.prompt == false){
|
45 | opts.prompt = true;
|
46 | }
|
47 | } else {
|
48 | badArg(argv[i]);
|
49 | }
|
50 | } else {
|
51 | badArg(argv[i]);
|
52 | }
|
53 | }
|
54 | else {
|
55 | var shortArg = /^-([A-Za-z])/.exec(argv[i]);
|
56 | if (shortArg) {
|
57 | var shortArgName = shortArg[1];
|
58 | var longName = undefined;
|
59 | var des;
|
60 | for (var sd in descriptor) {
|
61 | des = descriptor[sd];
|
62 | if (des.shortOption === shortArgName) {
|
63 | longName = sd;
|
64 | break;
|
65 | }
|
66 | }
|
67 |
|
68 | if (longName) {
|
69 | if (des.toggle) {
|
70 | opts[longName] = true;
|
71 | } else if (i < (argv.length - 1)) {
|
72 | i++;
|
73 | if (des.type === 'int') {
|
74 | argv[i] = parseInt(argv[i], 10);
|
75 | }
|
76 |
|
77 |
|
78 | if (des.multiple) {
|
79 | if (!opts[longName]) {
|
80 | opts[longName] = [];
|
81 | }
|
82 | opts[longName].push(argv[i]);
|
83 | } else {
|
84 | opts[longName] = argv[i];
|
85 |
|
86 |
|
87 | if(des.prompt == false){
|
88 | opts.prompt = true;
|
89 | }
|
90 | }
|
91 | } else {
|
92 | badArg(argv[i]);
|
93 | }
|
94 | } else {
|
95 | badArg(argv[i])
|
96 | }
|
97 |
|
98 | } else {
|
99 | badArg(argv[i]);
|
100 | }
|
101 | }
|
102 | }
|
103 | return opts;
|
104 | };
|
105 |
|
106 | function badArg(arg) {
|
107 | throw new Error(util.format('Unknown argument %s', arg));
|
108 | }
|
109 |
|
110 |
|
111 |
|
112 |
|
113 |
|
114 |
|
115 |
|
116 |
|
117 | module.exports.validate = function(opts, descriptor, cb) {
|
118 | defaults.defaultOptions(opts);
|
119 | async.eachSeries(Object.getOwnPropertyNames(descriptor), function(item, done) {
|
120 | checkProperty(opts, descriptor, item, done);
|
121 | }, function(err) {
|
122 | cb(err, opts);
|
123 | });
|
124 | };
|
125 |
|
126 | function checkProperty(opts, descriptor, propName, done) {
|
127 | var desc = descriptor[propName];
|
128 |
|
129 |
|
130 | if (desc === null || desc === undefined) {
|
131 | done(new Error(util.format('Invalid property %s', propName)));
|
132 | return;
|
133 | }
|
134 | if (desc.required && !opts[propName]) {
|
135 | if (desc.prompt && !opts.prompt ) {
|
136 | if (opts.interactive) {
|
137 | var pn = (desc.name ? desc.name : propName);
|
138 | prompt(pn, desc.secure, function(err, val) {
|
139 | if (err) {
|
140 | done(err);
|
141 | } else {
|
142 | if (desc.secure === true) {
|
143 | opts[propName] = new SecureValue(val);
|
144 | } else {
|
145 | opts[propName] = val;
|
146 | }
|
147 | done();
|
148 | }
|
149 | });
|
150 | } else {
|
151 | done(new Error(util.format('Missing required option "%s"', propName)));
|
152 | }
|
153 | } else {
|
154 | done(new Error(util.format('Missing required option with no prompt "%s"', propName)));
|
155 | }
|
156 | } else {
|
157 | if (opts[propName] && (desc.secure === true)) {
|
158 | makeSecure(opts, propName);
|
159 | }
|
160 | done();
|
161 | }
|
162 | }
|
163 |
|
164 | function prompt(name, secure, cb) {
|
165 | var opts = {
|
166 | prompt: name + ':'
|
167 | };
|
168 | if (secure) {
|
169 | opts.silent = true;
|
170 | opts.replace = '*';
|
171 | }
|
172 |
|
173 | read(opts, cb);
|
174 | }
|
175 |
|
176 |
|
177 |
|
178 |
|
179 |
|
180 | module.exports.validateSync = function(opts, descriptor) {
|
181 | _.each(Object.getOwnPropertyNames(descriptor), function(item) {
|
182 | checkPropertySync(opts, descriptor, item);
|
183 | });
|
184 | };
|
185 |
|
186 | function checkPropertySync(opts, descriptor, propName) {
|
187 | var desc = descriptor[propName];
|
188 | if (desc === null || desc === undefined) {
|
189 | var err = new Error(util.format('Invalid property %s', propName));
|
190 | console.error(err);
|
191 | throw err;
|
192 | }
|
193 | if (desc.required && !opts[propName] && (!opts.prompt && desc.prompt)) {
|
194 | var err = new Error(util.format('Missing required option "%s"', propName));
|
195 | console.error(err);
|
196 | throw err;
|
197 | } else {
|
198 | if (opts[propName] && (desc.secure === true)) {
|
199 | makeSecure(opts, propName);
|
200 | }
|
201 | }
|
202 | }
|
203 |
|
204 | function makeSecure(opts, propName) {
|
205 | if (opts[propName] && (!(opts[propName] instanceof SecureValue))) {
|
206 | opts[propName] = new SecureValue(opts[propName]);
|
207 | }
|
208 | }
|
209 |
|
210 |
|
211 |
|
212 |
|
213 | module.exports.getHelp = function(descriptor) {
|
214 | var tab = new Table(TableFormat);
|
215 |
|
216 | _.each(_.sortBy(_.pairs(descriptor)), function(d) {
|
217 | tab.push([
|
218 | d[0],
|
219 | (d[1].shortOption ? '-' + d[1].shortOption : ''),
|
220 | ((d[1].required && !d[1].prompt) ? '(required)': '(optional)'),
|
221 | ((d[1].name ? d[1].name : 'undefined')),
|
222 | ((d[1].scope == 'default') ? '' : '(command specific)')
|
223 | ]);
|
224 | });
|
225 |
|
226 | return tab.toString();
|
227 | };
|
228 |
|
229 |
|
230 |
|
231 |
|
232 | function SecureValue(val) {
|
233 | if (!(this instanceof SecureValue)) {
|
234 | return new SecureValue(val);
|
235 | }
|
236 | Object.defineProperty(this, 'value', {
|
237 | configurable: false,
|
238 | enumerable: false,
|
239 | writable: false,
|
240 | value: val
|
241 | });
|
242 | }
|
243 |
|
244 | module.exports.SecureValue = SecureValue;
|
245 |
|
246 | SecureValue.prototype.toString = function() {
|
247 | return '********';
|
248 | };
|
249 |
|
250 | SecureValue.prototype.getValue = function () {
|
251 | return this.value;
|
252 | };
|