UNPKG

3.43 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.RequiredFlagError = undefined;
7
8require('cli-engine-config');
9
10class Parse {
11 constructor(input) {
12 this.input = input;
13 input.args = input.args || [];
14 input.flags = input.flags || {};
15 }
16
17 async parse(output = {}) {
18 let argv = output.argv || [];
19 output.flags = output.flags || {};
20 output.argv = [];
21 output.args = {};
22
23 let parseFlag = arg => {
24 let long = arg.startsWith('--');
25 let name = long ? findLongFlag(arg) : findShortFlag(arg);
26 if (!name) {
27 const i = arg.indexOf('=');
28 if (i !== -1) {
29 let sliced = arg.slice(i + 1);
30 argv.unshift(sliced);
31
32 let equalsParsed = parseFlag(arg.slice(0, i));
33 if (!equalsParsed) {
34 argv.shift();
35 }
36 return equalsParsed;
37 }
38 return false;
39 }
40 let flag = this.input.flags[name];
41 let cur = output.flags[name];
42 if (flag.parse) {
43 // TODO: handle multiple flags
44 if (cur) throw new Error(`Flag --${name} already provided`);
45 let input;
46 if (long || arg.length < 3) input = argv.shift();else input = arg.slice(arg[2] === '=' ? 3 : 2);
47 if (!input) throw new Error(`Flag --${name} expects a value`);
48 output.flags[name] = input;
49 } else {
50 if (!cur) output.flags[name] = true;
51 // push the rest of the short characters back on the stack
52 if (!long && arg.length > 2) argv.unshift(`-${arg.slice(2)}`);
53 }
54 return true;
55 };
56
57 let findLongFlag = arg => {
58 let name = arg.slice(2);
59 if (this.input.flags[name]) return name;
60 };
61
62 let findShortFlag = arg => {
63 for (let k of Object.keys(this.input.flags)) {
64 if (this.input.flags[k].char === arg[1]) return k;
65 }
66 };
67
68 let parsingFlags = true;
69 let maxArgs = this.input.args.length;
70 let minArgs = this.input.args.filter(a => a.required !== false && !a.optional).length;
71 while (argv.length) {
72 let arg = argv.shift();
73 if (parsingFlags && arg.startsWith('-')) {
74 // attempt to parse as flag
75 if (arg === '--') {
76 parsingFlags = false;
77 continue;
78 }
79 if (parseFlag(arg)) continue;
80 // not actually a flag if it reaches here so parse as an arg
81 }
82 // not a flag, parse as arg
83 let argDefinition = this.input.args[output.argv.length];
84 if (argDefinition) output.args[argDefinition.name] = arg;
85 output.argv.push(arg);
86 }
87
88 if (!this.input.variableArgs && output.argv.length > maxArgs) throw new Error(`Unexpected argument ${output.argv[maxArgs]}`);
89 if (output.argv.length < minArgs) throw new Error(new Error(`Missing required argument ${this.input.args[output.argv.length].name}`));
90
91 for (let name of Object.keys(this.input.flags)) {
92 const flag = this.input.flags[name];
93 if (flag.parse) {
94 output.flags[name] = await flag.parse(output.flags[name], this.input.cmd, name);
95 flag.required = flag.required || flag.optional === false;
96 if (flag.required && !output.flags[name]) throw new RequiredFlagError(name);
97 }
98 }
99
100 return output;
101 }
102}
103
104exports.default = Parse;
105class RequiredFlagError extends Error {
106 constructor(name) {
107 super(`Missing required flag --${name}`);
108 }
109}
110exports.RequiredFlagError = RequiredFlagError;
\No newline at end of file