Skip to content

Commit 57203b1

Browse files
authored
Add curl option aliases and all boolean options (#47)
* Update list of boolean curl options * Add all removed boolean options since 1999 * store flags in a Set * add curl option aliases * add '-' as a boolean option
1 parent 31a063d commit 57203b1

File tree

1 file changed

+173
-33
lines changed

1 file changed

+173
-33
lines changed

resources/js/curl-to-go.js

Lines changed: 173 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)