@@ -16,12 +16,11 @@ const colorsUtil = require("./colors");
16
16
// S | string array
17
17
18
18
/** Parses the specified command line arguments according to the given configuration. */
19
- function parse ( argv , config ) {
19
+ function parse ( argv , config , populateDefaults = true ) {
20
20
var options = { } ;
21
21
var unknown = [ ] ;
22
22
var args = [ ] ;
23
23
var trailing = [ ] ;
24
- var provided = new Set ( ) ;
25
24
26
25
// make an alias map and initialize defaults
27
26
var aliases = { } ;
@@ -54,13 +53,15 @@ function parse(argv, config) {
54
53
else { args . push ( arg ) ; continue ; } // argument
55
54
}
56
55
if ( option ) {
57
- if ( option . type == null || option . type === "b" ) {
58
- options [ key ] = true ; // flag
59
- provided . add ( key ) ;
56
+ if ( option . value ) {
57
+ // alias setting fixed values
58
+ Object . keys ( option . value ) . forEach ( k => options [ k ] = option . value [ k ] ) ;
59
+ } else if ( option . type == null || option . type === "b" ) {
60
+ // boolean flag not taking a value
61
+ options [ key ] = true ;
60
62
} else {
61
- // the argument was provided
62
- if ( i + 1 < argv . length && argv [ i + 1 ] . charCodeAt ( 0 ) != 45 ) { // present
63
- provided . add ( key ) ;
63
+ if ( i + 1 < argv . length && argv [ i + 1 ] . charCodeAt ( 0 ) != 45 ) {
64
+ // non-boolean with given value
64
65
switch ( option . type ) {
65
66
case "i" : options [ key ] = parseInt ( argv [ ++ i ] , 10 ) ; break ;
66
67
case "I" : options [ key ] = ( options [ key ] || [ ] ) . concat ( parseInt ( argv [ ++ i ] , 10 ) ) ; break ;
@@ -70,7 +71,8 @@ function parse(argv, config) {
70
71
case "S" : options [ key ] = ( options [ key ] || [ ] ) . concat ( argv [ ++ i ] . split ( "," ) ) ; break ;
71
72
default : unknown . push ( arg ) ; -- i ;
72
73
}
73
- } else { // omitted
74
+ } else {
75
+ // non-boolean with omitted value
74
76
switch ( option . type ) {
75
77
case "i" :
76
78
case "f" : options [ key ] = option . default || 0 ; break ;
@@ -82,12 +84,12 @@ function parse(argv, config) {
82
84
}
83
85
}
84
86
}
85
- if ( option . value ) Object . keys ( option . value ) . forEach ( k => options [ k ] = option . value [ k ] ) ;
86
87
} else unknown . push ( arg ) ;
87
88
}
88
89
while ( i < k ) trailing . push ( argv [ i ++ ] ) ; // trailing
90
+ if ( populateDefaults ) addDefaults ( config , options ) ;
89
91
90
- return { options, unknown, arguments : args , trailing, provided } ;
92
+ return { options, unknown, arguments : args , trailing } ;
91
93
}
92
94
93
95
exports . parse = parse ;
@@ -138,3 +140,76 @@ function help(config, options) {
138
140
}
139
141
140
142
exports . help = help ;
143
+
144
+ /** Merges two sets of options into one, preferring the current over the parent set. */
145
+ function merge ( config , currentOptions , parentOptions ) {
146
+ const mergedOptions = { } ;
147
+ for ( const [ key , { mutuallyExclusive } ] of Object . entries ( config ) ) {
148
+ if ( currentOptions [ key ] == null ) {
149
+ if ( parentOptions [ key ] != null ) {
150
+ // only parent value present
151
+ if ( Array . isArray ( parentOptions [ key ] ) ) {
152
+ if ( mutuallyExclusive ) {
153
+ const exclude = currentOptions [ mutuallyExclusive ] ;
154
+ if ( exclude ) {
155
+ mergedOptions [ key ] = parentOptions [ key ] . filter ( value => ! exclude . includes ( value ) ) ;
156
+ } else {
157
+ mergedOptions [ key ] = parentOptions [ key ] . slice ( ) ;
158
+ }
159
+ } else {
160
+ mergedOptions [ key ] = parentOptions [ key ] . slice ( ) ;
161
+ }
162
+ } else {
163
+ mergedOptions [ key ] = parentOptions [ key ] ;
164
+ }
165
+ }
166
+ } else if ( parentOptions [ key ] == null ) {
167
+ // only current value present
168
+ if ( Array . isArray ( currentOptions [ key ] ) ) {
169
+ mergedOptions [ key ] = currentOptions [ key ] . slice ( ) ;
170
+ } else {
171
+ mergedOptions [ key ] = currentOptions [ key ] ;
172
+ }
173
+ } else {
174
+ // both current and parent values present
175
+ if ( Array . isArray ( currentOptions [ key ] ) ) {
176
+ if ( mutuallyExclusive ) {
177
+ const exclude = currentOptions [ mutuallyExclusive ] ;
178
+ if ( exclude ) {
179
+ mergedOptions [ key ] = [
180
+ ...currentOptions [ key ] ,
181
+ ...parentOptions [ key ] . filter ( value => ! currentOptions [ key ] . includes ( value ) && ! exclude . includes ( value ) )
182
+ ] ;
183
+ } else {
184
+ mergedOptions [ key ] = [
185
+ ...currentOptions [ key ] ,
186
+ ...parentOptions [ key ] . filter ( value => ! currentOptions [ key ] . includes ( value ) ) // dedup
187
+ ] ;
188
+ }
189
+ } else {
190
+ mergedOptions [ key ] = [
191
+ ...currentOptions [ key ] ,
192
+ ...parentOptions [ key ] . filter ( value => ! currentOptions [ key ] . includes ( value ) ) // dedup
193
+ ] ;
194
+ }
195
+ } else {
196
+ mergedOptions [ key ] = currentOptions [ key ] ;
197
+ }
198
+ }
199
+ }
200
+ return mergedOptions ;
201
+ }
202
+
203
+ exports . merge = merge ;
204
+
205
+ /** Populates default values on a parsed options result. */
206
+ function addDefaults ( config , options ) {
207
+ for ( const [ key , { default : defaultValue } ] of Object . entries ( config ) ) {
208
+ if ( options [ key ] == null && defaultValue != null ) {
209
+ options [ key ] = defaultValue ;
210
+ }
211
+ }
212
+ return options ;
213
+ }
214
+
215
+ exports . addDefaults = addDefaults ;
0 commit comments