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