@@ -17,26 +17,160 @@ function curlToGo(curl) {
1717 // List of curl flags that are boolean typed; this helps with parsing
1818 // a command like `curl -abc value` to know whether 'value' belongs to '-c'
1919 // or is just a positional argument instead.
20- var boolOptions = [ '#' , 'progress-bar' , '-' , 'next' , '0' , 'http1.0' , 'http1.1' , 'http2' ,
21- 'no-npn' , 'no-alpn' , '1' , 'tlsv1' , '2' , 'sslv2' , '3' , 'sslv3' , '4' , 'ipv4' , '6' , 'ipv6' ,
22- 'a' , 'append' , 'anyauth' , 'B' , 'use-ascii' , 'basic' , 'compressed' , 'create-dirs' ,
23- 'crlf' , 'digest' , 'disable-eprt' , 'disable-epsv' , 'environment' , 'cert-status' ,
24- 'false-start' , 'f' , 'fail' , 'ftp-create-dirs' , 'ftp-pasv' , 'ftp-skip-pasv-ip' ,
25- 'ftp-pret' , 'ftp-ssl-ccc' , 'ftp-ssl-control' , 'g' , 'globoff' , 'G' , 'get' ,
26- 'ignore-content-length' , 'i' , 'include' , 'I' , 'head' , 'j' , 'junk-session-cookies' ,
27- 'J' , 'remote-header-name' , 'k' , 'insecure' , 'l' , 'list-only' , 'L' , 'location' ,
28- 'location-trusted' , 'metalink' , 'n' , 'netrc' , 'N' , 'no-buffer' , 'netrc-file' ,
29- 'netrc-optional' , 'negotiate' , 'no-keepalive' , 'no-sessionid' , 'ntlm' , 'O' ,
30- 'remote-name' , 'oauth2-bearer' , 'p' , 'proxy-tunnel' , 'path-as-is' , 'post301' , 'post302' ,
31- 'post303' , 'proxy-anyauth' , 'proxy-basic' , 'proxy-digest' , 'proxy-negotiate' ,
32- 'proxy-ntlm' , 'q' , 'raw' , 'remote-name-all' , 's' , 'silent' , 'sasl-ir' , 'S' , 'show-error' ,
33- 'ssl' , 'ssl-reqd' , 'ssl-allow-beast' , 'ssl-no-revoke' , 'socks5-gssapi-nec' , 'tcp-nodelay' ,
34- 'tlsv1.0' , 'tlsv1.1' , 'tlsv1.2' , 'tr-encoding' , 'trace-time' , 'v' , 'verbose' , 'xattr' ,
35- 'h' , 'help' , 'M' , 'manual' , 'V' , 'version' ] ;
20+ // https://github.com/curl/curl/blob/f410b9e538129e77607fef1894f96c684a7c8c3b/src/tool_getparam.c#L73-L341
21+ var boolOptions = new Set ( [
22+ 'disable-epsv' , 'no-disable-epsv' , 'disallow-username-in-url' , 'no-disallow-username-in-url' ,
23+ 'epsv' , 'no-epsv' , 'npn' , 'no-npn' , 'alpn' , 'no-alpn' , 'compressed' , 'no-compressed' ,
24+ 'tr-encoding' , 'no-tr-encoding' , 'digest' , 'no-digest' , 'negotiate' , 'no-negotiate' ,
25+ 'ntlm' , 'no-ntlm' , 'ntlm-wb' , 'no-ntlm-wb' , 'basic' , 'no-basic' , 'anyauth' , 'no-anyauth' ,
26+ 'wdebug' , 'no-wdebug' , 'ftp-create-dirs' , 'no-ftp-create-dirs' ,
27+ 'create-dirs' , 'no-create-dirs' , 'proxy-ntlm' , 'no-proxy-ntlm' , 'crlf' , 'no-crlf' ,
28+ 'haproxy-protocol' , 'no-haproxy-protocol' , 'disable-eprt' , 'no-disable-eprt' ,
29+ 'eprt' , 'no-eprt' , 'xattr' , 'no-xattr' , 'ftp-ssl' , 'no-ftp-ssl' , 'ssl' , 'no-ssl' ,
30+ 'ftp-pasv' , 'no-ftp-pasv' , 'tcp-nodelay' , 'no-tcp-nodelay' , 'proxy-digest' , 'no-proxy-digest' ,
31+ 'proxy-basic' , 'no-proxy-basic' , 'retry-connrefused' , 'no-retry-connrefused' ,
32+ 'proxy-negotiate' , 'no-proxy-negotiate' , 'proxy-anyauth' , 'no-proxy-anyauth' ,
33+ 'trace-time' , 'no-trace-time' , 'ignore-content-length' , 'no-ignore-content-length' ,
34+ 'ftp-skip-pasv-ip' , 'no-ftp-skip-pasv-ip' , 'ftp-ssl-reqd' , 'no-ftp-ssl-reqd' ,
35+ 'ssl-reqd' , 'no-ssl-reqd' , 'sessionid' , 'no-sessionid' , 'ftp-ssl-control' , 'no-ftp-ssl-control' ,
36+ 'ftp-ssl-ccc' , 'no-ftp-ssl-ccc' , 'raw' , 'no-raw' , 'post301' , 'no-post301' ,
37+ 'keepalive' , 'no-keepalive' , 'post302' , 'no-post302' ,
38+ 'socks5-gssapi-nec' , 'no-socks5-gssapi-nec' , 'ftp-pret' , 'no-ftp-pret' , 'post303' , 'no-post303' ,
39+ 'metalink' , 'no-metalink' , 'sasl-ir' , 'no-sasl-ir' , 'test-event' , 'no-test-event' ,
40+ 'path-as-is' , 'no-path-as-is' , 'tftp-no-options' , 'no-tftp-no-options' ,
41+ 'suppress-connect-headers' , 'no-suppress-connect-headers' , 'compressed-ssh' , 'no-compressed-ssh' ,
42+ 'retry-all-errors' , 'no-retry-all-errors' ,
43+ 'http1.0' , 'http1.1' , 'http2' , 'http2-prior-knowledge' , 'http3' , 'http0.9' , 'no-http0.9' ,
44+ 'tlsv1' , 'tlsv1.0' , 'tlsv1.1' , 'tlsv1.2' , 'tlsv1.3' , 'sslv2' , 'sslv3' ,
45+ 'ipv4' , 'ipv6' ,
46+ 'append' , 'no-append' , 'use-ascii' , 'no-use-ascii' , 'ssl-allow-beast' , 'no-ssl-allow-beast' ,
47+ 'ssl-auto-client-cert' , 'no-ssl-auto-client-cert' ,
48+ 'proxy-ssl-auto-client-cert' , 'no-proxy-ssl-auto-client-cert' , 'cert-status' , 'no-cert-status' ,
49+ 'doh-cert-status' , 'no-doh-cert-status' , 'false-start' , 'no-false-start' ,
50+ 'ssl-no-revoke' , 'no-ssl-no-revoke' , 'ssl-revoke-best-effort' , 'no-ssl-revoke-best-effort' ,
51+ 'tcp-fastopen' , 'no-tcp-fastopen' , 'proxy-ssl-allow-beast' , 'no-proxy-ssl-allow-beast' ,
52+ 'proxy-insecure' , 'no-proxy-insecure' , 'proxy-tlsv1' , 'socks5-basic' , 'no-socks5-basic' ,
53+ 'socks5-gssapi' , 'no-socks5-gssapi' , 'fail' , 'no-fail' , 'fail-early' , 'no-fail-early' ,
54+ 'styled-output' , 'no-styled-output' , 'mail-rcpt-allowfails' , 'no-mail-rcpt-allowfails' ,
55+ 'fail-with-body' , 'no-fail-with-body' , 'globoff' , 'no-globoff' , 'get' , 'help' , 'no-help' ,
56+ 'include' , 'no-include' , 'head' , 'no-head' , 'junk-session-cookies' , 'no-junk-session-cookies' ,
57+ 'remote-header-name' , 'no-remote-header-name' , 'insecure' , 'no-insecure' ,
58+ 'doh-insecure' , 'no-doh-insecure' , 'list-only' , 'no-list-only' , 'location' , 'no-location' ,
59+ 'location-trusted' , 'no-location-trusted' , 'manual' , 'no-manual' , 'netrc' , 'no-netrc' ,
60+ 'netrc-optional' , 'no-netrc-optional' , 'buffer' , 'no-buffer' , 'remote-name' ,
61+ 'remote-name-all' , 'no-remote-name-all' , 'proxytunnel' , 'no-proxytunnel' , 'disable' , 'no-disable' ,
62+ 'remote-time' , 'no-remote-time' , 'silent' , 'no-silent' , 'show-error' , 'no-show-error' ,
63+ 'verbose' , 'no-verbose' , 'version' , 'no-version' , 'parallel' , 'no-parallel' ,
64+ 'parallel-immediate' , 'no-parallel-immediate' , 'progress-bar' , 'no-progress-bar' ,
65+ 'progress-meter' , 'no-progress-meter' , 'next' ,
66+ // renamed to --http3 in https://github.com/curl/curl/commit/026840e3
67+ 'http3-direct' ,
68+ // replaced by --request-target in https://github.com/curl/curl/commit/9b167fd0
69+ 'strip-path-slash' , 'no-strip-path-slash' ,
70+ // removed in https://github.com/curl/curl/commit/a8e388dd
71+ 'environment' , 'no-environment' ,
72+ // curl technically accepted these non-sensical options, they were removed in
73+ // https://github.com/curl/curl/commit/913c3c8f
74+ 'no-http1.0' , 'no-http1.1' , 'no-http2' , 'no-http2-prior-knowledge' ,
75+ 'no-tlsv1' , 'no-tlsv1.0' , 'no-tlsv1.1' , 'no-tlsv1.2' , 'no-tlsv1.3' , 'no-sslv2' , 'no-sslv3' ,
76+ 'no-ipv4' , 'no-ipv6' , 'no-proxy-tlsv1' , 'no-get' , 'no-remote-name' , 'no-next' ,
77+ // removed in https://github.com/curl/curl/commit/720ea577
78+ 'proxy-sslv2' , 'no-proxy-sslv2' , 'proxy-sslv3' , 'no-proxy-sslv3' ,
79+ // removed in https://github.com/curl/curl/commit/388c6b5e
80+ // I don't think this was ever a real short option
81+ // '~',
82+ // renamed to --http2 in https://github.com/curl/curl/commit/0952c9ab
83+ 'http2.0' , 'no-http2.0' ,
84+ // removed in https://github.com/curl/curl/commit/ebf31389
85+ // I don't think this option was ever released, it was renamed the same day
86+ // it was introduced
87+ // 'ssl-no-empty-fragments', 'no-ssl-no-empty-fragments',
88+ // renamed to --ntlm-wb in https://github.com/curl/curl/commit/b4f6319c
89+ 'ntlm-sso' , 'no-ntlm-sso' ,
90+ // all options got "--no-" versions in https://github.com/curl/curl/commit/5abfdc01
91+ // renamed to --no-keepalive in https://github.com/curl/curl/commit/f866af91
92+ 'no-keep-alive' ,
93+ // may've been short for --crlf until https://github.com/curl/curl/commit/16643faa
94+ // '9',
95+ // removed in https://github.com/curl/curl/commit/07660eea
96+ // -@ used to be short for --create-dirs
97+ 'ftp-ascii' , // '@',
98+ // removed in https://github.com/curl/curl/commit/c13dbf7b
99+ // 'c', 'continue',
100+ // removed in https://github.com/curl/curl/commit/a1d6ad26
101+ // -t used to be short for --upload
102+ // 't', 'upload',
103+ // https://github.com/mholt/curl-to-go/pull/47#issuecomment-879485938
104+ '-' ,
105+ ] ) ;
106+
107+ // all of curl's short options have a long form
108+ var optionAliases = {
109+ '0' : 'http1.0' ,
110+ '1' : 'tlsv1' ,
111+ '2' : 'sslv2' ,
112+ '3' : 'sslv3' ,
113+ '4' : 'ipv4' ,
114+ '6' : 'ipv6' ,
115+ 'a' : 'append' ,
116+ 'A' : 'user-agent' ,
117+ 'b' : 'cookie' ,
118+ 'B' : 'use-ascii' ,
119+ 'c' : 'cookie-jar' ,
120+ 'C' : 'continue-at' ,
121+ 'd' : 'data' ,
122+ 'D' : 'dump-header' ,
123+ 'e' : 'referer' ,
124+ 'E' : 'cert' ,
125+ 'f' : 'fail' ,
126+ 'F' : 'form' ,
127+ 'g' : 'globoff' ,
128+ 'G' : 'get' ,
129+ 'h' : 'help' ,
130+ 'H' : 'header' ,
131+ 'i' : 'include' ,
132+ 'I' : 'head' ,
133+ 'j' : 'junk-session-cookies' ,
134+ 'J' : 'remote-header-name' ,
135+ 'k' : 'insecure' ,
136+ 'K' : 'config' ,
137+ 'l' : 'list-only' ,
138+ 'L' : 'location' ,
139+ 'm' : 'max-time' ,
140+ 'M' : 'manual' ,
141+ 'n' : 'netrc' ,
142+ // N is an alias for --no-buffer, not --buffer
143+ 'N' : 'no-buffer' ,
144+ 'o' : 'output' ,
145+ 'O' : 'remote-name' ,
146+ 'p' : 'proxytunnel' ,
147+ 'P' : 'ftp-port' ,
148+ 'q' : 'disable' ,
149+ 'Q' : 'quote' ,
150+ 'r' : 'range' ,
151+ 'R' : 'remote-time' ,
152+ 's' : 'silent' ,
153+ 'S' : 'show-error' ,
154+ 't' : 'telnet-option' ,
155+ 'T' : 'upload-file' ,
156+ 'u' : 'user' ,
157+ 'U' : 'proxy-user' ,
158+ 'v' : 'verbose' ,
159+ 'V' : 'version' ,
160+ 'w' : 'write-out' ,
161+ 'x' : 'proxy' ,
162+ 'X' : 'request' ,
163+ 'Y' : 'speed-limit' ,
164+ 'y' : 'speed-time' ,
165+ 'z' : 'time-cond' ,
166+ 'Z' : 'parallel' ,
167+ '#' : 'progress-bar' ,
168+ ':' : 'next' ,
169+ } ;
36170
37171 if ( ! curl . trim ( ) )
38172 return ;
39- var cmd = parseCommand ( curl , { boolFlags : boolOptions } ) ;
173+ var cmd = parseCommand ( curl , { boolFlags : boolOptions , aliases : optionAliases } ) ;
40174
41175 if ( cmd . _ [ 0 ] != "curl" )
42176 throw "Not a curl command" ;
@@ -196,21 +330,16 @@ function curlToGo(curl) {
196330 relevant . url = cmd . _ [ 1 ] ; // position 1 because index 0 is the curl command itself
197331
198332 // gather the headers together
199- if ( cmd . H )
200- relevant . headers = relevant . headers . concat ( cmd . H ) ;
201333 if ( cmd . header )
202334 relevant . headers = relevant . headers . concat ( cmd . header ) ;
203335 relevant . headers = parseHeaders ( relevant . headers )
204336
205337 // set method to HEAD?
206- if ( cmd . I || cmd . head )
338+ if ( cmd . head )
207339 relevant . method = "HEAD" ;
208340
209- // between -X and --request, prefer the long form I guess
210341 if ( cmd . request && cmd . request . length > 0 )
211- relevant . method = cmd . request [ cmd . request . length - 1 ] . toUpperCase ( ) ;
212- else if ( cmd . X && cmd . X . length > 0 )
213- relevant . method = cmd . X [ cmd . X . length - 1 ] . toUpperCase ( ) ; // if multiple, use last (according to curl docs)
342+ relevant . method = cmd . request [ cmd . request . length - 1 ] . toUpperCase ( ) ; // if multiple, use last (according to curl docs)
214343 else if (
215344 ( cmd [ "data-binary" ] && cmd [ "data-binary" ] . length > 0 )
216345 || ( cmd [ "data-raw" ] && cmd [ "data-raw" ] . length > 0 )
@@ -243,8 +372,6 @@ function curlToGo(curl) {
243372 }
244373 }
245374 } ;
246- if ( cmd . d )
247- loadData ( cmd . d ) ;
248375 if ( cmd . data )
249376 loadData ( cmd . data ) ;
250377 if ( cmd [ "data-binary" ] )
@@ -256,12 +383,9 @@ function curlToGo(curl) {
256383 if ( dataFiles . length > 0 )
257384 relevant . data . files = dataFiles ;
258385
259- // between -u and --user, choose the long form...
260386 var basicAuthString = "" ;
261387 if ( cmd . user && cmd . user . length > 0 )
262388 basicAuthString = cmd . user [ cmd . user . length - 1 ] ;
263- else if ( cmd . u && cmd . u . length > 0 )
264- basicAuthString = cmd . u [ cmd . u . length - 1 ] ;
265389 // if the -u or --user flags haven't been set then don't set the
266390 // basicauth property.
267391 if ( basicAuthString ) {
@@ -281,7 +405,7 @@ function curlToGo(curl) {
281405 if ( ! relevant . method )
282406 relevant . method = "GET" ;
283407
284- if ( cmd . k || cmd . insecure ) {
408+ if ( cmd . insecure ) {
285409 relevant . insecure = true ;
286410 }
287411
@@ -378,13 +502,13 @@ function parseCommand(input, options) {
378502 cursor ++ ; // skip leading dash
379503 while ( cursor < input . length && ! whitespace ( input [ cursor ] ) )
380504 {
381- var flagName = input [ cursor ] ;
505+ var flagName = fullName ( input [ cursor ] ) ;
382506 if ( typeof result [ flagName ] == 'undefined' ) {
383507 result [ flagName ] = [ ] ;
384508 }
385509 cursor ++ ; // skip the flag name
386510 if ( boolFlag ( flagName ) )
387- result [ flagName ] = true ;
511+ result [ flagName ] = toBool ( flagName ) ;
388512 else if ( Array . isArray ( result [ flagName ] ) )
389513 result [ flagName ] . push ( nextString ( ) ) ;
390514 }
@@ -396,7 +520,7 @@ function parseCommand(input, options) {
396520 cursor += 2 ; // skip leading dashes
397521 var flagName = nextString ( "=" ) ;
398522 if ( boolFlag ( flagName ) )
399- result [ flagName ] = true ;
523+ result [ flagName ] = toBool ( flagName ) ;
400524 else {
401525 if ( typeof result [ flagName ] == 'undefined' ) {
402526 result [ flagName ] = [ ] ;
@@ -413,8 +537,17 @@ function parseCommand(input, options) {
413537 result . _ . push ( nextString ( ) ) ;
414538 }
415539
540+ // fullName returns the long name of a short flag
541+ function fullName ( flag ) {
542+ var alias = options . aliases [ flag ]
543+ return alias ? alias : flag ;
544+ }
545+
416546 // boolFlag returns whether a flag is known to be boolean type
417547 function boolFlag ( flag ) {
548+ if ( options . boolFlags instanceof Set ) {
549+ return options . boolFlags . has ( flag ) ;
550+ }
418551 if ( Array . isArray ( options . boolFlags ) ) {
419552 for ( var i = 0 ; i < options . boolFlags . length ; i ++ ) {
420553 if ( options . boolFlags [ i ] == flag )
@@ -424,6 +557,13 @@ function parseCommand(input, options) {
424557 return false ;
425558 }
426559
560+ // toBool converts a long flag name to a boolean value.
561+ // --verbose -> true
562+ // --no-verbose -> false
563+ function toBool ( flag ) {
564+ return ! ( flag . startsWith ( 'no-' ) || flag . startsWith ( 'disable-' ) ) ;
565+ }
566+
427567 // nextString skips any leading whitespace and consumes the next
428568 // space-delimited string value and returns it. If endChar is set,
429569 // it will be used to determine the end of the string. Normally just
0 commit comments