UNPKG

6.97 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const ts_lodash_1 = require("ts-lodash");
4const debug = require('debug')('cli-flags');
5class Parser {
6 constructor(input) {
7 this.input = input;
8 this.raw = [];
9 this.argv = input.argv.slice(0);
10 this._setNames();
11 this.booleanFlags = ts_lodash_1.default.pickBy(input.flags, (f) => f.type === 'boolean');
12 }
13 parse() {
14 this._debugInput();
15 const findLongFlag = (arg) => {
16 const name = arg.slice(2);
17 if (this.input.flags[name]) {
18 return name;
19 }
20 if (arg.startsWith('--no-')) {
21 const flag = this.booleanFlags[arg.slice(5)];
22 if (flag && flag.allowNo)
23 return flag.name;
24 }
25 };
26 const findShortFlag = (arg) => {
27 return Object.keys(this.input.flags).find(k => this.input.flags[k].char === arg[1]);
28 };
29 const parseFlag = (arg) => {
30 const long = arg.startsWith('--');
31 const name = long ? findLongFlag(arg) : findShortFlag(arg);
32 if (!name) {
33 const i = arg.indexOf('=');
34 if (i !== -1) {
35 const sliced = arg.slice(i + 1);
36 this.argv.unshift(sliced);
37 const equalsParsed = parseFlag(arg.slice(0, i));
38 if (!equalsParsed) {
39 this.argv.shift();
40 }
41 return equalsParsed;
42 }
43 return false;
44 }
45 const flag = this.input.flags[name];
46 if (flag.type === 'option') {
47 let input;
48 if (long || arg.length < 3) {
49 input = this.argv.shift();
50 }
51 else {
52 input = arg.slice(arg[2] === '=' ? 3 : 2);
53 }
54 if (!input) {
55 throw new Error(`Flag --${name} expects a value`);
56 }
57 flag.input.push(input);
58 this.raw.push({ type: 'flag', flag: flag.name, input });
59 }
60 else {
61 flag.input = arg;
62 this.raw.push({ type: 'flag', flag: flag.name, input: arg });
63 if (!long && arg.length > 2) {
64 this.argv.unshift(`-${arg.slice(2)}`);
65 }
66 }
67 return true;
68 };
69 let parsingFlags = true;
70 while (this.argv.length) {
71 const input = this.argv.shift();
72 if (parsingFlags && input.startsWith('-')) {
73 if (input === '--') {
74 parsingFlags = false;
75 continue;
76 }
77 if (parseFlag(input)) {
78 continue;
79 }
80 }
81 const arg = this.input.args[this._argTokens.length];
82 if (arg)
83 arg.input = input;
84 this.raw.push({ type: 'arg', input });
85 }
86 const argv = this._argv();
87 const args = this._args(argv);
88 const flags = this._flags();
89 this._debugOutput(argv, args, flags);
90 return {
91 args,
92 argv,
93 flags,
94 raw: this.raw,
95 };
96 }
97 _args(argv) {
98 const args = {};
99 for (let i = 0; i < this.input.args.length; i++) {
100 const arg = this.input.args[i];
101 args[arg.name] = argv[i];
102 }
103 return args;
104 }
105 _flags() {
106 const flags = {};
107 for (const token of this._flagTokens) {
108 const flag = this.input.flags[token.flag];
109 if (!flag)
110 throw new Error(`Unexpected flag ${token.flag}`);
111 if (flag.type === 'boolean') {
112 if (token.input === `--no-${flag.name}`) {
113 flags[token.flag] = false;
114 }
115 else {
116 flags[token.flag] = true;
117 }
118 }
119 else {
120 const value = flag.parse(token.input, Object.assign({ flag }, this.input.parseContext));
121 if (flag.multiple) {
122 flags[token.flag] = flags[token.flag] || [];
123 flags[token.flag].push(value);
124 }
125 else {
126 flags[token.flag] = value;
127 }
128 flag.value = flags[token.flag];
129 }
130 }
131 for (const [k, flag] of Object.entries(this.input.flags)) {
132 if (!flags[k]) {
133 if (flag.type === 'option' && flag.default) {
134 if (typeof flag.default === 'function') {
135 flags[k] = flag.default({ flag, input: this.input });
136 }
137 else {
138 flags[k] = flag.default;
139 }
140 flag.value = flags[k];
141 }
142 }
143 }
144 return flags;
145 }
146 _argv() {
147 const args = [];
148 const tokens = this._argTokens;
149 for (let i = 0; i < Math.max(this.input.args.length, tokens.length); i++) {
150 const token = tokens[i];
151 const arg = this.input.args[i];
152 if (token) {
153 if (arg) {
154 args[i] = arg.parse(token.input, Object.assign({ arg }, this.input.parseContext));
155 }
156 else {
157 args[i] = token.input;
158 }
159 }
160 else {
161 if (arg.default) {
162 if (typeof arg.default === 'function') {
163 args[i] = arg.default();
164 }
165 else {
166 args[i] = arg.default;
167 }
168 }
169 }
170 }
171 return args;
172 }
173 _debugOutput(args, flags, argv) {
174 if (argv.length) {
175 debug('argv: %o', argv);
176 }
177 if (Object.keys(args).length) {
178 debug('args: %o', args);
179 }
180 if (Object.keys(flags).length) {
181 debug('flags: %o', flags);
182 }
183 }
184 _debugInput() {
185 debug('input: %s', this.argv.join(' '));
186 if (this.input.args.length) {
187 debug('available args: %s', this.input.args.map(a => a.name).join(' '));
188 }
189 if (Object.keys(this.input.flags).length) {
190 debug('available flags: %s', Object.keys(this.input.flags)
191 .map(f => `--${f}`)
192 .join(' '));
193 }
194 }
195 get _argTokens() {
196 return this.raw.filter(o => o.type === 'arg');
197 }
198 get _flagTokens() {
199 return this.raw.filter(o => o.type === 'flag');
200 }
201 _setNames() {
202 for (const [name, flag] of Object.entries(this.input.flags)) {
203 flag.name = name;
204 }
205 }
206}
207exports.Parser = Parser;