1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | const ts_lodash_1 = require("ts-lodash");
|
4 | const debug = require('debug')('cli-flags');
|
5 | class 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 | }
|
207 | exports.Parser = Parser;
|