1 | "use strict";
|
2 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
3 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
4 | };
|
5 | var __importStar = (this && this.__importStar) || function (mod) {
|
6 | if (mod && mod.__esModule) return mod;
|
7 | var result = {};
|
8 | if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
9 | result["default"] = mod;
|
10 | return result;
|
11 | };
|
12 | Object.defineProperty(exports, "__esModule", { value: true });
|
13 | const option_1 = __importDefault(require("./option"));
|
14 | const argument_1 = __importDefault(require("./argument"));
|
15 | const error_1 = require("./error");
|
16 | const utils = __importStar(require("./utils"));
|
17 |
|
18 | class Command {
|
19 | |
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 | constructor(name) {
|
29 | |
30 |
|
31 |
|
32 | this._help = new option_1.default("-h, --help", "display help");
|
33 | |
34 |
|
35 |
|
36 |
|
37 | this._rest = [];
|
38 | |
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 | this.options = [];
|
47 | |
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 | this.subCommands = [];
|
56 | |
57 |
|
58 |
|
59 |
|
60 | this.parsedOpts = {};
|
61 | |
62 |
|
63 |
|
64 |
|
65 | this.parsedArgs = {};
|
66 | |
67 |
|
68 |
|
69 |
|
70 | this.unknownOptions = [];
|
71 | let args = name.split(/\s+/);
|
72 | this.name = args.shift();
|
73 | let findOptional = false;
|
74 | let findVariadic = false;
|
75 | this.args = args.map(argStr => {
|
76 | if (findVariadic) {
|
77 | throw new error_1.CommandpostError({
|
78 | parts: [argStr],
|
79 | message: "parameter can not placed after variadic parameter",
|
80 | reason: error_1.ErrorReason.ParameterCantPlacedAfterVariadic,
|
81 | });
|
82 | }
|
83 | let arg = new argument_1.default(argStr);
|
84 | if (arg.required && findOptional) {
|
85 | throw new error_1.CommandpostError({
|
86 | parts: [argStr],
|
87 | message: "parameter can not placed after variadic parameter",
|
88 | reason: error_1.ErrorReason.ParameterCannPlacedAfterOptional,
|
89 | });
|
90 | }
|
91 | if (!arg.required) {
|
92 | findOptional = true;
|
93 | }
|
94 | if (arg.variadic) {
|
95 | findVariadic = true;
|
96 | }
|
97 | return arg;
|
98 | });
|
99 | this._action = () => {
|
100 | process.stdout.write(this.helpText() + "\n");
|
101 | };
|
102 | }
|
103 | |
104 |
|
105 |
|
106 |
|
107 |
|
108 |
|
109 | description(desc) {
|
110 | this._description = desc;
|
111 | return this;
|
112 | }
|
113 | |
114 |
|
115 |
|
116 |
|
117 |
|
118 |
|
119 | usage(usage) {
|
120 | this._usage = usage;
|
121 | return this;
|
122 | }
|
123 | |
124 |
|
125 |
|
126 |
|
127 |
|
128 |
|
129 |
|
130 |
|
131 | option(flags, description, defaultValue) {
|
132 | let option = new option_1.default(flags, description, defaultValue);
|
133 | this.options.push(option);
|
134 | return this;
|
135 | }
|
136 | |
137 |
|
138 |
|
139 |
|
140 |
|
141 |
|
142 | allowUnknownOption(flag = true) {
|
143 | this._allowUnknownOption = flag;
|
144 | return this;
|
145 | }
|
146 | |
147 |
|
148 |
|
149 |
|
150 |
|
151 | action(fn) {
|
152 | this._action = fn;
|
153 | return this;
|
154 | }
|
155 | |
156 |
|
157 |
|
158 |
|
159 |
|
160 | subCommand(name) {
|
161 | let command = new Command(name);
|
162 | command.parent = this;
|
163 | this.subCommands.push(command);
|
164 | return command;
|
165 | }
|
166 | |
167 |
|
168 |
|
169 |
|
170 |
|
171 | is(arg) {
|
172 | return this.name === arg;
|
173 | }
|
174 | |
175 |
|
176 |
|
177 |
|
178 |
|
179 |
|
180 |
|
181 | help(flags, description) {
|
182 | this._help = new option_1.default(flags, description);
|
183 | return this;
|
184 | }
|
185 | |
186 |
|
187 |
|
188 |
|
189 |
|
190 |
|
191 |
|
192 | version(version, flags, description = "output the version number") {
|
193 | this._version = new option_1.default(flags, description);
|
194 | this._versionStr = version;
|
195 | return this;
|
196 | }
|
197 | |
198 |
|
199 |
|
200 |
|
201 |
|
202 | exec() {
|
203 | return Promise.resolve(this._action(this.parsedOpts, this.parsedArgs, this._rest));
|
204 | }
|
205 | |
206 |
|
207 |
|
208 |
|
209 |
|
210 | parse(argv) {
|
211 | return Promise
|
212 | .resolve(null)
|
213 | .then(() => {
|
214 | let rest = this._parseRawArgs(argv);
|
215 |
|
216 | if (this._args.some(arg => this._help.is(arg))) {
|
217 |
|
218 | process.stdout.write(this.helpText() + "\n");
|
219 | process.exit(0);
|
220 | return Promise.resolve({});
|
221 | }
|
222 | let subCommand;
|
223 | if (this.parent == null) {
|
224 |
|
225 | if (this._rest.some(arg => this._help.name() === arg)) {
|
226 |
|
227 | if (rest[0]) {
|
228 | subCommand = this.subCommands.filter(cmd => cmd.is(rest[0]))[0];
|
229 | if (subCommand) {
|
230 | process.stdout.write(subCommand.helpText() + "\n");
|
231 | process.exit(0);
|
232 | return Promise.resolve({});
|
233 | }
|
234 | }
|
235 |
|
236 | }
|
237 | }
|
238 |
|
239 | if (this._version && this._args.some(arg => this._version.is(arg))) {
|
240 | process.stdout.write((this._versionStr || "unknown") + "\n");
|
241 | process.exit(0);
|
242 | return Promise.resolve({});
|
243 | }
|
244 | if (rest[0]) {
|
245 | subCommand = this.subCommands.filter(cmd => cmd.is(rest[0]))[0];
|
246 | if (subCommand) {
|
247 | return subCommand.parse(rest.slice(1));
|
248 | }
|
249 | }
|
250 | return this.exec();
|
251 | });
|
252 | }
|
253 | |
254 |
|
255 |
|
256 |
|
257 | _getAncestorsAndMe() {
|
258 | if (!this.parent) {
|
259 | return [this];
|
260 | }
|
261 | else {
|
262 | return this.parent._getAncestorsAndMe().concat([this]);
|
263 | }
|
264 | }
|
265 | |
266 |
|
267 |
|
268 |
|
269 |
|
270 | _parseRawArgs(args) {
|
271 | args = args.slice(0);
|
272 | let target = [];
|
273 | let rest = [];
|
274 | for (let i = 0; i < args.length; i++) {
|
275 | let arg = args[i];
|
276 | if (arg === "--") {
|
277 |
|
278 | target = target.concat(args.slice(i));
|
279 | break;
|
280 | }
|
281 | let cmd = this.subCommands.filter(cmd => cmd.is(arg))[0];
|
282 | if (cmd) {
|
283 | rest = args.slice(i);
|
284 | break;
|
285 | }
|
286 | target.push(arg);
|
287 | }
|
288 | this._rawArgs = target.slice(0);
|
289 | this._args = this._normalize(target);
|
290 | this._rest = this._parseOptions(this._args);
|
291 | let cmds = this._getAncestorsAndMe();
|
292 | let allowUnknownOption = cmds.reverse().map(cmd => cmd._allowUnknownOption).filter(allowUnknownOption => typeof allowUnknownOption !== "undefined")[0];
|
293 | if (this.unknownOptions.length !== 0 && !allowUnknownOption) {
|
294 | let errMsg = "unknown option";
|
295 | errMsg += this.unknownOptions.length === 1 ? " " : "s ";
|
296 | errMsg += this.unknownOptions.join(", ") + "\n";
|
297 | errMsg += this.helpText();
|
298 | throw new error_1.CommandpostError({
|
299 | message: errMsg,
|
300 | reason: error_1.ErrorReason.UnknownOption,
|
301 | parts: this.unknownOptions,
|
302 | params: {
|
303 | origin: this,
|
304 | args,
|
305 | },
|
306 | });
|
307 | }
|
308 | if (this._matchSubCommand(rest)) {
|
309 | return rest;
|
310 | }
|
311 | this._rest = this._parseArgs(this._rest);
|
312 | return rest;
|
313 | }
|
314 | |
315 |
|
316 |
|
317 |
|
318 |
|
319 | _matchSubCommand(rest) {
|
320 | if (rest == null || !rest[0]) {
|
321 | return false;
|
322 | }
|
323 | let subCommand = this.subCommands.filter(cmd => cmd.is(rest[0]))[0];
|
324 | return !!subCommand;
|
325 | }
|
326 | |
327 |
|
328 |
|
329 |
|
330 |
|
331 | _parseOptions(args) {
|
332 | args = args.slice(0);
|
333 | let rest = [];
|
334 | let processedOptions = [];
|
335 | while (args.length !== 0) {
|
336 | let arg = args.shift();
|
337 | if (arg === "--") {
|
338 | rest = rest.concat(args);
|
339 | break;
|
340 | }
|
341 | let opt = this.options.filter(opt => opt.is(arg))[0];
|
342 | if (!opt) {
|
343 | rest.push(arg);
|
344 | if (arg.indexOf("-") === 0 && !this._help.is(arg) && (!this._version || !this._version.is(arg))) {
|
345 | this.unknownOptions.push(arg);
|
346 | }
|
347 | continue;
|
348 | }
|
349 | args = opt.parse(this.parsedOpts, [arg].concat(args));
|
350 | processedOptions.push(opt);
|
351 | }
|
352 | this.options
|
353 | .filter(opt => processedOptions.indexOf(opt) === -1)
|
354 | .forEach(opt => {
|
355 | let optName = utils.kebabToLowerCamelCase(opt.name());
|
356 | if (opt.required || opt.optional) {
|
357 |
|
358 | this.parsedOpts[optName] = this.parsedOpts[optName] || [];
|
359 | if (opt.defaultValue) {
|
360 | this.parsedOpts[optName].push(opt.defaultValue);
|
361 | }
|
362 | }
|
363 | else {
|
364 | this.parsedOpts[optName] = opt.defaultValue;
|
365 | }
|
366 | });
|
367 | return rest;
|
368 | }
|
369 | |
370 |
|
371 |
|
372 |
|
373 |
|
374 | _parseArgs(rest) {
|
375 | rest = rest.slice(0);
|
376 | this.args.forEach(argInfo => {
|
377 | rest = argInfo.parse(this.parsedArgs, rest);
|
378 | });
|
379 | return rest;
|
380 | }
|
381 | |
382 |
|
383 |
|
384 |
|
385 |
|
386 | _normalize(args) {
|
387 | let result = [];
|
388 | for (let i = 0; i < args.length; i++) {
|
389 | let arg = args[i];
|
390 | let lastOpt;
|
391 | if (0 < i) {
|
392 | lastOpt = this.options.filter(opt => opt.is(args[i - 1]))[0];
|
393 | }
|
394 | if (arg === "--") {
|
395 |
|
396 | result = result.concat(args.slice(i));
|
397 | break;
|
398 | }
|
399 | else if (lastOpt && lastOpt.required) {
|
400 | result.push(arg);
|
401 | }
|
402 | else if (/^-[^-]/.test(arg)) {
|
403 |
|
404 | arg.slice(1).split("").forEach(c => result.push("-" + c));
|
405 | }
|
406 | else if (/^--/.test(arg) && arg.indexOf("=") !== -1) {
|
407 | result.push(arg.slice(0, arg.indexOf("=")), arg.slice(arg.indexOf("=") + 1));
|
408 | }
|
409 | else {
|
410 | result.push(arg);
|
411 | }
|
412 | }
|
413 | return result;
|
414 | }
|
415 | |
416 |
|
417 |
|
418 |
|
419 | helpText() {
|
420 | let result = "";
|
421 | if (this._description) {
|
422 | result += this._description + "\n\n";
|
423 | }
|
424 |
|
425 | result += " Usage: ";
|
426 | if (this._usage != null) {
|
427 | result += this._usage;
|
428 | }
|
429 | else {
|
430 | result += this._getAncestorsAndMe().map(cmd => cmd.name).join(" ") + " ";
|
431 | if (this.options.length !== 0) {
|
432 | result += "[options] ";
|
433 | }
|
434 | if (this.subCommands.length !== 0) {
|
435 | result += "[command] ";
|
436 | }
|
437 | if (this.args.length !== 0) {
|
438 | result += "[--] ";
|
439 | result += this.args.map(arg => {
|
440 | if (arg.required) {
|
441 | return "<" + arg.name + (arg.variadic ? "..." : "") + ">";
|
442 | }
|
443 | else {
|
444 | return "[" + arg.name + (arg.variadic ? "..." : "") + "]";
|
445 | }
|
446 | }).join(" ");
|
447 | }
|
448 | }
|
449 | result += "\n\n";
|
450 |
|
451 | if (this.options.length !== 0) {
|
452 | result += " Options:\n\n";
|
453 | let optionsMaxLength = utils.maxLength(this.options.map(opt => opt.flags));
|
454 | result += this.options.map(opt => {
|
455 | let result = " ";
|
456 | result += utils.pad(opt.flags, optionsMaxLength);
|
457 | result += " ";
|
458 | result += opt.description || "";
|
459 | result += "\n";
|
460 | return result;
|
461 | }).join("");
|
462 | result += "\n\n";
|
463 | }
|
464 |
|
465 | if (this.subCommands.length !== 0) {
|
466 | result += " Commands:\n\n";
|
467 | let subCommandsMaxLength = utils.maxLength(this.subCommands.map(cmd => cmd.name));
|
468 | result += this.subCommands.map(cmd => {
|
469 | let result = " ";
|
470 | result += utils.pad(cmd.name, subCommandsMaxLength);
|
471 | result += " ";
|
472 | result += cmd._description || "";
|
473 | result += "\n";
|
474 | return result;
|
475 | }).join("");
|
476 | result += "\n\n";
|
477 | }
|
478 | return result;
|
479 | }
|
480 | }
|
481 | exports.default = Command;
|
482 |
|
\ | No newline at end of file |