11'use strict' ;
2- const isA = Array . isArray ,
3- isB = x => typeof x === 'boolean' ;
2+ const isA = Array . isArray ;
43/**
54 * @typedef {string } VarKey Variable name
65 * @typedef {string | boolean | string[] } VarVal Variable value
76 * @typedef {string } OptStr Option string, e.g. '--', '-o', '--option'
8- * @typedef {OptStr | null } OptDef Option definitions, e.g. '--', '-o', '--option', or ` null` to refer to the variable name
7+ * @typedef {OptStr | null } OptDef Option definitions, e.g. '--', '-o', '--option', or null to refer to the variable name
98 * @typedef {OptDef | OptDef[] } OptKit one or more option definitions
109 *
1110 * @typedef {object } VarKit Variable configuration object
1211 * @property {VarVal } def Variable **def**inition & **def**ault value (pun intended)
1312 * @property {OptKit } [set] Array of options to set the variable value
1413 * @property {OptKit } [rst] Array of options to reset the variable value
1514 *
16- * @typedef {OptKit } HaltKit Halt options, identical to `OptKit`, for now...
15+ * @typedef {OptDef | OptDef[] } HaltKit Halt options, identical to `OptKit`, for now...
1716 * @typedef {{opt: OptStr, key: VarKey} } HaltRes
1817 * @typedef {Record<VarKey, VarKit | HaltKit> } KeyKitMap
1918 * @typedef {Record<VarKey, VarVal> } KeyValMap
@@ -23,6 +22,8 @@ const isA = Array.isArray,
2322 * @returns {boolean } Whether the parsing should continue (false) or quit (true)
2423 * @typedef {Record<OptStr, VarKey> } OptKeyMap internal type
2524 */
25+ /** @param {OptKit } ok */
26+ const god = ok => typeof ok === 'string' ? [ ok ] : isA ( ok ) ? ok : [ ] ;
2627/**
2728 * Command line argument parser function
2829 * @param {string[] } argv Command line arguments array
@@ -42,15 +43,19 @@ export default function parse(argv, i, req, res, err) {
4243 const hlt_ = { } ;
4344 /** @type {OptStr } option */
4445 let opt = '' ;
45- /** @type {OptStr | null } option of an extension */
46- let ext = null ;
47- /** @type {VarKey | undefined } key (because of using object...) */
46+ /** @type {OptStr } option of the extension */
47+ let ext = '' ;
48+ /** @type {VarKey | undefined } key */
4849 let key ;
49- /** @type {VarKey | undefined } key of anonymous variable */
50- let ann ;
51- // methods
50+ /** @type {VarKey | undefined } key to set the universe variable */
51+ let suv ;
52+ /** @type {boolean } set universe variable to halt (?) */
53+ let sun = false ;
54+ // methodsze
55+ /** @param {string } msg @param {VarVal } [val] */
5256 const ask = ( msg , val ) => err ( { msg, i, opt, key, val} ) ;
53- // assert(key != null)
57+ // below: assert(key != null)
58+ /** @param {VarVal } val */
5459 const set = val => {
5560 const cur = res [ key ] ;
5661 if ( isA ( cur ) ) cur . push ( val ) ; else res [ key ] = val ;
@@ -61,136 +66,109 @@ export default function parse(argv, i, req, res, err) {
6166 } ;
6267 const noB = ( ) => {
6368 const def = req [ key ] . def ;
64- if ( isB ( def ) ) res [ key ] = ! def ; else return true ;
69+ if ( typeof def === 'boolean' ) {
70+ res [ key ] = ! def ;
71+ return false ;
72+ } return true ;
73+ } ;
74+ /** @param {string } s */
75+ const one = s => {
76+ if ( key = set_ [ opt = s ] ) {
77+ if ( noB ( ) ) ext = opt ;
78+ } else if ( key = rst_ [ opt ] ) rst ( ) ;
79+ else return ask ( 'invalid option' ) ;
80+ return false ;
6581 } ;
6682 // prepare
6783 for ( key in req ) {
6884 const vk = req [ key ] ;
69- H: {
70- /** @type {HaltKit } */
71- let hk ;
72- if ( vk == null ) hk = [ key ] ;
73- else if ( isA ( vk ) ) hk = vk ;
74- else if ( typeof vk === 'object' ) break H;
75- else hk = [ vk ] ;
76- for ( const od of hk )
77- if ( od !== '--' ) hlt_ [ od || key ] = key ;
78- continue ;
79- }
80- let ok = vk . set ;
85+ H: { let hk ;
86+ switch ( typeof vk ) {
87+ case 'object' :
88+ if ( vk == null ) hk = [ key ] ;
89+ else if ( isA ( vk ) ) hk = vk ;
90+ else break H; break ;
91+ case 'string' : hk = [ vk ] ; break ;
92+ default : continue ; }
93+ for ( const o of hk ) if ( o !== '--' ) hlt_ [ o || key ] = key ; else suv = key , sun = true ; // lol
94+ continue ; }
8195 const def = vk . def ;
82- if ( isA ( def ) ) {
83- res [ key ] = def . slice ( ) ;
84- if ( ok !== undefined )
85- for ( const od of isA ( ok ) ?ok :[ ok ] )
86- if ( od !== '--' ) set_ [ od || key ] = key ; else ann = key ;
87- } else {
88- res [ key ] = def ;
89- if ( ok !== undefined )
90- for ( const od of isA ( ok ) ?ok :[ ok ] )
91- if ( od !== '--' ) set_ [ od || key ] = key ; // no stomach
92- }
93- if ( ( ok = vk . rst ) !== undefined )
94- for ( const od of isA ( ok ) ?ok :[ ok ] )
95- if ( od !== '--' ) rst_ [ od || key ] = key ;
96+ res [ key ] = isA ( def ) ? def . slice ( ) : def ; // just rst() with known `def`
97+ for ( const o of god ( vk . set ) ) if ( o !== '--' ) set_ [ o || key ] = key ; else suv = key , sun = false ;
98+ for ( const o of god ( vk . rst ) ) if ( o !== '--' ) rst_ [ o || key ] = key ; // ?? wanna reset around?
9699 }
97100 // process
98101 /** @type {HaltRes } */
99102 let halt = null ;
100103 I: for ( ; i < argv . length ; ++ i ) {
101104 const s = argv [ i ] ;
102- // extension ~ Just bite one more thing
103- if ( ext != null ) { // fact(const val = s)
104- ext = null ; // assert(opt === ext)
105- if ( key != null ) { // assert(key === set_[opt])
105+ // extension ~ Just one more thing
106+ if ( ext ) { // fact(const val = s)
107+ ext = '' ; // assert(opt === ext)
108+ if ( key ) { // assert(key === set_[opt])
106109 set ( s ) ;
107- continue I;
108- } else {
109- if ( ask ( 'invalid option' , s ) ) break I;
110+ continue ;
110111 }
112+ if ( ask ( 'invalid option' , s ) ) break ;
111113 }
112- // halt ~ It should be this simple, right?
113- if ( key = hlt_ [ s ] ) {
114- opt = s ;
115- halt = { opt, key} ;
116- break I;
117- }
118- // ordinary ~ No more dashes!
114+ // halt ~ Basic so that `i` is usable for resuming parsing
115+ if ( key = hlt_ [ opt = s ] ) { ++ i ; halt = { opt, key} ; break ; }
116+ // abc
119117 if ( s . length < 2 || s [ 0 ] !== '-' ) {
120- opt = s ;
121- if ( key = set_ [ opt ] ) {
118+ if ( key = set_ [ opt = s ] ) {
122119 if ( noB ( ) ) ext = opt ;
123- } else if ( key = rst_ [ opt ] ) {
124- rst ( ) ;
125- } else if ( ann ) {
126- res [ ann ] . push ( opt ) ;
127- } else {
128- if ( ask ( 'invalid option' ) ) break I;
129- }
130- continue I;
131- }
132- // ultimate ~ Eat you all nom nom
133- if ( s === '--' ) {
134- opt = s ;
135- if ( key = ann ) {
136- const val = res [ key ] ; // assert(isA(val))
137- for ( ++ i ; i < argv . length ; ++ i ) val . push ( argv [ i ] ) ;
138- break I;
139- } else {
140- if ( ask ( 'unexpected argument' ) ) break I;
141- }
142- continue I;
120+ } else if ( key = rst_ [ opt ] ) rst ( ) ;
121+ else if ( key = suv ) if ( sun ) { ++ i ; halt = { opt, key} ; break ; } else set ( s ) ;
122+ else if ( ask ( 'invalid option' , s ) ) break ;
123+ continue ;
143124 }
144- // --opt?val
145- if ( s [ 1 ] === '-' ) {
146- const j = s . indexOf ( '=' ) ;
147- // --opt val ~ Make extension
148- if ( j < 0 ) {
149- opt = s ;
150- key = set_ [ opt ] ; // for the assertion
151- ext = opt ;
152- continue I;
153- }
154- // --opt=val ~ Explicit assignment
155- opt = s . slice ( 0 , j ) ;
156- if ( key = set_ [ opt ] ) {
157- const val = s . slice ( j + 1 ) ;
158- if ( isB ( res [ key ] ) ) {
159- if ( ask ( 'Cannot assign a value to a boolean-type option' , val ) ) break I;
160- } else {
161- set ( val ) ;
162- }
163- } else if ( key = rst_ [ opt ] ) {
164- if ( ask ( 'Cannot assign a value to a reset-type option' ) ) break I;
165- } else {
166- if ( ask ( 'invalid option' ) ) break I;
125+ // -abc
126+ if ( s [ 1 ] !== '-' ) {
127+ // -ab ~ no extension
128+ const J = s . length - 1 ;
129+ for ( let j = 1 ; j < J ; ++ j ) {
130+ opt = '-' + s [ j ] ;
131+ if ( key = set_ [ opt ] ) {
132+ if ( noB ( ) ) {
133+ set ( s . slice ( j + 1 ) ) ;
134+ continue I;
135+ }
136+ } else if ( key = rst_ [ opt ] ) rst ( ) ;
137+ else if ( ask ( 'invalid option' ) ) break I;
167138 }
168- continue I;
139+ // -c ~ not universe
140+ if ( one ( '-' + s [ J ] ) ) break ;
141+ continue ;
169142 }
170- // ab in -abc123 ~ Cannot make extension
171- const J = s . length - 1 ;
172- for ( let j = 1 ; j < J ; ++ j ) {
173- opt = '-' + s [ j ] ;
143+ // --abc
144+ if ( s . length > 2 ) {
145+ const k = s . indexOf ( '=' ) ;
146+ // --opt ~ not universe
147+ if ( k < 0 ) if ( one ( s ) ) break ; else continue ;
148+ // --opt=val ~ explicit assignment
149+ opt = s . slice ( 0 , k ) ;
150+ const val = s . slice ( k + 1 ) ;
174151 if ( key = set_ [ opt ] ) {
175- if ( noB ( ) ) {
176- set ( s . slice ( j + 1 ) ) ;
177- continue I;
178- }
152+ if ( typeof res [ key ] === 'boolean' ) {
153+ if ( ask ( 'Cannot assign a value to a boolean-type option' , val ) ) break ;
154+ } else set ( val ) ;
179155 } else if ( key = rst_ [ opt ] ) {
180- rst ( ) ;
156+ if ( ask ( 'Cannot assign a value to a reset-type option' , val ) ) break ;
181157 } else {
182- if ( ask ( 'invalid option' ) ) break I ;
158+ if ( ask ( 'invalid option' , val ) ) break ;
183159 }
160+ continue ;
161+ }
162+ // -- ~ collect all
163+ opt = '--' ;
164+ if ( key = suv ) { ++ i ;
165+ if ( sun ) { halt = { opt, key} ; break ; }
166+ const cur = res [ key ] , len = argv . length ;
167+ if ( isA ( cur ) ) while ( i < len ) cur . push ( argv [ i ++ ] ) ;
168+ else if ( i < len ) res [ key ] = argv [ ( i = len ) - 1 ] ;
169+ break ;
184170 }
185- // c in -abc123 ~ You can't be annonymous
186- opt = '-' + s [ J ] ;
187- if ( key = set_ [ opt ] ) {
188- if ( noB ( ) ) ext = opt ;
189- } else if ( key = rst_ [ opt ] ) {
190- rst ( ) ;
191- } else {
192- if ( ask ( 'invalid option' ) ) break I;
193- }
171+ if ( ask ( 'unexpected argument' ) ) break ;
194172 }
195173 if ( ext ) ask ( 'This option requires an argument' ) ; // assertion same as above
196174 return { i, halt} ;
0 commit comments