1+ import process from 'node:process' ;
2+
3+ export default function createCommandLineArgumentsHandler ( validArguments ) {
4+ const validTypes = [ 'json' , 'string' , 'number' , 'boolean' ] ;
5+ const argumentInfo = { } ;
6+ const shortArgsMap = { } ;
7+ const defaultTemplate = { } ;
8+ {
9+ const inputKeys = Object . keys ( validArguments ) ;
10+ for ( let i = 0 ; i < inputKeys . length ; i ++ ) {
11+ const key = inputKeys [ i ] ;
12+ const firstCode = key [ 0 ] . charCodeAt ( 0 ) ;
13+ if ( ( firstCode < 65 || firstCode > 90 ) && ( firstCode < 97 || firstCode > 122 ) )
14+ continue ;
15+ const argument = validArguments [ key ] ;
16+ if ( argument . type && validTypes . includes ( argument . type ) ) {
17+ argumentInfo [ key ] = { } ;
18+ argumentInfo [ key ] . type = argument . type ;
19+ argumentInfo [ key ] . hasShortKey = argument . shortKey ?? ( argument . type === 'boolean' ) ;
20+ argumentInfo [ key ] . takesParameter = ( argument . type !== 'boolean' ? true : argument . takesParameter ?? false ) ;
21+ argumentInfo [ key ] . acceptsPropertySyntax = argument . propertySyntax ;
22+ if ( argument . default ) {
23+ defaultTemplate [ key ] = argument . default ;
24+ }
25+ }
26+ }
27+ validArguments = null ;
28+ }
29+ const argumentKeys = Object . keys ( argumentInfo ) ;
30+ for ( let i = 0 ; i < argumentKeys . length ; i ++ ) {
31+ const key = argumentKeys [ i ] ;
32+ if ( ! argumentInfo [ key ] . hasShortKey )
33+ continue ;
34+ let shortKey = null ;
35+ let shortKeyCandidate = key [ 0 ] . toLowerCase ( ) ;
36+ for ( let j = 0 ; j < 26 ; j ++ ) {
37+ if ( ! shortArgsMap [ shortKeyCandidate ] ) {
38+ shortArgsMap [ shortKeyCandidate ] = key ;
39+ shortKey = shortKeyCandidate ;
40+ break ;
41+ } else if ( ! shortArgsMap [ shortKeyCandidate . toUpperCase ( ) ] ) {
42+ shortArgsMap [ shortKeyCandidate . toUpperCase ( ) ] = key ;
43+ shortKey = shortKeyCandidate . toUpperCase ( ) ;
44+ break ;
45+ }
46+ shortKeyCandidate = String . fromCharCode ( ( ( shortKeyCandidate . charCodeAt ( 0 ) - 95 ) % 26 ) + 96 ) ;
47+ console . log ( shortKeyCandidate ) ;
48+ }
49+ if ( ! shortKey )
50+ throw new Error ( `Could not assign short key for argument: ${ key } ` ) ;
51+ }
52+
53+ function checkForSplitValue ( value , args , index ) {
54+ if ( value [ 0 ] == "'" ) {
55+ return value [ value . length - 1 ] !== "'" ;
56+ } else if ( value [ 0 ] == '"' ) {
57+ return value [ value . length - 1 ] !== '"' ;
58+ }
59+ return false ;
60+ }
61+
62+ function parseBooleanArgument ( key , args , index , options , value ) {
63+ if ( value !== null && ! argumentInfo [ key ] . takesParameter ) {
64+ throw new Error ( `Invalid option: ${ key } ` ) ;
65+ } else if ( value === null && ! argumentInfo [ key ] . takesParameter ) {
66+ options [ key ] = true ;
67+ return 0 ;
68+ } else if ( argumentInfo [ key ] . takesParameter ) {
69+ let increment = 0 ;
70+ if ( value === null && args . length > index + 1 ) {
71+ value = args [ index + 1 ] ;
72+ increment = 1 ;
73+ } else if ( value === null ) {
74+ throw new Error ( `Invalid option: ${ key } ` ) ;
75+ } else if ( checkForSplitValue ( value ) ) {
76+ do {
77+ if ( args . length <= index + increment )
78+ throw new Error ( `Unclosed option value: ${ key } ` ) ;
79+ value += ' ' + args [ index + 1 ] ;
80+ increment ++ ;
81+ } while ( checkForSplitValue ( value ) ) ;
82+ value = value . slice ( 1 , - 1 ) ;
83+ }
84+ options [ key ] = value ;
85+ return increment ;
86+ } else {
87+ throw new Error ( `Invalid option: ${ key } ` ) ;
88+ }
89+ }
90+
91+ function parseNumberArgument ( key , args , index , options , value ) {
92+ let increment = 0 ;
93+ if ( value === null && args . length > index + 1 ) {
94+ value = args [ index + 1 ] ;
95+ increment = 1 ;
96+ }
97+ if ( value === null )
98+ throw new Error ( `Invalid option: ${ key } ` ) ;
99+ if ( checkForSplitValue ( value ) )
100+ throw new Error ( `Unclosed option value: ${ key } ` ) ;
101+ if ( value . startsWith ( "0x" ) ) {
102+ options [ key ] = parseInt ( value . slice ( 2 ) , 16 ) ;
103+ } else if ( value . startsWith ( "0o" ) ) {
104+ options [ key ] = parseInt ( value . slice ( 2 ) , 8 ) ;
105+ } else if ( value . startsWith ( "0b" ) ) {
106+ options [ key ] = parseInt ( value . slice ( 2 ) , 2 ) ;
107+ } else {
108+ if ( value . startsWith ( "0d" ) ) {
109+ options [ key ] = parseInt ( value . slice ( 2 ) , 10 ) ;
110+ } else options [ key ] = parseFloat ( value ) ;
111+ }
112+ return increment ;
113+ }
114+
115+ function parseStringArgument ( key , args , index , options , value ) {
116+ let increment = 0 ;
117+ if ( value === null && args . length > index + 1 ) {
118+ value = args [ index + 1 ] ;
119+ increment = 1 ;
120+ }
121+ if ( value === null )
122+ throw new Error ( `Invalid option: ${ key } ` ) ;
123+ if ( checkForSplitValue ( value ) ) {
124+ do {
125+ if ( args . length <= index + increment )
126+ throw new Error ( `Unclosed option value: ${ key } ` ) ;
127+ value += ' ' + args [ index + 1 ] ;
128+ increment ++ ;
129+ } while ( checkForSplitValue ( value ) ) ;
130+ value = value . slice ( 1 , - 1 ) ;
131+ }
132+ options [ key ] = value ;
133+ return increment ;
134+ }
135+
136+ function parseJsonArgument ( key , args , index , options , value ) {
137+ let increment = 0 ;
138+ if ( value === null && args . length > index + 1 ) {
139+ value = args [ index + 1 ] ;
140+ increment = 1 ;
141+ }
142+ if ( value === null )
143+ throw new Error ( `Invalid option: ${ key } ` ) ;
144+ if ( checkForSplitValue ( value ) ) {
145+ do {
146+ if ( args . length <= index + increment )
147+ throw new Error ( `Unclosed option value: ${ key } ` ) ;
148+ value += ' ' + args [ index + 1 ] ;
149+ increment ++ ;
150+ } while ( checkForSplitValue ( value ) ) ;
151+ value = value . slice ( 1 , - 1 ) ;
152+ }
153+ options [ key ] = JSON . parse ( value . replaceAll ( "'" , "\"" ) ) ;
154+ return increment ;
155+ }
156+
157+
158+ return function ( ) {
159+ const args = process . argv . slice ( 2 ) ;
160+ const parsedArgs = { args : [ ] , options : Object . assign ( { } , defaultTemplate ) } ;
161+
162+ for ( let i = 0 ; i < args . length ; i ++ ) {
163+ const arg = args [ i ] ;
164+ if ( arg . startsWith ( '--' ) ) {
165+ const longArg = arg . slice ( 2 ) ;
166+ let key = longArg ;
167+ let value = null ;
168+ if ( ! argumentInfo [ key . replace ( / - / g, '_' ) ] ) {
169+ let splitproperty = longArg . split ( "=" ) ;
170+ if ( splitproperty . length > 1 ) {
171+ key = splitproperty [ 0 ] ;
172+ value = splitproperty [ 1 ] ;
173+ } else {
174+ throw new Error ( `Invalid option: ${ key } ` ) ;
175+ }
176+ if ( ! argumentInfo [ key ] )
177+ throw new Error ( `Invalid option: ${ key } ` ) ;
178+ if ( ! argumentInfo [ key ] . acceptsPropertySyntax )
179+ throw new Error ( `Invalid property syntax for option: ${ key } ` ) ;
180+ }
181+ if ( key . indexOf ( '_' ) !== - 1 )
182+ throw new Error ( `Invalid option: ${ key } ` ) ;
183+ key = key . replace ( / - / g, '_' ) ;
184+ switch ( argumentInfo [ key ] . type ) {
185+ case 'boolean' :
186+ i += parseBooleanArgument ( key , args , i , parsedArgs . options , value ) ;
187+ break ;
188+ case 'number' :
189+ i += parseNumberArgument ( key , args , i , parsedArgs . options , value ) ;
190+ break ;
191+ case 'string' :
192+ i += parseStringArgument ( key , args , i , parsedArgs . options , value ) ;
193+ break ;
194+ case 'json' :
195+ i += parseJsonArgument ( key , args , i , parsedArgs . options , value ) ;
196+ break ;
197+ }
198+ } else if ( arg . startsWith ( '-' ) ) {
199+ const shortArg = arg . slice ( 1 ) ;
200+ for ( let j = 0 ; j < shortArg . length ; j ++ ) {
201+ const key = shortArgsMap [ shortArg [ j ] ] ;
202+ if ( ! key ) {
203+ throw new Error ( `Invalid option: ${ shortArg [ j ] } ` ) ;
204+ }
205+ if ( argumentInfo [ key ] . type === 'boolean' ) {
206+ i += parseBooleanArgument ( key , args , i , parsedArgs . options , null ) ;
207+ } else if ( j > 0 || shortArg . length > 1 ) {
208+ throw new Error ( `Invalid option: ${ shortArg } ` ) ;
209+ } else {
210+ switch ( argumentInfo [ key ] . type ) {
211+ case 'number' :
212+ i += parseNumberArgument ( key , args , i , parsedArgs . options , null ) ;
213+ break ;
214+ case 'string' :
215+ i += parseStringArgument ( key , args , i , parsedArgs . options , null ) ;
216+ break ;
217+ case 'json' :
218+ i += parseJsonArgument ( key , args , i , parsedArgs . options , null ) ;
219+ break ;
220+ }
221+ }
222+ }
223+ } else {
224+ parsedArgs . args . push ( arg ) ;
225+ }
226+ }
227+
228+ return parsedArgs ;
229+ }
230+ } ;
0 commit comments