blob: 8b59235f45e5df7222baf13aaf5571b37e6d02f9 [file] [log] [blame]
Leo Repp58b9f112021-11-22 11:57:47 +01001'use strict';
2
3const
4 Q = require('q'),
5
6 CoaParam = require('./coaparam'),
7 chalk = require('chalk');
8
9/**
10 * Option
11 *
12 * Named entity. Options may have short and long keys for use from command line.
13 *
14 * @namespace
15 * @class Opt
16 * @extends CoaParam
17 */
18module.exports = class Opt extends CoaParam {
19 /**
20 * @constructs
21 * @param {COA.Cmd} cmd - parent command
22 */
23 constructor(cmd) {
24 super(cmd);
25
26 this._short = null;
27 this._long = null;
28 this._flag = false;
29 this._only = false;
30 this._cmd._opts.push(this);
31 }
32
33 /**
34 * Set a short key for option to be used with one hyphen from command line.
35 *
36 * @param {String} short - short name
37 * @returns {COA.Opt} - this instance (for chainability)
38 */
39 short(short) {
40 this._short = short;
41 this._cmd._optsByKey[`-${short}`] = this;
42 return this;
43 }
44
45 /**
46 * Set a short key for option to be used with double hyphens from command line.
47 *
48 * @param {String} long - long name
49 * @returns {COA.Opt} - this instance (for chainability)
50 */
51 long(long) {
52 this._long = long;
53 this._cmd._optsByKey[`--${long}`] = this;
54 return this;
55 }
56
57 /**
58 * Make an option boolean, i.e. option without value.
59 *
60 * @returns {COA.Opt} - this instance (for chainability)
61 */
62 flag() {
63 this._flag = true;
64 return this;
65 }
66
67 /**
68 * Makes an option to act as a command,
69 * i.e. program will exit just after option action.
70 *
71 * @returns {COA.Opt} - this instance (for chainability)
72 */
73 only() {
74 this._only = true;
75 return this;
76 }
77
78 /**
79 * Add action for current option command.
80 * This action is performed if the current option
81 * is present in parsed options (with any value).
82 *
83 * @param {Function} act - action function,
84 * invoked in the context of command instance
85 * and has the parameters:
86 * - {Object} opts - parsed options
87 * - {Array} args - parsed arguments
88 * - {Object} res - actions result accumulator
89 * It can return rejected promise by Cmd.reject (in case of error)
90 * or any other value treated as result.
91 * @returns {COA.Opt} - this instance (for chainability)
92 */
93 act(act) {
94 // Need function here for arguments
95 const opt = this;
96 this._cmd.act(function(opts) {
97 if(!opts.hasOwnProperty(opt._name)) return;
98
99 const res = act.apply(this, arguments);
100 if(!opt._only) return res;
101
102 return Q.when(res, out => this.reject({
103 toString : () => out.toString(),
104 exitCode : 0
105 }));
106 });
107
108 return this;
109 }
110
111 _saveVal(opts, val) {
112 this._val && (val = this._val(val));
113
114 const name = this._name;
115 this._arr
116 ? (opts[name] || (opts[name] = [])).push(val)
117 : (opts[name] = val);
118
119 return val;
120 }
121
122 _parse(argv, opts) {
123 return this._saveVal(opts, this._flag ? true : argv.shift());
124 }
125
126 _checkParsed(opts) {
127 return !opts.hasOwnProperty(this._name);
128 }
129
130 _usage() {
131 const res = [],
132 nameStr = this._name.toUpperCase();
133
134 if(this._short) {
135 res.push('-', chalk.greenBright(this._short));
136 this._flag || res.push(' ' + nameStr);
137 res.push(', ');
138 }
139
140 if(this._long) {
141 res.push('--', chalk.green(this._long));
142 this._flag || res.push('=' + nameStr);
143 }
144
145 res.push(' : ', this._title);
146
147 this._req && res.push(' ', chalk.redBright('(required)'));
148
149 return res.join('');
150 }
151
152 _requiredText() {
153 return `Missing required option:\n ${this._usage()}`;
154 }
155};