From 65658c1e1e39497a6c0f11cf11827fdaf3613dd3 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Tue, 2 Jul 2024 18:13:21 +0200 Subject: [PATCH 01/36] 2.1.5 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index e507f1e..8fa7a4c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@httptoolkit/httpsnippet", - "version": "2.1.4", + "version": "2.1.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@httptoolkit/httpsnippet", - "version": "2.1.4", + "version": "2.1.5", "license": "MIT", "dependencies": { "chalk": "^1.1.1", diff --git a/package.json b/package.json index 600a9a5..26f3424 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "2.1.4", + "version": "2.1.5", "name": "@httptoolkit/httpsnippet", "description": "HTTP request snippet generator for *most* languages", "author": "Tim Perry ", From 584632f3aed8cb844a9f6f2afd32e5e41f035e40 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Tue, 2 Jul 2024 19:54:52 +0200 Subject: [PATCH 02/36] Add more escaping cases for header keys Most examples already handle this correctly, just tweaks required for R and HTTPie. I had assumed these were invalid header names, but apparently that's not actually correct! --- src/targets/r/httr.js | 7 ++++++- src/targets/shell/httpie.js | 9 +++++++-- test/fixtures/output/c/libcurl/malicious.c | 5 +++++ .../output/clojure/clj_http/malicious.clj | 7 ++++++- .../output/csharp/httpclient/malicious.cs | 5 +++++ .../output/csharp/restsharp/malicious.cs | 5 +++++ test/fixtures/output/go/native/malicious.go | 5 +++++ test/fixtures/output/http/1.1/malicious | 5 +++++ .../output/java/asynchttp/malicious.java | 5 +++++ .../output/java/nethttp/malicious.java | 5 +++++ .../output/java/okhttp/malicious.java | 5 +++++ .../output/java/unirest/malicious.java | 5 +++++ .../output/javascript/axios/malicious.js | 5 +++++ .../output/javascript/fetch/malicious.js | 5 +++++ .../output/javascript/jquery/malicious.js | 5 +++++ .../output/javascript/xhr/malicious.js | 5 +++++ .../output/kotlin/okhttp/malicious.kt | 5 +++++ test/fixtures/output/node/axios/malicious.js | 5 +++++ test/fixtures/output/node/fetch/malicious.js | 5 +++++ test/fixtures/output/node/native/malicious.js | 5 +++++ .../fixtures/output/node/request/malicious.js | 5 +++++ .../fixtures/output/node/unirest/malicious.js | 5 +++++ .../output/objc/nsurlsession/malicious.m | 7 ++++++- .../fixtures/output/ocaml/cohttp/malicious.ml | 5 +++++ test/fixtures/output/php/curl/malicious.php | 5 +++++ test/fixtures/output/php/http1/malicious.php | 5 +++++ test/fixtures/output/php/http2/malicious.php | 5 +++++ .../powershell/restmethod/malicious.ps1 | 5 +++++ .../powershell/webrequest/malicious.ps1 | 5 +++++ .../output/python/python3/malicious.py | 5 +++++ .../output/python/requests/malicious.py | 5 +++++ test/fixtures/output/r/httr/malicious.r | 2 +- test/fixtures/output/ruby/native/malicious.rb | 5 +++++ test/fixtures/output/shell/curl/malicious.sh | 5 +++++ .../output/shell/httpie/application-json.sh | 2 +- .../fixtures/output/shell/httpie/malicious.sh | 7 ++++++- test/fixtures/output/shell/wget/malicious.sh | 5 +++++ .../output/swift/nsurlsession/malicious.swift | 5 +++++ test/fixtures/requests/malicious.json | 20 +++++++++++++++++++ 39 files changed, 208 insertions(+), 8 deletions(-) diff --git a/src/targets/r/httr.js b/src/targets/r/httr.js index 11ba99a..0b815a6 100644 --- a/src/targets/r/httr.js +++ b/src/targets/r/httr.js @@ -106,7 +106,12 @@ module.exports = function (source, options) { const otherHeaders = Object.entries(source.allHeaders) // These headers are all handled separately: .filter(([key]) => !['cookie', 'accept', 'content-type'].includes(key.toLowerCase())) - .map(([key, value]) => `${key.replace(/-/g, '_')} = '${escape(value, { delimiter: "'" })}'`) + .map(([key, value]) => { + const safeKey = key.match(/^[a-zA-Z][a-zA-Z0-9_.-]*$/) + ? key.replace(/-/g, '_') + : '"' + escape(key) + '"' + return `${safeKey} = '${escape(value, { delimiter: "'" })}'` + }) .join(', ') const setHeaders = otherHeaders diff --git a/src/targets/shell/httpie.js b/src/targets/shell/httpie.js index 40b0338..0836ff2 100644 --- a/src/targets/shell/httpie.js +++ b/src/targets/shell/httpie.js @@ -90,7 +90,7 @@ module.exports = function (source, options) { // construct headers Object.keys(source.allHeaders).sort().forEach(function (key) { - code.push('%s:%s', key, shell.quote(source.allHeaders[key])) + code.push('%s:%s', shell.quote(key), shell.quote(source.allHeaders[key])) }) if (source.postData.mimeType === 'application/x-www-form-urlencoded') { @@ -109,7 +109,12 @@ module.exports = function (source, options) { code.unshift('http %s%s %s', flags.length ? flags.join(' ') + ' ' : '', source.method, shell.quote(opts.queryParams ? source.url : source.fullUrl)) if (raw && source.postData.text) { - code.unshift('echo %s | ', shell.quote(source.postData.text)) + if (source.postData.text.includes('\\')) { + // Printf handles escape characters more clearly & portably than echo + code.unshift("printf '%%s' %s | ", shell.quote(source.postData.text)) + } else { + code.unshift('echo %s | ', shell.quote(source.postData.text)) + } } return code.join() diff --git a/test/fixtures/output/c/libcurl/malicious.c b/test/fixtures/output/c/libcurl/malicious.c index 21f004d..b521db5 100644 --- a/test/fixtures/output/c/libcurl/malicious.c +++ b/test/fixtures/output/c/libcurl/malicious.c @@ -4,11 +4,16 @@ curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST"); curl_easy_setopt(hnd, CURLOPT_URL, "http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//?'=squote-key-test&squote-value-test='&%22=dquote-key-test&dquote-value-test=%22&%60=backtick-key-test&backtick-value-test=%60&%24(=dollar-parenthesis-key-test&dollar-parenthesis-value-test=%24(&%23%7B=hash-brace-key-test&hash-brace-value-test=%23%7B&%25(=percent-parenthesis-key-test&percent-parenthesis-value-test=%25(&%25%7B=percent-brace-key-test&percent-brace-value-test=%25%7B&%7B%7B=double-brace-key-test&double-brace-value-test=%7B%7B&%5C0=null-key-test&null-value-test=%5C0&%25s=string-fmt-key-test&string-fmt-value-test=%25s&%5C=slash-key-test&slash-value-test=%5C"); struct curl_slist *headers = NULL; +headers = curl_slist_append(headers, "': squote-key-test"); headers = curl_slist_append(headers, "squote-value-test: '"); headers = curl_slist_append(headers, "dquote-value-test: \""); +headers = curl_slist_append(headers, "`: backtick-key-test"); headers = curl_slist_append(headers, "backtick-value-test: `"); +headers = curl_slist_append(headers, "$: dollar-key-test"); headers = curl_slist_append(headers, "dollar-parenthesis-value-test: $("); +headers = curl_slist_append(headers, "#: hash-key-test"); headers = curl_slist_append(headers, "hash-brace-value-test: #{"); +headers = curl_slist_append(headers, "%: percent-key-test"); headers = curl_slist_append(headers, "percent-parenthesis-value-test: %("); headers = curl_slist_append(headers, "percent-brace-value-test: %{"); headers = curl_slist_append(headers, "double-brace-value-test: {{"); diff --git a/test/fixtures/output/clojure/clj_http/malicious.clj b/test/fixtures/output/clojure/clj_http/malicious.clj index 9c99ba8..9f74137 100644 --- a/test/fixtures/output/clojure/clj_http/malicious.clj +++ b/test/fixtures/output/clojure/clj_http/malicious.clj @@ -1,10 +1,15 @@ (require '[clj-http.client :as client]) -(client/post "http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//" {:headers {:squote-value-test "'" +(client/post "http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//" {:headers {"'" "squote-key-test" + :squote-value-test "'" :dquote-value-test "\"" + "`" "backtick-key-test" :backtick-value-test "`" + "$" "dollar-key-test" :dollar-parenthesis-value-test "$(" + "#" "hash-key-test" :hash-brace-value-test "#{" + "%" "percent-key-test" :percent-parenthesis-value-test "%(" :percent-brace-value-test "%{" :double-brace-value-test "{{" diff --git a/test/fixtures/output/csharp/httpclient/malicious.cs b/test/fixtures/output/csharp/httpclient/malicious.cs index b88e5e2..7524b59 100644 --- a/test/fixtures/output/csharp/httpclient/malicious.cs +++ b/test/fixtures/output/csharp/httpclient/malicious.cs @@ -5,11 +5,16 @@ RequestUri = new Uri("http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//?'=squote-key-test&squote-value-test='&%22=dquote-key-test&dquote-value-test=%22&%60=backtick-key-test&backtick-value-test=%60&%24(=dollar-parenthesis-key-test&dollar-parenthesis-value-test=%24(&%23%7B=hash-brace-key-test&hash-brace-value-test=%23%7B&%25(=percent-parenthesis-key-test&percent-parenthesis-value-test=%25(&%25%7B=percent-brace-key-test&percent-brace-value-test=%25%7B&%7B%7B=double-brace-key-test&double-brace-value-test=%7B%7B&%5C0=null-key-test&null-value-test=%5C0&%25s=string-fmt-key-test&string-fmt-value-test=%25s&%5C=slash-key-test&slash-value-test=%5C"), Headers = { + { "'", "squote-key-test" }, { "squote-value-test", "'" }, { "dquote-value-test", "\"" }, + { "`", "backtick-key-test" }, { "backtick-value-test", "`" }, + { "$", "dollar-key-test" }, { "dollar-parenthesis-value-test", "$(" }, + { "#", "hash-key-test" }, { "hash-brace-value-test", "#{" }, + { "%", "percent-key-test" }, { "percent-parenthesis-value-test", "%(" }, { "percent-brace-value-test", "%{" }, { "double-brace-value-test", "{{" }, diff --git a/test/fixtures/output/csharp/restsharp/malicious.cs b/test/fixtures/output/csharp/restsharp/malicious.cs index 91dca32..02140dd 100644 --- a/test/fixtures/output/csharp/restsharp/malicious.cs +++ b/test/fixtures/output/csharp/restsharp/malicious.cs @@ -1,10 +1,15 @@ var client = new RestClient("http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//?'=squote-key-test&squote-value-test='&%22=dquote-key-test&dquote-value-test=%22&%60=backtick-key-test&backtick-value-test=%60&%24(=dollar-parenthesis-key-test&dollar-parenthesis-value-test=%24(&%23%7B=hash-brace-key-test&hash-brace-value-test=%23%7B&%25(=percent-parenthesis-key-test&percent-parenthesis-value-test=%25(&%25%7B=percent-brace-key-test&percent-brace-value-test=%25%7B&%7B%7B=double-brace-key-test&double-brace-value-test=%7B%7B&%5C0=null-key-test&null-value-test=%5C0&%25s=string-fmt-key-test&string-fmt-value-test=%25s&%5C=slash-key-test&slash-value-test=%5C"); var request = new RestRequest(Method.POST); +request.AddHeader("'", "squote-key-test"); request.AddHeader("squote-value-test", "'"); request.AddHeader("dquote-value-test", "\""); +request.AddHeader("`", "backtick-key-test"); request.AddHeader("backtick-value-test", "`"); +request.AddHeader("$", "dollar-key-test"); request.AddHeader("dollar-parenthesis-value-test", "$("); +request.AddHeader("#", "hash-key-test"); request.AddHeader("hash-brace-value-test", "#{"); +request.AddHeader("%", "percent-key-test"); request.AddHeader("percent-parenthesis-value-test", "%("); request.AddHeader("percent-brace-value-test", "%{"); request.AddHeader("double-brace-value-test", "{{"); diff --git a/test/fixtures/output/go/native/malicious.go b/test/fixtures/output/go/native/malicious.go index 70c67a9..0e89205 100644 --- a/test/fixtures/output/go/native/malicious.go +++ b/test/fixtures/output/go/native/malicious.go @@ -15,11 +15,16 @@ func main() { req, _ := http.NewRequest("POST", url, payload) + req.Header.Add("'", "squote-key-test") req.Header.Add("squote-value-test", "'") req.Header.Add("dquote-value-test", "\"") + req.Header.Add("`", "backtick-key-test") req.Header.Add("backtick-value-test", "`") + req.Header.Add("$", "dollar-key-test") req.Header.Add("dollar-parenthesis-value-test", "$(") + req.Header.Add("#", "hash-key-test") req.Header.Add("hash-brace-value-test", "#{") + req.Header.Add("%", "percent-key-test") req.Header.Add("percent-parenthesis-value-test", "%(") req.Header.Add("percent-brace-value-test", "%{") req.Header.Add("double-brace-value-test", "{{") diff --git a/test/fixtures/output/http/1.1/malicious b/test/fixtures/output/http/1.1/malicious index 114186f..107f1af 100644 --- a/test/fixtures/output/http/1.1/malicious +++ b/test/fixtures/output/http/1.1/malicious @@ -1,9 +1,14 @@ POST /%27%22%60$(%(%%7B%7B%7B/0%s//?'=squote-key-test&squote-value-test='&%22=dquote-key-test&dquote-value-test=%22&%60=backtick-key-test&backtick-value-test=%60&%24(=dollar-parenthesis-key-test&dollar-parenthesis-value-test=%24(&%23%7B=hash-brace-key-test&hash-brace-value-test=%23%7B&%25(=percent-parenthesis-key-test&percent-parenthesis-value-test=%25(&%25%7B=percent-brace-key-test&percent-brace-value-test=%25%7B&%7B%7B=double-brace-key-test&double-brace-value-test=%7B%7B&%5C0=null-key-test&null-value-test=%5C0&%25s=string-fmt-key-test&string-fmt-value-test=%25s&%5C=slash-key-test&slash-value-test=%5C HTTP/1.1 +': squote-key-test Squote-Value-Test: ' Dquote-Value-Test: " +`: backtick-key-test Backtick-Value-Test: ` +$: dollar-key-test Dollar-Parenthesis-Value-Test: $( +#: hash-key-test Hash-Brace-Value-Test: #{ +%: percent-key-test Percent-Parenthesis-Value-Test: %( Percent-Brace-Value-Test: %{ Double-Brace-Value-Test: {{ diff --git a/test/fixtures/output/java/asynchttp/malicious.java b/test/fixtures/output/java/asynchttp/malicious.java index 7ff3d80..763dab9 100644 --- a/test/fixtures/output/java/asynchttp/malicious.java +++ b/test/fixtures/output/java/asynchttp/malicious.java @@ -1,10 +1,15 @@ AsyncHttpClient client = new DefaultAsyncHttpClient(); client.prepare("POST", "http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//?'=squote-key-test&squote-value-test='&%22=dquote-key-test&dquote-value-test=%22&%60=backtick-key-test&backtick-value-test=%60&%24(=dollar-parenthesis-key-test&dollar-parenthesis-value-test=%24(&%23%7B=hash-brace-key-test&hash-brace-value-test=%23%7B&%25(=percent-parenthesis-key-test&percent-parenthesis-value-test=%25(&%25%7B=percent-brace-key-test&percent-brace-value-test=%25%7B&%7B%7B=double-brace-key-test&double-brace-value-test=%7B%7B&%5C0=null-key-test&null-value-test=%5C0&%25s=string-fmt-key-test&string-fmt-value-test=%25s&%5C=slash-key-test&slash-value-test=%5C") + .setHeader("'", "squote-key-test") .setHeader("squote-value-test", "'") .setHeader("dquote-value-test", "\"") + .setHeader("`", "backtick-key-test") .setHeader("backtick-value-test", "`") + .setHeader("$", "dollar-key-test") .setHeader("dollar-parenthesis-value-test", "$(") + .setHeader("#", "hash-key-test") .setHeader("hash-brace-value-test", "#{") + .setHeader("%", "percent-key-test") .setHeader("percent-parenthesis-value-test", "%(") .setHeader("percent-brace-value-test", "%{") .setHeader("double-brace-value-test", "{{") diff --git a/test/fixtures/output/java/nethttp/malicious.java b/test/fixtures/output/java/nethttp/malicious.java index cd72894..e227616 100644 --- a/test/fixtures/output/java/nethttp/malicious.java +++ b/test/fixtures/output/java/nethttp/malicious.java @@ -1,10 +1,15 @@ HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//?'=squote-key-test&squote-value-test='&%22=dquote-key-test&dquote-value-test=%22&%60=backtick-key-test&backtick-value-test=%60&%24(=dollar-parenthesis-key-test&dollar-parenthesis-value-test=%24(&%23%7B=hash-brace-key-test&hash-brace-value-test=%23%7B&%25(=percent-parenthesis-key-test&percent-parenthesis-value-test=%25(&%25%7B=percent-brace-key-test&percent-brace-value-test=%25%7B&%7B%7B=double-brace-key-test&double-brace-value-test=%7B%7B&%5C0=null-key-test&null-value-test=%5C0&%25s=string-fmt-key-test&string-fmt-value-test=%25s&%5C=slash-key-test&slash-value-test=%5C")) + .header("'", "squote-key-test") .header("squote-value-test", "'") .header("dquote-value-test", "\"") + .header("`", "backtick-key-test") .header("backtick-value-test", "`") + .header("$", "dollar-key-test") .header("dollar-parenthesis-value-test", "$(") + .header("#", "hash-key-test") .header("hash-brace-value-test", "#{") + .header("%", "percent-key-test") .header("percent-parenthesis-value-test", "%(") .header("percent-brace-value-test", "%{") .header("double-brace-value-test", "{{") diff --git a/test/fixtures/output/java/okhttp/malicious.java b/test/fixtures/output/java/okhttp/malicious.java index 13d2499..008bb7c 100644 --- a/test/fixtures/output/java/okhttp/malicious.java +++ b/test/fixtures/output/java/okhttp/malicious.java @@ -5,11 +5,16 @@ Request request = new Request.Builder() .url("http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//?'=squote-key-test&squote-value-test='&%22=dquote-key-test&dquote-value-test=%22&%60=backtick-key-test&backtick-value-test=%60&%24(=dollar-parenthesis-key-test&dollar-parenthesis-value-test=%24(&%23%7B=hash-brace-key-test&hash-brace-value-test=%23%7B&%25(=percent-parenthesis-key-test&percent-parenthesis-value-test=%25(&%25%7B=percent-brace-key-test&percent-brace-value-test=%25%7B&%7B%7B=double-brace-key-test&double-brace-value-test=%7B%7B&%5C0=null-key-test&null-value-test=%5C0&%25s=string-fmt-key-test&string-fmt-value-test=%25s&%5C=slash-key-test&slash-value-test=%5C") .post(body) + .addHeader("'", "squote-key-test") .addHeader("squote-value-test", "'") .addHeader("dquote-value-test", "\"") + .addHeader("`", "backtick-key-test") .addHeader("backtick-value-test", "`") + .addHeader("$", "dollar-key-test") .addHeader("dollar-parenthesis-value-test", "$(") + .addHeader("#", "hash-key-test") .addHeader("hash-brace-value-test", "#{") + .addHeader("%", "percent-key-test") .addHeader("percent-parenthesis-value-test", "%(") .addHeader("percent-brace-value-test", "%{") .addHeader("double-brace-value-test", "{{") diff --git a/test/fixtures/output/java/unirest/malicious.java b/test/fixtures/output/java/unirest/malicious.java index 346a5ce..85f1906 100644 --- a/test/fixtures/output/java/unirest/malicious.java +++ b/test/fixtures/output/java/unirest/malicious.java @@ -1,9 +1,14 @@ HttpResponse response = Unirest.post("http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//?'=squote-key-test&squote-value-test='&%22=dquote-key-test&dquote-value-test=%22&%60=backtick-key-test&backtick-value-test=%60&%24(=dollar-parenthesis-key-test&dollar-parenthesis-value-test=%24(&%23%7B=hash-brace-key-test&hash-brace-value-test=%23%7B&%25(=percent-parenthesis-key-test&percent-parenthesis-value-test=%25(&%25%7B=percent-brace-key-test&percent-brace-value-test=%25%7B&%7B%7B=double-brace-key-test&double-brace-value-test=%7B%7B&%5C0=null-key-test&null-value-test=%5C0&%25s=string-fmt-key-test&string-fmt-value-test=%25s&%5C=slash-key-test&slash-value-test=%5C") + .header("'", "squote-key-test") .header("squote-value-test", "'") .header("dquote-value-test", "\"") + .header("`", "backtick-key-test") .header("backtick-value-test", "`") + .header("$", "dollar-key-test") .header("dollar-parenthesis-value-test", "$(") + .header("#", "hash-key-test") .header("hash-brace-value-test", "#{") + .header("%", "percent-key-test") .header("percent-parenthesis-value-test", "%(") .header("percent-brace-value-test", "%{") .header("double-brace-value-test", "{{") diff --git a/test/fixtures/output/javascript/axios/malicious.js b/test/fixtures/output/javascript/axios/malicious.js index c6a440e..c0435b0 100644 --- a/test/fixtures/output/javascript/axios/malicious.js +++ b/test/fixtures/output/javascript/axios/malicious.js @@ -28,11 +28,16 @@ const options = { 'slash-value-test': '\\' }, headers: { + '\'': 'squote-key-test', 'squote-value-test': '\'', 'dquote-value-test': '"', + '`': 'backtick-key-test', 'backtick-value-test': '`', + $: 'dollar-key-test', 'dollar-parenthesis-value-test': '$(', + '#': 'hash-key-test', 'hash-brace-value-test': '#{', + '%': 'percent-key-test', 'percent-parenthesis-value-test': '%(', 'percent-brace-value-test': '%{', 'double-brace-value-test': '{{', diff --git a/test/fixtures/output/javascript/fetch/malicious.js b/test/fixtures/output/javascript/fetch/malicious.js index 3a02317..4fd3ce1 100644 --- a/test/fixtures/output/javascript/fetch/malicious.js +++ b/test/fixtures/output/javascript/fetch/malicious.js @@ -1,11 +1,16 @@ const options = { method: 'POST', headers: { + '\'': 'squote-key-test', 'squote-value-test': '\'', 'dquote-value-test': '"', + '`': 'backtick-key-test', 'backtick-value-test': '`', + $: 'dollar-key-test', 'dollar-parenthesis-value-test': '$(', + '#': 'hash-key-test', 'hash-brace-value-test': '#{', + '%': 'percent-key-test', 'percent-parenthesis-value-test': '%(', 'percent-brace-value-test': '%{', 'double-brace-value-test': '{{', diff --git a/test/fixtures/output/javascript/jquery/malicious.js b/test/fixtures/output/javascript/jquery/malicious.js index 476209e..b6ccbb6 100644 --- a/test/fixtures/output/javascript/jquery/malicious.js +++ b/test/fixtures/output/javascript/jquery/malicious.js @@ -4,11 +4,16 @@ const settings = { "url": "http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//?'=squote-key-test&squote-value-test='&%22=dquote-key-test&dquote-value-test=%22&%60=backtick-key-test&backtick-value-test=%60&%24(=dollar-parenthesis-key-test&dollar-parenthesis-value-test=%24(&%23%7B=hash-brace-key-test&hash-brace-value-test=%23%7B&%25(=percent-parenthesis-key-test&percent-parenthesis-value-test=%25(&%25%7B=percent-brace-key-test&percent-brace-value-test=%25%7B&%7B%7B=double-brace-key-test&double-brace-value-test=%7B%7B&%5C0=null-key-test&null-value-test=%5C0&%25s=string-fmt-key-test&string-fmt-value-test=%25s&%5C=slash-key-test&slash-value-test=%5C", "method": "POST", "headers": { + "'": "squote-key-test", "squote-value-test": "'", "dquote-value-test": "\"", + "`": "backtick-key-test", "backtick-value-test": "`", + "$": "dollar-key-test", "dollar-parenthesis-value-test": "$(", + "#": "hash-key-test", "hash-brace-value-test": "#{", + "%": "percent-key-test", "percent-parenthesis-value-test": "%(", "percent-brace-value-test": "%{", "double-brace-value-test": "{{", diff --git a/test/fixtures/output/javascript/xhr/malicious.js b/test/fixtures/output/javascript/xhr/malicious.js index d998152..08c9797 100644 --- a/test/fixtures/output/javascript/xhr/malicious.js +++ b/test/fixtures/output/javascript/xhr/malicious.js @@ -10,11 +10,16 @@ xhr.addEventListener("readystatechange", function () { }); xhr.open("POST", "http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//?'=squote-key-test&squote-value-test='&%22=dquote-key-test&dquote-value-test=%22&%60=backtick-key-test&backtick-value-test=%60&%24(=dollar-parenthesis-key-test&dollar-parenthesis-value-test=%24(&%23%7B=hash-brace-key-test&hash-brace-value-test=%23%7B&%25(=percent-parenthesis-key-test&percent-parenthesis-value-test=%25(&%25%7B=percent-brace-key-test&percent-brace-value-test=%25%7B&%7B%7B=double-brace-key-test&double-brace-value-test=%7B%7B&%5C0=null-key-test&null-value-test=%5C0&%25s=string-fmt-key-test&string-fmt-value-test=%25s&%5C=slash-key-test&slash-value-test=%5C"); +xhr.setRequestHeader("'", "squote-key-test"); xhr.setRequestHeader("squote-value-test", "'"); xhr.setRequestHeader("dquote-value-test", "\""); +xhr.setRequestHeader("`", "backtick-key-test"); xhr.setRequestHeader("backtick-value-test", "`"); +xhr.setRequestHeader("$", "dollar-key-test"); xhr.setRequestHeader("dollar-parenthesis-value-test", "$("); +xhr.setRequestHeader("#", "hash-key-test"); xhr.setRequestHeader("hash-brace-value-test", "#{"); +xhr.setRequestHeader("%", "percent-key-test"); xhr.setRequestHeader("percent-parenthesis-value-test", "%("); xhr.setRequestHeader("percent-brace-value-test", "%{"); xhr.setRequestHeader("double-brace-value-test", "{{"); diff --git a/test/fixtures/output/kotlin/okhttp/malicious.kt b/test/fixtures/output/kotlin/okhttp/malicious.kt index ccd65e0..95d5e9f 100644 --- a/test/fixtures/output/kotlin/okhttp/malicious.kt +++ b/test/fixtures/output/kotlin/okhttp/malicious.kt @@ -5,11 +5,16 @@ val body = RequestBody.create(mediaType, "' \" ` $( #{ %( %{ {{ \\0 %s \\") val request = Request.Builder() .url("http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//?'=squote-key-test&squote-value-test='&%22=dquote-key-test&dquote-value-test=%22&%60=backtick-key-test&backtick-value-test=%60&%24(=dollar-parenthesis-key-test&dollar-parenthesis-value-test=%24(&%23%7B=hash-brace-key-test&hash-brace-value-test=%23%7B&%25(=percent-parenthesis-key-test&percent-parenthesis-value-test=%25(&%25%7B=percent-brace-key-test&percent-brace-value-test=%25%7B&%7B%7B=double-brace-key-test&double-brace-value-test=%7B%7B&%5C0=null-key-test&null-value-test=%5C0&%25s=string-fmt-key-test&string-fmt-value-test=%25s&%5C=slash-key-test&slash-value-test=%5C") .post(body) + .addHeader("'", "squote-key-test") .addHeader("squote-value-test", "'") .addHeader("dquote-value-test", "\"") + .addHeader("`", "backtick-key-test") .addHeader("backtick-value-test", "`") + .addHeader("$", "dollar-key-test") .addHeader("dollar-parenthesis-value-test", "$(") + .addHeader("#", "hash-key-test") .addHeader("hash-brace-value-test", "#{") + .addHeader("%", "percent-key-test") .addHeader("percent-parenthesis-value-test", "%(") .addHeader("percent-brace-value-test", "%{") .addHeader("double-brace-value-test", "{{") diff --git a/test/fixtures/output/node/axios/malicious.js b/test/fixtures/output/node/axios/malicious.js index c0c381f..0c3bc7c 100644 --- a/test/fixtures/output/node/axios/malicious.js +++ b/test/fixtures/output/node/axios/malicious.js @@ -28,11 +28,16 @@ var options = { 'slash-value-test': '\\' }, headers: { + '\'': 'squote-key-test', 'squote-value-test': '\'', 'dquote-value-test': '"', + '`': 'backtick-key-test', 'backtick-value-test': '`', + $: 'dollar-key-test', 'dollar-parenthesis-value-test': '$(', + '#': 'hash-key-test', 'hash-brace-value-test': '#{', + '%': 'percent-key-test', 'percent-parenthesis-value-test': '%(', 'percent-brace-value-test': '%{', 'double-brace-value-test': '{{', diff --git a/test/fixtures/output/node/fetch/malicious.js b/test/fixtures/output/node/fetch/malicious.js index 6f286b7..a50f8e9 100644 --- a/test/fixtures/output/node/fetch/malicious.js +++ b/test/fixtures/output/node/fetch/malicious.js @@ -5,11 +5,16 @@ let url = 'http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//?\'=squote-key-test& let options = { method: 'POST', headers: { + '\'': 'squote-key-test', 'squote-value-test': '\'', 'dquote-value-test': '"', + '`': 'backtick-key-test', 'backtick-value-test': '`', + $: 'dollar-key-test', 'dollar-parenthesis-value-test': '$(', + '#': 'hash-key-test', 'hash-brace-value-test': '#{', + '%': 'percent-key-test', 'percent-parenthesis-value-test': '%(', 'percent-brace-value-test': '%{', 'double-brace-value-test': '{{', diff --git a/test/fixtures/output/node/native/malicious.js b/test/fixtures/output/node/native/malicious.js index 830baac..13db86e 100644 --- a/test/fixtures/output/node/native/malicious.js +++ b/test/fixtures/output/node/native/malicious.js @@ -6,11 +6,16 @@ const options = { "port": null, "path": "/%27%22%60$(%(%%7B%7B%7B/0%s//?'=squote-key-test&squote-value-test='&%22=dquote-key-test&dquote-value-test=%22&%60=backtick-key-test&backtick-value-test=%60&%24(=dollar-parenthesis-key-test&dollar-parenthesis-value-test=%24(&%23%7B=hash-brace-key-test&hash-brace-value-test=%23%7B&%25(=percent-parenthesis-key-test&percent-parenthesis-value-test=%25(&%25%7B=percent-brace-key-test&percent-brace-value-test=%25%7B&%7B%7B=double-brace-key-test&double-brace-value-test=%7B%7B&%5C0=null-key-test&null-value-test=%5C0&%25s=string-fmt-key-test&string-fmt-value-test=%25s&%5C=slash-key-test&slash-value-test=%5C", "headers": { + "'": "squote-key-test", "squote-value-test": "'", "dquote-value-test": "\"", + "`": "backtick-key-test", "backtick-value-test": "`", + "$": "dollar-key-test", "dollar-parenthesis-value-test": "$(", + "#": "hash-key-test", "hash-brace-value-test": "#{", + "%": "percent-key-test", "percent-parenthesis-value-test": "%(", "percent-brace-value-test": "%{", "double-brace-value-test": "{{", diff --git a/test/fixtures/output/node/request/malicious.js b/test/fixtures/output/node/request/malicious.js index f502254..e289ee6 100644 --- a/test/fixtures/output/node/request/malicious.js +++ b/test/fixtures/output/node/request/malicious.js @@ -28,11 +28,16 @@ const options = { 'slash-value-test': '\\' }, headers: { + '\'': 'squote-key-test', 'squote-value-test': '\'', 'dquote-value-test': '"', + '`': 'backtick-key-test', 'backtick-value-test': '`', + $: 'dollar-key-test', 'dollar-parenthesis-value-test': '$(', + '#': 'hash-key-test', 'hash-brace-value-test': '#{', + '%': 'percent-key-test', 'percent-parenthesis-value-test': '%(', 'percent-brace-value-test': '%{', 'double-brace-value-test': '{{', diff --git a/test/fixtures/output/node/unirest/malicious.js b/test/fixtures/output/node/unirest/malicious.js index 58f76fd..d082c42 100644 --- a/test/fixtures/output/node/unirest/malicious.js +++ b/test/fixtures/output/node/unirest/malicious.js @@ -28,11 +28,16 @@ req.query({ }); req.headers({ + "'": "squote-key-test", "squote-value-test": "'", "dquote-value-test": "\"", + "`": "backtick-key-test", "backtick-value-test": "`", + "$": "dollar-key-test", "dollar-parenthesis-value-test": "$(", + "#": "hash-key-test", "hash-brace-value-test": "#{", + "%": "percent-key-test", "percent-parenthesis-value-test": "%(", "percent-brace-value-test": "%{", "double-brace-value-test": "{{", diff --git a/test/fixtures/output/objc/nsurlsession/malicious.m b/test/fixtures/output/objc/nsurlsession/malicious.m index 9c5ff77..66f2cc5 100644 --- a/test/fixtures/output/objc/nsurlsession/malicious.m +++ b/test/fixtures/output/objc/nsurlsession/malicious.m @@ -1,10 +1,15 @@ #import -NSDictionary *headers = @{ @"squote-value-test": @"'", +NSDictionary *headers = @{ @"'": @"squote-key-test", + @"squote-value-test": @"'", @"dquote-value-test": @"\"", + @"`": @"backtick-key-test", @"backtick-value-test": @"`", + @"$": @"dollar-key-test", @"dollar-parenthesis-value-test": @"$(", + @"#": @"hash-key-test", @"hash-brace-value-test": @"#{", + @"%": @"percent-key-test", @"percent-parenthesis-value-test": @"%(", @"percent-brace-value-test": @"%{", @"double-brace-value-test": @"{{", diff --git a/test/fixtures/output/ocaml/cohttp/malicious.ml b/test/fixtures/output/ocaml/cohttp/malicious.ml index 20b0757..ada920e 100644 --- a/test/fixtures/output/ocaml/cohttp/malicious.ml +++ b/test/fixtures/output/ocaml/cohttp/malicious.ml @@ -4,11 +4,16 @@ open Lwt let uri = Uri.of_string "http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//?'=squote-key-test&squote-value-test='&%22=dquote-key-test&dquote-value-test=%22&%60=backtick-key-test&backtick-value-test=%60&%24(=dollar-parenthesis-key-test&dollar-parenthesis-value-test=%24(&%23%7B=hash-brace-key-test&hash-brace-value-test=%23%7B&%25(=percent-parenthesis-key-test&percent-parenthesis-value-test=%25(&%25%7B=percent-brace-key-test&percent-brace-value-test=%25%7B&%7B%7B=double-brace-key-test&double-brace-value-test=%7B%7B&%5C0=null-key-test&null-value-test=%5C0&%25s=string-fmt-key-test&string-fmt-value-test=%25s&%5C=slash-key-test&slash-value-test=%5C" in let headers = Header.add_list (Header.init ()) [ + ("'", "squote-key-test"); ("squote-value-test", "'"); ("dquote-value-test", "\""); + ("`", "backtick-key-test"); ("backtick-value-test", "`"); + ("$", "dollar-key-test"); ("dollar-parenthesis-value-test", "$("); + ("#", "hash-key-test"); ("hash-brace-value-test", "#{"); + ("%", "percent-key-test"); ("percent-parenthesis-value-test", "%("); ("percent-brace-value-test", "%{"); ("double-brace-value-test", "{{"); diff --git a/test/fixtures/output/php/curl/malicious.php b/test/fixtures/output/php/curl/malicious.php index 10b4e54..11012f6 100644 --- a/test/fixtures/output/php/curl/malicious.php +++ b/test/fixtures/output/php/curl/malicious.php @@ -12,6 +12,11 @@ CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_POSTFIELDS => "' \" ` $( #{ %( %{ {{ \\0 %s \\", CURLOPT_HTTPHEADER => [ + "#: hash-key-test", + "$: dollar-key-test", + "%: percent-key-test", + "': squote-key-test", + "`: backtick-key-test", "backtick-value-test: `", "dollar-parenthesis-value-test: $(", "double-brace-value-test: {{", diff --git a/test/fixtures/output/php/http1/malicious.php b/test/fixtures/output/php/http1/malicious.php index de63752..99ba255 100644 --- a/test/fixtures/output/php/http1/malicious.php +++ b/test/fixtures/output/php/http1/malicious.php @@ -30,11 +30,16 @@ ]); $request->setHeaders([ + '\'' => 'squote-key-test', 'squote-value-test' => '\'', 'dquote-value-test' => '"', + '`' => 'backtick-key-test', 'backtick-value-test' => '`', + '$' => 'dollar-key-test', 'dollar-parenthesis-value-test' => '$(', + '#' => 'hash-key-test', 'hash-brace-value-test' => '#{', + '%' => 'percent-key-test', 'percent-parenthesis-value-test' => '%(', 'percent-brace-value-test' => '%{', 'double-brace-value-test' => '{{', diff --git a/test/fixtures/output/php/http2/malicious.php b/test/fixtures/output/php/http2/malicious.php index 0dea61b..b21bac8 100644 --- a/test/fixtures/output/php/http2/malicious.php +++ b/test/fixtures/output/php/http2/malicious.php @@ -36,11 +36,16 @@ ])); $request->setHeaders([ + '\'' => 'squote-key-test', 'squote-value-test' => '\'', 'dquote-value-test' => '"', + '`' => 'backtick-key-test', 'backtick-value-test' => '`', + '$' => 'dollar-key-test', 'dollar-parenthesis-value-test' => '$(', + '#' => 'hash-key-test', 'hash-brace-value-test' => '#{', + '%' => 'percent-key-test', 'percent-parenthesis-value-test' => '%(', 'percent-brace-value-test' => '%{', 'double-brace-value-test' => '{{', diff --git a/test/fixtures/output/powershell/restmethod/malicious.ps1 b/test/fixtures/output/powershell/restmethod/malicious.ps1 index da17c73..1ede1d0 100644 --- a/test/fixtures/output/powershell/restmethod/malicious.ps1 +++ b/test/fixtures/output/powershell/restmethod/malicious.ps1 @@ -1,9 +1,14 @@ $headers=@{} +$headers.Add('''', 'squote-key-test') $headers.Add('squote-value-test', '''') $headers.Add('dquote-value-test', '"') +$headers.Add('`', 'backtick-key-test') $headers.Add('backtick-value-test', '`') +$headers.Add('$', 'dollar-key-test') $headers.Add('dollar-parenthesis-value-test', '$(') +$headers.Add('#', 'hash-key-test') $headers.Add('hash-brace-value-test', '#{') +$headers.Add('%', 'percent-key-test') $headers.Add('percent-parenthesis-value-test', '%(') $headers.Add('percent-brace-value-test', '%{') $headers.Add('double-brace-value-test', '{{') diff --git a/test/fixtures/output/powershell/webrequest/malicious.ps1 b/test/fixtures/output/powershell/webrequest/malicious.ps1 index 4676ad7..026ffb0 100644 --- a/test/fixtures/output/powershell/webrequest/malicious.ps1 +++ b/test/fixtures/output/powershell/webrequest/malicious.ps1 @@ -1,9 +1,14 @@ $headers=@{} +$headers.Add('''', 'squote-key-test') $headers.Add('squote-value-test', '''') $headers.Add('dquote-value-test', '"') +$headers.Add('`', 'backtick-key-test') $headers.Add('backtick-value-test', '`') +$headers.Add('$', 'dollar-key-test') $headers.Add('dollar-parenthesis-value-test', '$(') +$headers.Add('#', 'hash-key-test') $headers.Add('hash-brace-value-test', '#{') +$headers.Add('%', 'percent-key-test') $headers.Add('percent-parenthesis-value-test', '%(') $headers.Add('percent-brace-value-test', '%{') $headers.Add('double-brace-value-test', '{{') diff --git a/test/fixtures/output/python/python3/malicious.py b/test/fixtures/output/python/python3/malicious.py index 706ecd0..9d5ecd8 100644 --- a/test/fixtures/output/python/python3/malicious.py +++ b/test/fixtures/output/python/python3/malicious.py @@ -5,11 +5,16 @@ payload = "' \" ` $( #{ %( %{ {{ \\0 %s \\" headers = { + "'": "squote-key-test", "squote-value-test": "'", "dquote-value-test": "\"", + "`": "backtick-key-test", "backtick-value-test": "`", + "$": "dollar-key-test", "dollar-parenthesis-value-test": "$(", + "#": "hash-key-test", "hash-brace-value-test": "#{", + "%": "percent-key-test", "percent-parenthesis-value-test": "%(", "percent-brace-value-test": "%{", "double-brace-value-test": "{{", diff --git a/test/fixtures/output/python/requests/malicious.py b/test/fixtures/output/python/requests/malicious.py index 0e9a043..14eb9dd 100644 --- a/test/fixtures/output/python/requests/malicious.py +++ b/test/fixtures/output/python/requests/malicious.py @@ -29,11 +29,16 @@ payload = "' \" ` $( #{ %( %{ {{ \\0 %s \\" headers = { + "'": "squote-key-test", "squote-value-test": "'", "dquote-value-test": "\"", + "`": "backtick-key-test", "backtick-value-test": "`", + "$": "dollar-key-test", "dollar-parenthesis-value-test": "$(", + "#": "hash-key-test", "hash-brace-value-test": "#{", + "%": "percent-key-test", "percent-parenthesis-value-test": "%(", "percent-brace-value-test": "%{", "double-brace-value-test": "{{", diff --git a/test/fixtures/output/r/httr/malicious.r b/test/fixtures/output/r/httr/malicious.r index 8275064..ac36ea6 100644 --- a/test/fixtures/output/r/httr/malicious.r +++ b/test/fixtures/output/r/httr/malicious.r @@ -31,6 +31,6 @@ payload <- "' \" ` $( #{ %( %{ {{ \\0 %s \\" encode <- "raw" -response <- VERB("POST", url, body = payload, query = queryString, add_headers(squote_value_test = '\'', dquote_value_test = '"', backtick_value_test = '`', dollar_parenthesis_value_test = '$(', hash_brace_value_test = '#{', percent_parenthesis_value_test = '%(', percent_brace_value_test = '%{', double_brace_value_test = '{{', null_value_test = '\\0', string_fmt_value_test = '%s', slash_value_test = '\\'), content_type("text/plain"), encode = encode) +response <- VERB("POST", url, body = payload, query = queryString, add_headers("'" = 'squote-key-test', squote_value_test = '\'', dquote_value_test = '"', "`" = 'backtick-key-test', backtick_value_test = '`', "$" = 'dollar-key-test', dollar_parenthesis_value_test = '$(', "#" = 'hash-key-test', hash_brace_value_test = '#{', "%" = 'percent-key-test', percent_parenthesis_value_test = '%(', percent_brace_value_test = '%{', double_brace_value_test = '{{', null_value_test = '\\0', string_fmt_value_test = '%s', slash_value_test = '\\'), content_type("text/plain"), encode = encode) content(response, "text") \ No newline at end of file diff --git a/test/fixtures/output/ruby/native/malicious.rb b/test/fixtures/output/ruby/native/malicious.rb index 9755a8a..6294fb8 100644 --- a/test/fixtures/output/ruby/native/malicious.rb +++ b/test/fixtures/output/ruby/native/malicious.rb @@ -6,11 +6,16 @@ http = Net::HTTP.new(url.host, url.port) request = Net::HTTP::Post.new(url) +request["'"] = 'squote-key-test' request["squote-value-test"] = '\'' request["dquote-value-test"] = '"' +request["`"] = 'backtick-key-test' request["backtick-value-test"] = '`' +request["$"] = 'dollar-key-test' request["dollar-parenthesis-value-test"] = '$(' +request["#"] = 'hash-key-test' request["hash-brace-value-test"] = '#{' +request["%"] = 'percent-key-test' request["percent-parenthesis-value-test"] = '%(' request["percent-brace-value-test"] = '%{' request["double-brace-value-test"] = '{{' diff --git a/test/fixtures/output/shell/curl/malicious.sh b/test/fixtures/output/shell/curl/malicious.sh index 19c1c8d..ee64132 100644 --- a/test/fixtures/output/shell/curl/malicious.sh +++ b/test/fixtures/output/shell/curl/malicious.sh @@ -1,5 +1,10 @@ curl --request POST \ --url 'http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//?'\''=squote-key-test&squote-value-test='\''&%22=dquote-key-test&dquote-value-test=%22&%60=backtick-key-test&backtick-value-test=%60&%24(=dollar-parenthesis-key-test&dollar-parenthesis-value-test=%24(&%23%7B=hash-brace-key-test&hash-brace-value-test=%23%7B&%25(=percent-parenthesis-key-test&percent-parenthesis-value-test=%25(&%25%7B=percent-brace-key-test&percent-brace-value-test=%25%7B&%7B%7B=double-brace-key-test&double-brace-value-test=%7B%7B&%5C0=null-key-test&null-value-test=%5C0&%25s=string-fmt-key-test&string-fmt-value-test=%25s&%5C=slash-key-test&slash-value-test=%5C' \ + --header '#: hash-key-test' \ + --header '$: dollar-key-test' \ + --header '%: percent-key-test' \ + --header ''\'': squote-key-test' \ + --header '`: backtick-key-test' \ --header 'backtick-value-test: `' \ --header 'dollar-parenthesis-value-test: $(' \ --header 'double-brace-value-test: {{' \ diff --git a/test/fixtures/output/shell/httpie/application-json.sh b/test/fixtures/output/shell/httpie/application-json.sh index 073a258..979ef3a 100644 --- a/test/fixtures/output/shell/httpie/application-json.sh +++ b/test/fixtures/output/shell/httpie/application-json.sh @@ -1,3 +1,3 @@ -echo '{"number":1,"string":"f\"oo","arr":[1,2,3],"nested":{"a":"b"},"arr_mix":[1,"a",{"arr_mix_nested":{}}],"boolean":false}' | \ +printf '%s' '{"number":1,"string":"f\"oo","arr":[1,2,3],"nested":{"a":"b"},"arr_mix":[1,"a",{"arr_mix_nested":{}}],"boolean":false}' | \ http POST http://mockbin.com/har \ content-type:application/json diff --git a/test/fixtures/output/shell/httpie/malicious.sh b/test/fixtures/output/shell/httpie/malicious.sh index 5a44864..e9e64d3 100644 --- a/test/fixtures/output/shell/httpie/malicious.sh +++ b/test/fixtures/output/shell/httpie/malicious.sh @@ -1,5 +1,10 @@ -echo ''\'' " ` $( #{ %( %{ {{ \0 %s \' | \ +printf '%s' ''\'' " ` $( #{ %( %{ {{ \0 %s \' | \ http POST 'http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//?'\''=squote-key-test&squote-value-test='\''&%22=dquote-key-test&dquote-value-test=%22&%60=backtick-key-test&backtick-value-test=%60&%24(=dollar-parenthesis-key-test&dollar-parenthesis-value-test=%24(&%23%7B=hash-brace-key-test&hash-brace-value-test=%23%7B&%25(=percent-parenthesis-key-test&percent-parenthesis-value-test=%25(&%25%7B=percent-brace-key-test&percent-brace-value-test=%25%7B&%7B%7B=double-brace-key-test&double-brace-value-test=%7B%7B&%5C0=null-key-test&null-value-test=%5C0&%25s=string-fmt-key-test&string-fmt-value-test=%25s&%5C=slash-key-test&slash-value-test=%5C' \ + '#':hash-key-test \ + '$':dollar-key-test \ + %:percent-key-test \ + ''\''':squote-key-test \ + '`':backtick-key-test \ backtick-value-test:'`' \ dollar-parenthesis-value-test:'$(' \ double-brace-value-test:'{{' \ diff --git a/test/fixtures/output/shell/wget/malicious.sh b/test/fixtures/output/shell/wget/malicious.sh index cdd5905..3649342 100644 --- a/test/fixtures/output/shell/wget/malicious.sh +++ b/test/fixtures/output/shell/wget/malicious.sh @@ -1,10 +1,15 @@ wget --quiet \ --method POST \ + --header ''\'': squote-key-test' \ --header 'squote-value-test: '\''' \ --header 'dquote-value-test: "' \ + --header '`: backtick-key-test' \ --header 'backtick-value-test: `' \ + --header '$: dollar-key-test' \ --header 'dollar-parenthesis-value-test: $(' \ + --header '#: hash-key-test' \ --header 'hash-brace-value-test: #{' \ + --header '%: percent-key-test' \ --header 'percent-parenthesis-value-test: %(' \ --header 'percent-brace-value-test: %{' \ --header 'double-brace-value-test: {{' \ diff --git a/test/fixtures/output/swift/nsurlsession/malicious.swift b/test/fixtures/output/swift/nsurlsession/malicious.swift index a6c5ff6..7dd4777 100644 --- a/test/fixtures/output/swift/nsurlsession/malicious.swift +++ b/test/fixtures/output/swift/nsurlsession/malicious.swift @@ -1,11 +1,16 @@ import Foundation let headers = [ + "'": "squote-key-test", "squote-value-test": "'", "dquote-value-test": "\"", + "`": "backtick-key-test", "backtick-value-test": "`", + "$": "dollar-key-test", "dollar-parenthesis-value-test": "$(", + "#": "hash-key-test", "hash-brace-value-test": "#{", + "%": "percent-key-test", "percent-parenthesis-value-test": "%(", "percent-brace-value-test": "%{", "double-brace-value-test": "{{", diff --git a/test/fixtures/requests/malicious.json b/test/fixtures/requests/malicious.json index 1ad354e..a701153 100644 --- a/test/fixtures/requests/malicious.json +++ b/test/fixtures/requests/malicious.json @@ -92,6 +92,10 @@ } ], "headers": [ + { + "name": "'", + "value": "squote-key-test" + }, { "name": "squote-value-test", "value": "'" @@ -100,18 +104,34 @@ "name": "dquote-value-test", "value": "\"" }, + { + "name": "`", + "value": "backtick-key-test" + }, { "name": "backtick-value-test", "value": "`" }, + { + "name": "$", + "value": "dollar-key-test" + }, { "name": "dollar-parenthesis-value-test", "value": "$(" }, + { + "name": "#", + "value": "hash-key-test" + }, { "name": "hash-brace-value-test", "value": "#{" }, + { + "name": "%", + "value": "percent-key-test" + }, { "name": "percent-parenthesis-value-test", "value": "%(" From 22e5a6e90e5171087ff424b699cf03ed9780ce38 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Tue, 2 Jul 2024 20:02:49 +0200 Subject: [PATCH 03/36] 2.1.6 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8fa7a4c..53bc2c6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@httptoolkit/httpsnippet", - "version": "2.1.5", + "version": "2.1.6", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@httptoolkit/httpsnippet", - "version": "2.1.5", + "version": "2.1.6", "license": "MIT", "dependencies": { "chalk": "^1.1.1", diff --git a/package.json b/package.json index 26f3424..4e026a8 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "2.1.5", + "version": "2.1.6", "name": "@httptoolkit/httpsnippet", "description": "HTTP request snippet generator for *most* languages", "author": "Tim Perry ", From bf61e2e54778e7ba83a5de7c83e4887bb7ab12c4 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Fri, 19 Jul 2024 20:48:06 +0100 Subject: [PATCH 04/36] Fix issue with $ interpolation in PHP curl snippets --- src/targets/php/curl.js | 20 ++++++--- src/targets/php/helpers.js | 6 ++- .../php/curl/application-form-encoded.php | 12 +++--- .../output/php/curl/application-json.php | 12 +++--- test/fixtures/output/php/curl/compression.php | 10 ++--- test/fixtures/output/php/curl/cookies.php | 10 ++--- .../output/php/curl/custom-method.php | 8 ++-- test/fixtures/output/php/curl/full.php | 16 +++---- test/fixtures/output/php/curl/headers.php | 14 +++---- test/fixtures/output/php/curl/https.php | 8 ++-- .../output/php/curl/jsonObj-multiline.php | 14 ++++--- .../output/php/curl/jsonObj-null-value.php | 12 +++--- test/fixtures/output/php/curl/malicious.php | 42 +++++++++---------- .../output/php/curl/multipart-data.php | 18 +++++--- .../output/php/curl/multipart-file.php | 18 +++++--- .../output/php/curl/multipart-form-data.php | 17 +++++--- test/fixtures/output/php/curl/nested.php | 8 ++-- test/fixtures/output/php/curl/query.php | 8 ++-- test/fixtures/output/php/curl/short.php | 8 ++-- test/fixtures/output/php/curl/text-plain.php | 12 +++--- 20 files changed, 152 insertions(+), 121 deletions(-) diff --git a/src/targets/php/curl.js b/src/targets/php/curl.js index 50a2e0f..37a5d82 100644 --- a/src/targets/php/curl.js +++ b/src/targets/php/curl.js @@ -12,6 +12,7 @@ const { format } = require('../../helpers/format') const CodeBuilder = require('../../helpers/code-builder') +const { phpSqEscape } = require('./helpers') module.exports = function (source, options) { const opts = Object.assign({ @@ -78,7 +79,16 @@ module.exports = function (source, options) { curlOptions.forEach(function (option) { if (!~[null, undefined].indexOf(option.value)) { - curlopts.push(format('%s => %s,', option.name, option.escape ? JSON.stringify(option.value) : option.value)) + curlopts.push( + format('%s => %s,', + option.name, + option.escape && typeof option.value === 'string' + ? `'${phpSqEscape(option.value)}'` + : option.escape + ? JSON.stringify(option.value) + : option.value + ) + ) } }) @@ -88,12 +98,12 @@ module.exports = function (source, options) { }) if (cookies.length) { - curlopts.push(format('CURLOPT_COOKIE => "%s",', cookies.join('; '))) + curlopts.push(format("CURLOPT_COOKIE => '%s'", phpSqEscape(cookies.join('; ')))) } // construct cookies const headers = Object.keys(source.headersObj).sort().map(function (key) { - return format('"%s: %qd"', key, source.headersObj[key]) + return format("'%s: %s'", phpSqEscape(key), phpSqEscape(source.headersObj[key])) }) if (headers.length) { @@ -113,9 +123,9 @@ module.exports = function (source, options) { .push('if ($err) {') if (opts.namedErrors) { - code.push(1, 'echo array_flip(get_defined_constants(true)["curl"])[$err];') + code.push(1, "echo array_flip(get_defined_constants(true)['curl'])[$err];") } else { - code.push(1, 'echo "cURL Error #:" . $err;') + code.push(1, "echo 'cURL Error #:' . $err;") } code.push('} else {') diff --git a/src/targets/php/helpers.js b/src/targets/php/helpers.js index 0e833fa..c1dffd0 100644 --- a/src/targets/php/helpers.js +++ b/src/targets/php/helpers.js @@ -1,6 +1,7 @@ 'use strict' -const { escape } = require('../../helpers/format') +// PHP single quotes are super simple - all escapes ignored except sq & slash +const phpSqEscape = val => val.replace(/\\/g, '\\\\').replace(/'/g, "\\'") const convert = function (obj, indent, lastIndent) { let i, result @@ -19,7 +20,7 @@ const convert = function (obj, indent, lastIndent) { break case '[object String]': - result = "'" + escape(obj, { delimiter: "'", escapeNewlines: false }) + "'" + result = "'" + phpSqEscape(obj) + "'" break case '[object Number]': @@ -55,6 +56,7 @@ const convert = function (obj, indent, lastIndent) { } module.exports = { + phpSqEscape: phpSqEscape, convert: convert, methods: [ 'ACL', diff --git a/test/fixtures/output/php/curl/application-form-encoded.php b/test/fixtures/output/php/curl/application-form-encoded.php index 0892dd3..47114c3 100644 --- a/test/fixtures/output/php/curl/application-form-encoded.php +++ b/test/fixtures/output/php/curl/application-form-encoded.php @@ -3,16 +3,16 @@ $curl = curl_init(); curl_setopt_array($curl, [ - CURLOPT_URL => "http://mockbin.com/har", + CURLOPT_URL => 'http://mockbin.com/har', CURLOPT_RETURNTRANSFER => true, - CURLOPT_ENCODING => "", + CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, - CURLOPT_CUSTOMREQUEST => "POST", - CURLOPT_POSTFIELDS => "foo=bar&hello=world", + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_POSTFIELDS => 'foo=bar&hello=world', CURLOPT_HTTPHEADER => [ - "content-type: application/x-www-form-urlencoded" + 'content-type: application/x-www-form-urlencoded' ], ]); @@ -22,7 +22,7 @@ curl_close($curl); if ($err) { - echo "cURL Error #:" . $err; + echo 'cURL Error #:' . $err; } else { echo $response; } diff --git a/test/fixtures/output/php/curl/application-json.php b/test/fixtures/output/php/curl/application-json.php index 8a0f0c1..e80ff42 100644 --- a/test/fixtures/output/php/curl/application-json.php +++ b/test/fixtures/output/php/curl/application-json.php @@ -3,16 +3,16 @@ $curl = curl_init(); curl_setopt_array($curl, [ - CURLOPT_URL => "http://mockbin.com/har", + CURLOPT_URL => 'http://mockbin.com/har', CURLOPT_RETURNTRANSFER => true, - CURLOPT_ENCODING => "", + CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, - CURLOPT_CUSTOMREQUEST => "POST", - CURLOPT_POSTFIELDS => "{\"number\":1,\"string\":\"f\\\"oo\",\"arr\":[1,2,3],\"nested\":{\"a\":\"b\"},\"arr_mix\":[1,\"a\",{\"arr_mix_nested\":{}}],\"boolean\":false}", + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_POSTFIELDS => '{"number":1,"string":"f\\"oo","arr":[1,2,3],"nested":{"a":"b"},"arr_mix":[1,"a",{"arr_mix_nested":{}}],"boolean":false}', CURLOPT_HTTPHEADER => [ - "content-type: application/json" + 'content-type: application/json' ], ]); @@ -22,7 +22,7 @@ curl_close($curl); if ($err) { - echo "cURL Error #:" . $err; + echo 'cURL Error #:' . $err; } else { echo $response; } diff --git a/test/fixtures/output/php/curl/compression.php b/test/fixtures/output/php/curl/compression.php index 6bf18d4..bfc0378 100644 --- a/test/fixtures/output/php/curl/compression.php +++ b/test/fixtures/output/php/curl/compression.php @@ -3,15 +3,15 @@ $curl = curl_init(); curl_setopt_array($curl, [ - CURLOPT_URL => "http://mockbin.com/har", + CURLOPT_URL => 'http://mockbin.com/har', CURLOPT_RETURNTRANSFER => true, - CURLOPT_ENCODING => "", + CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, - CURLOPT_CUSTOMREQUEST => "GET", + CURLOPT_CUSTOMREQUEST => 'GET', CURLOPT_HTTPHEADER => [ - "accept-encoding: deflate, gzip, br" + 'accept-encoding: deflate, gzip, br' ], ]); @@ -21,7 +21,7 @@ curl_close($curl); if ($err) { - echo "cURL Error #:" . $err; + echo 'cURL Error #:' . $err; } else { echo $response; } \ No newline at end of file diff --git a/test/fixtures/output/php/curl/cookies.php b/test/fixtures/output/php/curl/cookies.php index 2810430..c604973 100644 --- a/test/fixtures/output/php/curl/cookies.php +++ b/test/fixtures/output/php/curl/cookies.php @@ -3,14 +3,14 @@ $curl = curl_init(); curl_setopt_array($curl, [ - CURLOPT_URL => "http://mockbin.com/har", + CURLOPT_URL => 'http://mockbin.com/har', CURLOPT_RETURNTRANSFER => true, - CURLOPT_ENCODING => "", + CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, - CURLOPT_CUSTOMREQUEST => "POST", - CURLOPT_COOKIE => "foo=bar; bar=baz", + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_COOKIE => 'foo=bar; bar=baz' ]); $response = curl_exec($curl); @@ -19,7 +19,7 @@ curl_close($curl); if ($err) { - echo "cURL Error #:" . $err; + echo 'cURL Error #:' . $err; } else { echo $response; } diff --git a/test/fixtures/output/php/curl/custom-method.php b/test/fixtures/output/php/curl/custom-method.php index 08aa597..16e6d57 100644 --- a/test/fixtures/output/php/curl/custom-method.php +++ b/test/fixtures/output/php/curl/custom-method.php @@ -3,13 +3,13 @@ $curl = curl_init(); curl_setopt_array($curl, [ - CURLOPT_URL => "http://mockbin.com/har", + CURLOPT_URL => 'http://mockbin.com/har', CURLOPT_RETURNTRANSFER => true, - CURLOPT_ENCODING => "", + CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, - CURLOPT_CUSTOMREQUEST => "PROPFIND", + CURLOPT_CUSTOMREQUEST => 'PROPFIND', ]); $response = curl_exec($curl); @@ -18,7 +18,7 @@ curl_close($curl); if ($err) { - echo "cURL Error #:" . $err; + echo 'cURL Error #:' . $err; } else { echo $response; } diff --git a/test/fixtures/output/php/curl/full.php b/test/fixtures/output/php/curl/full.php index 6f342b6..ee1aaee 100644 --- a/test/fixtures/output/php/curl/full.php +++ b/test/fixtures/output/php/curl/full.php @@ -3,18 +3,18 @@ $curl = curl_init(); curl_setopt_array($curl, [ - CURLOPT_URL => "http://mockbin.com/har?foo=bar&foo=baz&baz=abc&key=value", + CURLOPT_URL => 'http://mockbin.com/har?foo=bar&foo=baz&baz=abc&key=value', CURLOPT_RETURNTRANSFER => true, - CURLOPT_ENCODING => "", + CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, - CURLOPT_CUSTOMREQUEST => "POST", - CURLOPT_POSTFIELDS => "foo=bar", - CURLOPT_COOKIE => "foo=bar; bar=baz", + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_POSTFIELDS => 'foo=bar', + CURLOPT_COOKIE => 'foo=bar; bar=baz' CURLOPT_HTTPHEADER => [ - "accept: application/json", - "content-type: application/x-www-form-urlencoded" + 'accept: application/json', + 'content-type: application/x-www-form-urlencoded' ], ]); @@ -24,7 +24,7 @@ curl_close($curl); if ($err) { - echo "cURL Error #:" . $err; + echo 'cURL Error #:' . $err; } else { echo $response; } diff --git a/test/fixtures/output/php/curl/headers.php b/test/fixtures/output/php/curl/headers.php index d0d4bb7..42dfe33 100644 --- a/test/fixtures/output/php/curl/headers.php +++ b/test/fixtures/output/php/curl/headers.php @@ -3,17 +3,17 @@ $curl = curl_init(); curl_setopt_array($curl, [ - CURLOPT_URL => "http://mockbin.com/har", + CURLOPT_URL => 'http://mockbin.com/har', CURLOPT_RETURNTRANSFER => true, - CURLOPT_ENCODING => "", + CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, - CURLOPT_CUSTOMREQUEST => "GET", + CURLOPT_CUSTOMREQUEST => 'GET', CURLOPT_HTTPHEADER => [ - "accept: application/json", - "quoted-value: \"quoted\" 'string'", - "x-foo: Bar" + 'accept: application/json', + 'quoted-value: "quoted" \'string\'', + 'x-foo: Bar' ], ]); @@ -23,7 +23,7 @@ curl_close($curl); if ($err) { - echo "cURL Error #:" . $err; + echo 'cURL Error #:' . $err; } else { echo $response; } diff --git a/test/fixtures/output/php/curl/https.php b/test/fixtures/output/php/curl/https.php index 7d97476..bef4757 100644 --- a/test/fixtures/output/php/curl/https.php +++ b/test/fixtures/output/php/curl/https.php @@ -3,13 +3,13 @@ $curl = curl_init(); curl_setopt_array($curl, [ - CURLOPT_URL => "https://mockbin.com/har", + CURLOPT_URL => 'https://mockbin.com/har', CURLOPT_RETURNTRANSFER => true, - CURLOPT_ENCODING => "", + CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, - CURLOPT_CUSTOMREQUEST => "GET", + CURLOPT_CUSTOMREQUEST => 'GET', ]); $response = curl_exec($curl); @@ -18,7 +18,7 @@ curl_close($curl); if ($err) { - echo "cURL Error #:" . $err; + echo 'cURL Error #:' . $err; } else { echo $response; } diff --git a/test/fixtures/output/php/curl/jsonObj-multiline.php b/test/fixtures/output/php/curl/jsonObj-multiline.php index 19f7727..2c5d836 100644 --- a/test/fixtures/output/php/curl/jsonObj-multiline.php +++ b/test/fixtures/output/php/curl/jsonObj-multiline.php @@ -3,16 +3,18 @@ $curl = curl_init(); curl_setopt_array($curl, [ - CURLOPT_URL => "http://mockbin.com/har", + CURLOPT_URL => 'http://mockbin.com/har', CURLOPT_RETURNTRANSFER => true, - CURLOPT_ENCODING => "", + CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, - CURLOPT_CUSTOMREQUEST => "POST", - CURLOPT_POSTFIELDS => "{\n \"foo\": \"bar\"\n}", + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_POSTFIELDS => '{ + "foo": "bar" +}', CURLOPT_HTTPHEADER => [ - "content-type: application/json" + 'content-type: application/json' ], ]); @@ -22,7 +24,7 @@ curl_close($curl); if ($err) { - echo "cURL Error #:" . $err; + echo 'cURL Error #:' . $err; } else { echo $response; } diff --git a/test/fixtures/output/php/curl/jsonObj-null-value.php b/test/fixtures/output/php/curl/jsonObj-null-value.php index 99a2289..68fee65 100644 --- a/test/fixtures/output/php/curl/jsonObj-null-value.php +++ b/test/fixtures/output/php/curl/jsonObj-null-value.php @@ -3,16 +3,16 @@ $curl = curl_init(); curl_setopt_array($curl, [ - CURLOPT_URL => "http://mockbin.com/har", + CURLOPT_URL => 'http://mockbin.com/har', CURLOPT_RETURNTRANSFER => true, - CURLOPT_ENCODING => "", + CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, - CURLOPT_CUSTOMREQUEST => "POST", - CURLOPT_POSTFIELDS => "{\"foo\":null}", + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_POSTFIELDS => '{"foo":null}', CURLOPT_HTTPHEADER => [ - "content-type: application/json" + 'content-type: application/json' ], ]); @@ -22,7 +22,7 @@ curl_close($curl); if ($err) { - echo "cURL Error #:" . $err; + echo 'cURL Error #:' . $err; } else { echo $response; } diff --git a/test/fixtures/output/php/curl/malicious.php b/test/fixtures/output/php/curl/malicious.php index 11012f6..6418f5c 100644 --- a/test/fixtures/output/php/curl/malicious.php +++ b/test/fixtures/output/php/curl/malicious.php @@ -3,31 +3,31 @@ $curl = curl_init(); curl_setopt_array($curl, [ - CURLOPT_URL => "http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//?'=squote-key-test&squote-value-test='&%22=dquote-key-test&dquote-value-test=%22&%60=backtick-key-test&backtick-value-test=%60&%24(=dollar-parenthesis-key-test&dollar-parenthesis-value-test=%24(&%23%7B=hash-brace-key-test&hash-brace-value-test=%23%7B&%25(=percent-parenthesis-key-test&percent-parenthesis-value-test=%25(&%25%7B=percent-brace-key-test&percent-brace-value-test=%25%7B&%7B%7B=double-brace-key-test&double-brace-value-test=%7B%7B&%5C0=null-key-test&null-value-test=%5C0&%25s=string-fmt-key-test&string-fmt-value-test=%25s&%5C=slash-key-test&slash-value-test=%5C", + CURLOPT_URL => 'http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//?\'=squote-key-test&squote-value-test=\'&%22=dquote-key-test&dquote-value-test=%22&%60=backtick-key-test&backtick-value-test=%60&%24(=dollar-parenthesis-key-test&dollar-parenthesis-value-test=%24(&%23%7B=hash-brace-key-test&hash-brace-value-test=%23%7B&%25(=percent-parenthesis-key-test&percent-parenthesis-value-test=%25(&%25%7B=percent-brace-key-test&percent-brace-value-test=%25%7B&%7B%7B=double-brace-key-test&double-brace-value-test=%7B%7B&%5C0=null-key-test&null-value-test=%5C0&%25s=string-fmt-key-test&string-fmt-value-test=%25s&%5C=slash-key-test&slash-value-test=%5C', CURLOPT_RETURNTRANSFER => true, - CURLOPT_ENCODING => "", + CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, - CURLOPT_CUSTOMREQUEST => "POST", - CURLOPT_POSTFIELDS => "' \" ` $( #{ %( %{ {{ \\0 %s \\", + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_POSTFIELDS => '\' " ` $( #{ %( %{ {{ \\0 %s \\', CURLOPT_HTTPHEADER => [ - "#: hash-key-test", - "$: dollar-key-test", - "%: percent-key-test", - "': squote-key-test", - "`: backtick-key-test", - "backtick-value-test: `", - "dollar-parenthesis-value-test: $(", - "double-brace-value-test: {{", - "dquote-value-test: \"", - "hash-brace-value-test: #{", - "null-value-test: \\0", - "percent-brace-value-test: %{", - "percent-parenthesis-value-test: %(", - "slash-value-test: \\", - "squote-value-test: '", - "string-fmt-value-test: %s" + '#: hash-key-test', + '$: dollar-key-test', + '%: percent-key-test', + '\': squote-key-test', + '`: backtick-key-test', + 'backtick-value-test: `', + 'dollar-parenthesis-value-test: $(', + 'double-brace-value-test: {{', + 'dquote-value-test: "', + 'hash-brace-value-test: #{', + 'null-value-test: \\0', + 'percent-brace-value-test: %{', + 'percent-parenthesis-value-test: %(', + 'slash-value-test: \\', + 'squote-value-test: \'', + 'string-fmt-value-test: %s' ], ]); @@ -37,7 +37,7 @@ curl_close($curl); if ($err) { - echo "cURL Error #:" . $err; + echo 'cURL Error #:' . $err; } else { echo $response; } \ No newline at end of file diff --git a/test/fixtures/output/php/curl/multipart-data.php b/test/fixtures/output/php/curl/multipart-data.php index d6ce07f..4f91074 100644 --- a/test/fixtures/output/php/curl/multipart-data.php +++ b/test/fixtures/output/php/curl/multipart-data.php @@ -3,16 +3,22 @@ $curl = curl_init(); curl_setopt_array($curl, [ - CURLOPT_URL => "http://mockbin.com/har", + CURLOPT_URL => 'http://mockbin.com/har', CURLOPT_RETURNTRANSFER => true, - CURLOPT_ENCODING => "", + CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, - CURLOPT_CUSTOMREQUEST => "POST", - CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"; filename=\"hello.txt\"\r\nContent-Type: text/plain\r\n\r\nHello World\r\n-----011000010111000001101001--\r\n", + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_POSTFIELDS => '-----011000010111000001101001 +Content-Disposition: form-data; name="foo"; filename="hello.txt" +Content-Type: text/plain + +Hello World +-----011000010111000001101001-- +', CURLOPT_HTTPHEADER => [ - "content-type: multipart/form-data; boundary=---011000010111000001101001" + 'content-type: multipart/form-data; boundary=---011000010111000001101001' ], ]); @@ -22,7 +28,7 @@ curl_close($curl); if ($err) { - echo "cURL Error #:" . $err; + echo 'cURL Error #:' . $err; } else { echo $response; } diff --git a/test/fixtures/output/php/curl/multipart-file.php b/test/fixtures/output/php/curl/multipart-file.php index e238b8e..129b9d2 100644 --- a/test/fixtures/output/php/curl/multipart-file.php +++ b/test/fixtures/output/php/curl/multipart-file.php @@ -3,16 +3,22 @@ $curl = curl_init(); curl_setopt_array($curl, [ - CURLOPT_URL => "http://mockbin.com/har", + CURLOPT_URL => 'http://mockbin.com/har', CURLOPT_RETURNTRANSFER => true, - CURLOPT_ENCODING => "", + CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, - CURLOPT_CUSTOMREQUEST => "POST", - CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"; filename=\"hello.txt\"\r\nContent-Type: text/plain\r\n\r\n\r\n-----011000010111000001101001--\r\n", + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_POSTFIELDS => '-----011000010111000001101001 +Content-Disposition: form-data; name="foo"; filename="hello.txt" +Content-Type: text/plain + + +-----011000010111000001101001-- +', CURLOPT_HTTPHEADER => [ - "content-type: multipart/form-data; boundary=---011000010111000001101001" + 'content-type: multipart/form-data; boundary=---011000010111000001101001' ], ]); @@ -22,7 +28,7 @@ curl_close($curl); if ($err) { - echo "cURL Error #:" . $err; + echo 'cURL Error #:' . $err; } else { echo $response; } diff --git a/test/fixtures/output/php/curl/multipart-form-data.php b/test/fixtures/output/php/curl/multipart-form-data.php index 038aa49..17e5a9d 100644 --- a/test/fixtures/output/php/curl/multipart-form-data.php +++ b/test/fixtures/output/php/curl/multipart-form-data.php @@ -3,16 +3,21 @@ $curl = curl_init(); curl_setopt_array($curl, [ - CURLOPT_URL => "http://mockbin.com/har", + CURLOPT_URL => 'http://mockbin.com/har', CURLOPT_RETURNTRANSFER => true, - CURLOPT_ENCODING => "", + CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, - CURLOPT_CUSTOMREQUEST => "POST", - CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"\r\n\r\nbar\r\n-----011000010111000001101001--\r\n", + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_POSTFIELDS => '-----011000010111000001101001 +Content-Disposition: form-data; name="foo" + +bar +-----011000010111000001101001-- +', CURLOPT_HTTPHEADER => [ - "Content-Type: multipart/form-data; boundary=---011000010111000001101001" + 'Content-Type: multipart/form-data; boundary=---011000010111000001101001' ], ]); @@ -22,7 +27,7 @@ curl_close($curl); if ($err) { - echo "cURL Error #:" . $err; + echo 'cURL Error #:' . $err; } else { echo $response; } diff --git a/test/fixtures/output/php/curl/nested.php b/test/fixtures/output/php/curl/nested.php index 9b345ab..28161a8 100644 --- a/test/fixtures/output/php/curl/nested.php +++ b/test/fixtures/output/php/curl/nested.php @@ -3,13 +3,13 @@ $curl = curl_init(); curl_setopt_array($curl, [ - CURLOPT_URL => "http://mockbin.com/har?foo%5Bbar%5D=baz%2Czap&fiz=buz&key=value", + CURLOPT_URL => 'http://mockbin.com/har?foo%5Bbar%5D=baz%2Czap&fiz=buz&key=value', CURLOPT_RETURNTRANSFER => true, - CURLOPT_ENCODING => "", + CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, - CURLOPT_CUSTOMREQUEST => "GET", + CURLOPT_CUSTOMREQUEST => 'GET', ]); $response = curl_exec($curl); @@ -18,7 +18,7 @@ curl_close($curl); if ($err) { - echo "cURL Error #:" . $err; + echo 'cURL Error #:' . $err; } else { echo $response; } diff --git a/test/fixtures/output/php/curl/query.php b/test/fixtures/output/php/curl/query.php index 158e851..a799eb8 100644 --- a/test/fixtures/output/php/curl/query.php +++ b/test/fixtures/output/php/curl/query.php @@ -3,13 +3,13 @@ $curl = curl_init(); curl_setopt_array($curl, [ - CURLOPT_URL => "http://mockbin.com/har?foo=bar&foo=baz&baz=abc&key=value", + CURLOPT_URL => 'http://mockbin.com/har?foo=bar&foo=baz&baz=abc&key=value', CURLOPT_RETURNTRANSFER => true, - CURLOPT_ENCODING => "", + CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, - CURLOPT_CUSTOMREQUEST => "GET", + CURLOPT_CUSTOMREQUEST => 'GET', ]); $response = curl_exec($curl); @@ -18,7 +18,7 @@ curl_close($curl); if ($err) { - echo "cURL Error #:" . $err; + echo 'cURL Error #:' . $err; } else { echo $response; } diff --git a/test/fixtures/output/php/curl/short.php b/test/fixtures/output/php/curl/short.php index 9188e25..9f81196 100644 --- a/test/fixtures/output/php/curl/short.php +++ b/test/fixtures/output/php/curl/short.php @@ -3,13 +3,13 @@ $curl = curl_init(); curl_setopt_array($curl, [ - CURLOPT_URL => "http://mockbin.com/har", + CURLOPT_URL => 'http://mockbin.com/har', CURLOPT_RETURNTRANSFER => true, - CURLOPT_ENCODING => "", + CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, - CURLOPT_CUSTOMREQUEST => "GET", + CURLOPT_CUSTOMREQUEST => 'GET', ]); $response = curl_exec($curl); @@ -18,7 +18,7 @@ curl_close($curl); if ($err) { - echo "cURL Error #:" . $err; + echo 'cURL Error #:' . $err; } else { echo $response; } diff --git a/test/fixtures/output/php/curl/text-plain.php b/test/fixtures/output/php/curl/text-plain.php index 8fbb09d..999c5c0 100644 --- a/test/fixtures/output/php/curl/text-plain.php +++ b/test/fixtures/output/php/curl/text-plain.php @@ -3,16 +3,16 @@ $curl = curl_init(); curl_setopt_array($curl, [ - CURLOPT_URL => "http://mockbin.com/har", + CURLOPT_URL => 'http://mockbin.com/har', CURLOPT_RETURNTRANSFER => true, - CURLOPT_ENCODING => "", + CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, - CURLOPT_CUSTOMREQUEST => "POST", - CURLOPT_POSTFIELDS => "Hello World", + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_POSTFIELDS => 'Hello World', CURLOPT_HTTPHEADER => [ - "content-type: text/plain" + 'content-type: text/plain' ], ]); @@ -22,7 +22,7 @@ curl_close($curl); if ($err) { - echo "cURL Error #:" . $err; + echo 'cURL Error #:' . $err; } else { echo $response; } From d21b2250ac420c18e6298109da35b883bc4dcefa Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Fri, 19 Jul 2024 21:23:19 +0100 Subject: [PATCH 05/36] Preserve non-standard/unparseable query strings as-is in snippet output This is particularly notable for cases like the &&& repro here, but is also clearly visible in cases like ?a=b&c, which would often become something more like '?a=b&c='. This only applies when the queryString in the HAR is empty, which will be rare, but HTTP Toolkit (and others) can use this to leave that blank and send only the raw URL to preserve formatting at the cost of the losing the nice structure query param setting code in the output. --- src/index.js | 37 ++++++++++++------- .../output/c/libcurl/unparseable-query.c | 6 +++ .../clojure/clj_http/unparseable-query.clj | 3 ++ .../csharp/httpclient/unparseable-query.cs | 12 ++++++ .../csharp/restsharp/unparseable-query.cs | 3 ++ .../output/go/native/unparseable-query.go | 23 ++++++++++++ .../output/http/1.1/unparseable-query | 2 + .../java/asynchttp/unparseable-query.java | 8 ++++ .../java/nethttp/unparseable-query.java | 6 +++ .../output/java/okhttp/unparseable-query.java | 8 ++++ .../java/unirest/unparseable-query.java | 2 + .../javascript/axios/unparseable-query.js | 9 +++++ .../javascript/fetch/unparseable-query.js | 6 +++ .../javascript/jquery/unparseable-query.js | 11 ++++++ .../javascript/xhr/unparseable-query.js | 14 +++++++ .../output/kotlin/okhttp/unparseable-query.kt | 8 ++++ .../output/node/axios/unparseable-query.js | 9 +++++ .../output/node/fetch/unparseable-query.js | 10 +++++ .../output/node/native/unparseable-query.js | 24 ++++++++++++ .../output/node/request/unparseable-query.js | 9 +++++ .../output/node/unirest/unparseable-query.js | 9 +++++ .../objc/nsurlsession/unparseable-query.m | 18 +++++++++ .../output/ocaml/cohttp/unparseable-query.ml | 9 +++++ .../output/php/curl/unparseable-query.php | 24 ++++++++++++ .../output/php/http1/unparseable-query.php | 13 +++++++ .../output/php/http2/unparseable-query.php | 11 ++++++ .../restmethod/unparseable-query.ps1 | 1 + .../webrequest/unparseable-query.ps1 | 1 + .../python/python3/unparseable-query.py | 10 +++++ .../python/requests/unparseable-query.py | 7 ++++ .../output/r/httr/unparseable-query.r | 7 ++++ .../output/ruby/native/unparseable-query.rb | 11 ++++++ .../output/shell/curl/unparseable-query.sh | 2 + .../output/shell/httpie/unparseable-query.sh | 1 + .../output/shell/wget/unparseable-query.sh | 4 ++ .../nsurlsession/unparseable-query.swift | 18 +++++++++ test/fixtures/requests/unparseable-query.json | 6 +++ 37 files changed, 348 insertions(+), 14 deletions(-) create mode 100644 test/fixtures/output/c/libcurl/unparseable-query.c create mode 100644 test/fixtures/output/clojure/clj_http/unparseable-query.clj create mode 100644 test/fixtures/output/csharp/httpclient/unparseable-query.cs create mode 100644 test/fixtures/output/csharp/restsharp/unparseable-query.cs create mode 100644 test/fixtures/output/go/native/unparseable-query.go create mode 100644 test/fixtures/output/http/1.1/unparseable-query create mode 100644 test/fixtures/output/java/asynchttp/unparseable-query.java create mode 100644 test/fixtures/output/java/nethttp/unparseable-query.java create mode 100644 test/fixtures/output/java/okhttp/unparseable-query.java create mode 100644 test/fixtures/output/java/unirest/unparseable-query.java create mode 100644 test/fixtures/output/javascript/axios/unparseable-query.js create mode 100644 test/fixtures/output/javascript/fetch/unparseable-query.js create mode 100644 test/fixtures/output/javascript/jquery/unparseable-query.js create mode 100644 test/fixtures/output/javascript/xhr/unparseable-query.js create mode 100644 test/fixtures/output/kotlin/okhttp/unparseable-query.kt create mode 100644 test/fixtures/output/node/axios/unparseable-query.js create mode 100644 test/fixtures/output/node/fetch/unparseable-query.js create mode 100644 test/fixtures/output/node/native/unparseable-query.js create mode 100644 test/fixtures/output/node/request/unparseable-query.js create mode 100644 test/fixtures/output/node/unirest/unparseable-query.js create mode 100644 test/fixtures/output/objc/nsurlsession/unparseable-query.m create mode 100644 test/fixtures/output/ocaml/cohttp/unparseable-query.ml create mode 100644 test/fixtures/output/php/curl/unparseable-query.php create mode 100644 test/fixtures/output/php/http1/unparseable-query.php create mode 100644 test/fixtures/output/php/http2/unparseable-query.php create mode 100644 test/fixtures/output/powershell/restmethod/unparseable-query.ps1 create mode 100644 test/fixtures/output/powershell/webrequest/unparseable-query.ps1 create mode 100644 test/fixtures/output/python/python3/unparseable-query.py create mode 100644 test/fixtures/output/python/requests/unparseable-query.py create mode 100644 test/fixtures/output/r/httr/unparseable-query.r create mode 100644 test/fixtures/output/ruby/native/unparseable-query.rb create mode 100644 test/fixtures/output/shell/curl/unparseable-query.sh create mode 100644 test/fixtures/output/shell/httpie/unparseable-query.sh create mode 100644 test/fixtures/output/shell/wget/unparseable-query.sh create mode 100644 test/fixtures/output/swift/nsurlsession/unparseable-query.swift create mode 100644 test/fixtures/requests/unparseable-query.json diff --git a/src/index.js b/src/index.js index c8ebfc8..eb9078e 100644 --- a/src/index.js +++ b/src/index.js @@ -219,20 +219,29 @@ HTTPSnippet.prototype.prepare = function (request) { // merge all possible queryString values request.queryObj = Object.assign(request.queryObj, request.uriObj.query) - // reset uriObj values for a clean url - request.uriObj.query = null - request.uriObj.search = null - request.uriObj.path = request.uriObj.pathname - - // keep the base url clean of queryString - request.url = url.format(request.uriObj) - - // update the uri object - request.uriObj.query = request.queryObj - request.uriObj.search = qs.stringify(request.queryObj) - - if (request.uriObj.search) { - request.uriObj.path = request.uriObj.pathname + '?' + request.uriObj.search + // In some cases (unparseable query - preference to use raw in exporter) the queryString might + // be empty while the URL search is not. In that case, we prefer the URL search. + const hasQueryObj = Object.keys(request.queryObj).length > 0 + if (hasQueryObj || !request.uriObj.search) { + // reset uriObj values for a clean url + request.uriObj.query = null + request.uriObj.search = null + request.uriObj.path = request.uriObj.pathname + + // keep the base url clean of queryString + request.url = url.format(request.uriObj) + + // update the uri object + request.uriObj.query = request.queryObj + request.uriObj.search = qs.stringify(request.queryObj) + + if (request.uriObj.search) { + request.uriObj.path = request.uriObj.pathname + '?' + request.uriObj.search + } + } else { + // We have no request.queryObj (so snippets won't send query params in a structured way) + // We keep the queryString in request.url (so it's sent raw everywhere) + // request.fullUrl is recreated below (maybe mild fixed?) but preserves raw search etc } // construct a full url diff --git a/test/fixtures/output/c/libcurl/unparseable-query.c b/test/fixtures/output/c/libcurl/unparseable-query.c new file mode 100644 index 0000000..2854209 --- /dev/null +++ b/test/fixtures/output/c/libcurl/unparseable-query.c @@ -0,0 +1,6 @@ +CURL *hnd = curl_easy_init(); + +curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "GET"); +curl_easy_setopt(hnd, CURLOPT_URL, "http://mockbin.com/har?&&&"); + +CURLcode ret = curl_easy_perform(hnd); \ No newline at end of file diff --git a/test/fixtures/output/clojure/clj_http/unparseable-query.clj b/test/fixtures/output/clojure/clj_http/unparseable-query.clj new file mode 100644 index 0000000..597f745 --- /dev/null +++ b/test/fixtures/output/clojure/clj_http/unparseable-query.clj @@ -0,0 +1,3 @@ +(require '[clj-http.client :as client]) + +(client/get "http://mockbin.com/har?&&&") \ No newline at end of file diff --git a/test/fixtures/output/csharp/httpclient/unparseable-query.cs b/test/fixtures/output/csharp/httpclient/unparseable-query.cs new file mode 100644 index 0000000..85d9c25 --- /dev/null +++ b/test/fixtures/output/csharp/httpclient/unparseable-query.cs @@ -0,0 +1,12 @@ +var client = new HttpClient(); +var request = new HttpRequestMessage +{ + Method = HttpMethod.Get, + RequestUri = new Uri("http://mockbin.com/har?&&&"), +}; +using (var response = await client.SendAsync(request)) +{ + response.EnsureSuccessStatusCode(); + var body = await response.Content.ReadAsStringAsync(); + Console.WriteLine(body); +} \ No newline at end of file diff --git a/test/fixtures/output/csharp/restsharp/unparseable-query.cs b/test/fixtures/output/csharp/restsharp/unparseable-query.cs new file mode 100644 index 0000000..4ecfda8 --- /dev/null +++ b/test/fixtures/output/csharp/restsharp/unparseable-query.cs @@ -0,0 +1,3 @@ +var client = new RestClient("http://mockbin.com/har?&&&"); +var request = new RestRequest(Method.GET); +IRestResponse response = client.Execute(request); \ No newline at end of file diff --git a/test/fixtures/output/go/native/unparseable-query.go b/test/fixtures/output/go/native/unparseable-query.go new file mode 100644 index 0000000..45a11c7 --- /dev/null +++ b/test/fixtures/output/go/native/unparseable-query.go @@ -0,0 +1,23 @@ +package main + +import ( + "fmt" + "net/http" + "io" +) + +func main() { + + url := "http://mockbin.com/har?&&&" + + req, _ := http.NewRequest("GET", url, nil) + + res, _ := http.DefaultClient.Do(req) + + defer res.Body.Close() + body, _ := io.ReadAll(res.Body) + + fmt.Println(res) + fmt.Println(string(body)) + +} \ No newline at end of file diff --git a/test/fixtures/output/http/1.1/unparseable-query b/test/fixtures/output/http/1.1/unparseable-query new file mode 100644 index 0000000..a30d520 --- /dev/null +++ b/test/fixtures/output/http/1.1/unparseable-query @@ -0,0 +1,2 @@ +GET /har?&&& HTTP/1.1 +Host: mockbin.com \ No newline at end of file diff --git a/test/fixtures/output/java/asynchttp/unparseable-query.java b/test/fixtures/output/java/asynchttp/unparseable-query.java new file mode 100644 index 0000000..5097a3d --- /dev/null +++ b/test/fixtures/output/java/asynchttp/unparseable-query.java @@ -0,0 +1,8 @@ +AsyncHttpClient client = new DefaultAsyncHttpClient(); +client.prepare("GET", "http://mockbin.com/har?&&&") + .execute() + .toCompletableFuture() + .thenAccept(System.out::println) + .join(); + +client.close(); \ No newline at end of file diff --git a/test/fixtures/output/java/nethttp/unparseable-query.java b/test/fixtures/output/java/nethttp/unparseable-query.java new file mode 100644 index 0000000..64bd680 --- /dev/null +++ b/test/fixtures/output/java/nethttp/unparseable-query.java @@ -0,0 +1,6 @@ +HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("http://mockbin.com/har?&&&")) + .method("GET", HttpRequest.BodyPublishers.noBody()) + .build(); +HttpResponse response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()); +System.out.println(response.body()); \ No newline at end of file diff --git a/test/fixtures/output/java/okhttp/unparseable-query.java b/test/fixtures/output/java/okhttp/unparseable-query.java new file mode 100644 index 0000000..605aabb --- /dev/null +++ b/test/fixtures/output/java/okhttp/unparseable-query.java @@ -0,0 +1,8 @@ +OkHttpClient client = new OkHttpClient(); + +Request request = new Request.Builder() + .url("http://mockbin.com/har?&&&") + .get() + .build(); + +Response response = client.newCall(request).execute(); \ No newline at end of file diff --git a/test/fixtures/output/java/unirest/unparseable-query.java b/test/fixtures/output/java/unirest/unparseable-query.java new file mode 100644 index 0000000..0d53364 --- /dev/null +++ b/test/fixtures/output/java/unirest/unparseable-query.java @@ -0,0 +1,2 @@ +HttpResponse response = Unirest.get("http://mockbin.com/har?&&&") + .asString(); \ No newline at end of file diff --git a/test/fixtures/output/javascript/axios/unparseable-query.js b/test/fixtures/output/javascript/axios/unparseable-query.js new file mode 100644 index 0000000..733a6bc --- /dev/null +++ b/test/fixtures/output/javascript/axios/unparseable-query.js @@ -0,0 +1,9 @@ +import axios from "axios"; + +const options = {method: 'GET', url: 'http://mockbin.com/har?&&&'}; + +axios.request(options).then(function (response) { + console.log(response.data); +}).catch(function (error) { + console.error(error); +}); \ No newline at end of file diff --git a/test/fixtures/output/javascript/fetch/unparseable-query.js b/test/fixtures/output/javascript/fetch/unparseable-query.js new file mode 100644 index 0000000..10b5b9e --- /dev/null +++ b/test/fixtures/output/javascript/fetch/unparseable-query.js @@ -0,0 +1,6 @@ +const options = {method: 'GET'}; + +fetch('http://mockbin.com/har?&&&', options) + .then(response => response.json()) + .then(response => console.log(response)) + .catch(err => console.error(err)); \ No newline at end of file diff --git a/test/fixtures/output/javascript/jquery/unparseable-query.js b/test/fixtures/output/javascript/jquery/unparseable-query.js new file mode 100644 index 0000000..fdb5d51 --- /dev/null +++ b/test/fixtures/output/javascript/jquery/unparseable-query.js @@ -0,0 +1,11 @@ +const settings = { + "async": true, + "crossDomain": true, + "url": "http://mockbin.com/har?&&&", + "method": "GET", + "headers": {} +}; + +$.ajax(settings).done(function (response) { + console.log(response); +}); \ No newline at end of file diff --git a/test/fixtures/output/javascript/xhr/unparseable-query.js b/test/fixtures/output/javascript/xhr/unparseable-query.js new file mode 100644 index 0000000..0188eb8 --- /dev/null +++ b/test/fixtures/output/javascript/xhr/unparseable-query.js @@ -0,0 +1,14 @@ +const data = null; + +const xhr = new XMLHttpRequest(); +xhr.withCredentials = true; + +xhr.addEventListener("readystatechange", function () { + if (this.readyState === this.DONE) { + console.log(this.responseText); + } +}); + +xhr.open("GET", "http://mockbin.com/har?&&&"); + +xhr.send(data); \ No newline at end of file diff --git a/test/fixtures/output/kotlin/okhttp/unparseable-query.kt b/test/fixtures/output/kotlin/okhttp/unparseable-query.kt new file mode 100644 index 0000000..fa476db --- /dev/null +++ b/test/fixtures/output/kotlin/okhttp/unparseable-query.kt @@ -0,0 +1,8 @@ +val client = OkHttpClient() + +val request = Request.Builder() + .url("http://mockbin.com/har?&&&") + .get() + .build() + +val response = client.newCall(request).execute() \ No newline at end of file diff --git a/test/fixtures/output/node/axios/unparseable-query.js b/test/fixtures/output/node/axios/unparseable-query.js new file mode 100644 index 0000000..9e39489 --- /dev/null +++ b/test/fixtures/output/node/axios/unparseable-query.js @@ -0,0 +1,9 @@ +var axios = require("axios").default; + +var options = {method: 'GET', url: 'http://mockbin.com/har?&&&'}; + +axios.request(options).then(function (response) { + console.log(response.data); +}).catch(function (error) { + console.error(error); +}); \ No newline at end of file diff --git a/test/fixtures/output/node/fetch/unparseable-query.js b/test/fixtures/output/node/fetch/unparseable-query.js new file mode 100644 index 0000000..b06f203 --- /dev/null +++ b/test/fixtures/output/node/fetch/unparseable-query.js @@ -0,0 +1,10 @@ +const fetch = require('node-fetch'); + +let url = 'http://mockbin.com/har?&&&'; + +let options = {method: 'GET'}; + +fetch(url, options) + .then(res => res.json()) + .then(json => console.log(json)) + .catch(err => console.error('error:' + err)); \ No newline at end of file diff --git a/test/fixtures/output/node/native/unparseable-query.js b/test/fixtures/output/node/native/unparseable-query.js new file mode 100644 index 0000000..8ee8728 --- /dev/null +++ b/test/fixtures/output/node/native/unparseable-query.js @@ -0,0 +1,24 @@ +const http = require("http"); + +const options = { + "method": "GET", + "hostname": "mockbin.com", + "port": null, + "path": "/har?&&&", + "headers": {} +}; + +const req = http.request(options, function (res) { + const chunks = []; + + res.on("data", function (chunk) { + chunks.push(chunk); + }); + + res.on("end", function () { + const body = Buffer.concat(chunks); + console.log(body.toString()); + }); +}); + +req.end(); \ No newline at end of file diff --git a/test/fixtures/output/node/request/unparseable-query.js b/test/fixtures/output/node/request/unparseable-query.js new file mode 100644 index 0000000..3860cc2 --- /dev/null +++ b/test/fixtures/output/node/request/unparseable-query.js @@ -0,0 +1,9 @@ +const request = require('request'); + +const options = {method: 'GET', url: 'http://mockbin.com/har?&&&'}; + +request(options, function (error, response, body) { + if (error) throw new Error(error); + + console.log(body); +}); \ No newline at end of file diff --git a/test/fixtures/output/node/unirest/unparseable-query.js b/test/fixtures/output/node/unirest/unparseable-query.js new file mode 100644 index 0000000..86c3dd0 --- /dev/null +++ b/test/fixtures/output/node/unirest/unparseable-query.js @@ -0,0 +1,9 @@ +const unirest = require("unirest"); + +const req = unirest("GET", "http://mockbin.com/har?&&&"); + +req.end(function (res) { + if (res.error) throw new Error(res.error); + + console.log(res.body); +}); \ No newline at end of file diff --git a/test/fixtures/output/objc/nsurlsession/unparseable-query.m b/test/fixtures/output/objc/nsurlsession/unparseable-query.m new file mode 100644 index 0000000..4bc5ef8 --- /dev/null +++ b/test/fixtures/output/objc/nsurlsession/unparseable-query.m @@ -0,0 +1,18 @@ +#import + +NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://mockbin.com/har?&&&"] + cachePolicy:NSURLRequestUseProtocolCachePolicy + timeoutInterval:10.0]; +[request setHTTPMethod:@"GET"]; + +NSURLSession *session = [NSURLSession sharedSession]; +NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request + completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + if (error) { + NSLog(@"%@", error); + } else { + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response; + NSLog(@"%@", httpResponse); + } + }]; +[dataTask resume]; \ No newline at end of file diff --git a/test/fixtures/output/ocaml/cohttp/unparseable-query.ml b/test/fixtures/output/ocaml/cohttp/unparseable-query.ml new file mode 100644 index 0000000..f46dbd8 --- /dev/null +++ b/test/fixtures/output/ocaml/cohttp/unparseable-query.ml @@ -0,0 +1,9 @@ +open Cohttp_lwt_unix +open Cohttp +open Lwt + +let uri = Uri.of_string "http://mockbin.com/har?&&&" in + +Client.call `GET uri +>>= fun (res, body_stream) -> + (* Do stuff with the result *) \ No newline at end of file diff --git a/test/fixtures/output/php/curl/unparseable-query.php b/test/fixtures/output/php/curl/unparseable-query.php new file mode 100644 index 0000000..7dc5293 --- /dev/null +++ b/test/fixtures/output/php/curl/unparseable-query.php @@ -0,0 +1,24 @@ + 'http://mockbin.com/har?&&&', + CURLOPT_RETURNTRANSFER => true, + CURLOPT_ENCODING => '', + CURLOPT_MAXREDIRS => 10, + CURLOPT_TIMEOUT => 30, + CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, + CURLOPT_CUSTOMREQUEST => 'GET', +]); + +$response = curl_exec($curl); +$err = curl_error($curl); + +curl_close($curl); + +if ($err) { + echo 'cURL Error #:' . $err; +} else { + echo $response; +} \ No newline at end of file diff --git a/test/fixtures/output/php/http1/unparseable-query.php b/test/fixtures/output/php/http1/unparseable-query.php new file mode 100644 index 0000000..bb2f030 --- /dev/null +++ b/test/fixtures/output/php/http1/unparseable-query.php @@ -0,0 +1,13 @@ +setUrl('http://mockbin.com/har?&&&'); +$request->setMethod(HTTP_METH_GET); + +try { + $response = $request->send(); + + echo $response->getBody(); +} catch (HttpException $ex) { + echo $ex; +} \ No newline at end of file diff --git a/test/fixtures/output/php/http2/unparseable-query.php b/test/fixtures/output/php/http2/unparseable-query.php new file mode 100644 index 0000000..c7e9f5a --- /dev/null +++ b/test/fixtures/output/php/http2/unparseable-query.php @@ -0,0 +1,11 @@ +setRequestUrl('http://mockbin.com/har?&&&'); +$request->setRequestMethod('GET'); +$client->enqueue($request)->send(); +$response = $client->getResponse(); + +echo $response->getBody(); \ No newline at end of file diff --git a/test/fixtures/output/powershell/restmethod/unparseable-query.ps1 b/test/fixtures/output/powershell/restmethod/unparseable-query.ps1 new file mode 100644 index 0000000..6a1c059 --- /dev/null +++ b/test/fixtures/output/powershell/restmethod/unparseable-query.ps1 @@ -0,0 +1 @@ +$response = Invoke-RestMethod -Uri 'http://mockbin.com/har?&&&' -Method GET \ No newline at end of file diff --git a/test/fixtures/output/powershell/webrequest/unparseable-query.ps1 b/test/fixtures/output/powershell/webrequest/unparseable-query.ps1 new file mode 100644 index 0000000..b21147e --- /dev/null +++ b/test/fixtures/output/powershell/webrequest/unparseable-query.ps1 @@ -0,0 +1 @@ +$response = Invoke-WebRequest -Uri 'http://mockbin.com/har?&&&' -Method GET \ No newline at end of file diff --git a/test/fixtures/output/python/python3/unparseable-query.py b/test/fixtures/output/python/python3/unparseable-query.py new file mode 100644 index 0000000..cd9cfc5 --- /dev/null +++ b/test/fixtures/output/python/python3/unparseable-query.py @@ -0,0 +1,10 @@ +import http.client + +conn = http.client.HTTPConnection("mockbin.com") + +conn.request("GET", "/har?&&&") + +res = conn.getresponse() +data = res.read() + +print(data.decode("utf-8")) \ No newline at end of file diff --git a/test/fixtures/output/python/requests/unparseable-query.py b/test/fixtures/output/python/requests/unparseable-query.py new file mode 100644 index 0000000..476de8e --- /dev/null +++ b/test/fixtures/output/python/requests/unparseable-query.py @@ -0,0 +1,7 @@ +import requests + +url = "http://mockbin.com/har?&&&" + +response = requests.get(url) + +print(response.text) \ No newline at end of file diff --git a/test/fixtures/output/r/httr/unparseable-query.r b/test/fixtures/output/r/httr/unparseable-query.r new file mode 100644 index 0000000..52d1099 --- /dev/null +++ b/test/fixtures/output/r/httr/unparseable-query.r @@ -0,0 +1,7 @@ +library(httr) + +url <- "http://mockbin.com/har?&&&" + +response <- VERB("GET", url, content_type("application/octet-stream")) + +content(response, "text") \ No newline at end of file diff --git a/test/fixtures/output/ruby/native/unparseable-query.rb b/test/fixtures/output/ruby/native/unparseable-query.rb new file mode 100644 index 0000000..c66aa82 --- /dev/null +++ b/test/fixtures/output/ruby/native/unparseable-query.rb @@ -0,0 +1,11 @@ +require 'uri' +require 'net/http' + +url = URI("http://mockbin.com/har?&&&") + +http = Net::HTTP.new(url.host, url.port) + +request = Net::HTTP::Get.new(url) + +response = http.request(request) +puts response.read_body \ No newline at end of file diff --git a/test/fixtures/output/shell/curl/unparseable-query.sh b/test/fixtures/output/shell/curl/unparseable-query.sh new file mode 100644 index 0000000..c912c2b --- /dev/null +++ b/test/fixtures/output/shell/curl/unparseable-query.sh @@ -0,0 +1,2 @@ +curl --request GET \ + --url 'http://mockbin.com/har?&&&' \ No newline at end of file diff --git a/test/fixtures/output/shell/httpie/unparseable-query.sh b/test/fixtures/output/shell/httpie/unparseable-query.sh new file mode 100644 index 0000000..016d3ec --- /dev/null +++ b/test/fixtures/output/shell/httpie/unparseable-query.sh @@ -0,0 +1 @@ +http GET 'http://mockbin.com/har?&&&' \ No newline at end of file diff --git a/test/fixtures/output/shell/wget/unparseable-query.sh b/test/fixtures/output/shell/wget/unparseable-query.sh new file mode 100644 index 0000000..cf8b52a --- /dev/null +++ b/test/fixtures/output/shell/wget/unparseable-query.sh @@ -0,0 +1,4 @@ +wget --quiet \ + --method GET \ + --output-document \ + - 'http://mockbin.com/har?&&&' \ No newline at end of file diff --git a/test/fixtures/output/swift/nsurlsession/unparseable-query.swift b/test/fixtures/output/swift/nsurlsession/unparseable-query.swift new file mode 100644 index 0000000..0c7980c --- /dev/null +++ b/test/fixtures/output/swift/nsurlsession/unparseable-query.swift @@ -0,0 +1,18 @@ +import Foundation + +let request = NSMutableURLRequest(url: NSURL(string: "http://mockbin.com/har?&&&")! as URL, + cachePolicy: .useProtocolCachePolicy, + timeoutInterval: 10.0) +request.httpMethod = "GET" + +let session = URLSession.shared +let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in + if (error != nil) { + print(error) + } else { + let httpResponse = response as? HTTPURLResponse + print(httpResponse) + } +}) + +dataTask.resume() \ No newline at end of file diff --git a/test/fixtures/requests/unparseable-query.json b/test/fixtures/requests/unparseable-query.json new file mode 100644 index 0000000..925027b --- /dev/null +++ b/test/fixtures/requests/unparseable-query.json @@ -0,0 +1,6 @@ +{ + "method": "GET", + "url": "http://mockbin.com/har?&&&", + "httpVersion": "HTTP/1.1", + "queryString": [] +} From ecd166fd30317652b2524324fb2c001e949c0723 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Mon, 22 Jul 2024 11:24:46 +0200 Subject: [PATCH 06/36] Preserve *partially* parseable query strings too --- src/index.js | 15 +++++++++------ .../fixtures/output/c/libcurl/unparseable-query.c | 2 +- .../output/clojure/clj_http/unparseable-query.clj | 2 +- .../output/csharp/httpclient/unparseable-query.cs | 2 +- .../output/csharp/restsharp/unparseable-query.cs | 2 +- .../output/go/native/unparseable-query.go | 2 +- test/fixtures/output/http/1.1/unparseable-query | 2 +- .../output/java/asynchttp/unparseable-query.java | 2 +- .../output/java/nethttp/unparseable-query.java | 2 +- .../output/java/okhttp/unparseable-query.java | 2 +- .../output/java/unirest/unparseable-query.java | 2 +- .../output/javascript/axios/unparseable-query.js | 2 +- .../output/javascript/fetch/unparseable-query.js | 2 +- .../output/javascript/jquery/unparseable-query.js | 2 +- .../output/javascript/xhr/unparseable-query.js | 2 +- .../output/kotlin/okhttp/unparseable-query.kt | 2 +- .../output/node/axios/unparseable-query.js | 2 +- .../output/node/fetch/unparseable-query.js | 2 +- .../output/node/native/unparseable-query.js | 2 +- .../output/node/request/unparseable-query.js | 2 +- .../output/node/unirest/unparseable-query.js | 2 +- .../output/objc/nsurlsession/unparseable-query.m | 2 +- .../output/ocaml/cohttp/unparseable-query.ml | 2 +- .../output/php/curl/unparseable-query.php | 2 +- .../output/php/http1/unparseable-query.php | 2 +- .../output/php/http2/unparseable-query.php | 2 +- .../powershell/restmethod/unparseable-query.ps1 | 2 +- .../powershell/webrequest/unparseable-query.ps1 | 2 +- .../output/python/python3/unparseable-query.py | 2 +- .../output/python/requests/unparseable-query.py | 2 +- test/fixtures/output/r/httr/unparseable-query.r | 2 +- .../output/ruby/native/unparseable-query.rb | 2 +- .../output/shell/curl/unparseable-query.sh | 2 +- .../output/shell/httpie/unparseable-query.sh | 2 +- .../output/shell/wget/unparseable-query.sh | 2 +- .../swift/nsurlsession/unparseable-query.swift | 2 +- test/fixtures/requests/unparseable-query.json | 2 +- 37 files changed, 45 insertions(+), 42 deletions(-) diff --git a/src/index.js b/src/index.js index eb9078e..565d039 100644 --- a/src/index.js +++ b/src/index.js @@ -216,13 +216,16 @@ HTTPSnippet.prototype.prepare = function (request) { // eslint-disable-next-line node/no-deprecated-api request.uriObj = url.parse(request.url, true, true) - // merge all possible queryString values - request.queryObj = Object.assign(request.queryObj, request.uriObj.query) + // In some cases (unparseable/partially parseable query string) we want to fully preserve the + // original string (as it may not follow qs conventions at all). We assume any scenario where + // qs cannot reproduce the original value is this case. + const simpleQueryString = !request.uriObj.search || + (qs.stringify(request.uriObj.query) === request.uriObj.search.slice(1)) + + if (simpleQueryString) { + // merge all possible queryString values + request.queryObj = Object.assign(request.queryObj, request.uriObj.query) - // In some cases (unparseable query - preference to use raw in exporter) the queryString might - // be empty while the URL search is not. In that case, we prefer the URL search. - const hasQueryObj = Object.keys(request.queryObj).length > 0 - if (hasQueryObj || !request.uriObj.search) { // reset uriObj values for a clean url request.uriObj.query = null request.uriObj.search = null diff --git a/test/fixtures/output/c/libcurl/unparseable-query.c b/test/fixtures/output/c/libcurl/unparseable-query.c index 2854209..dfb694d 100644 --- a/test/fixtures/output/c/libcurl/unparseable-query.c +++ b/test/fixtures/output/c/libcurl/unparseable-query.c @@ -1,6 +1,6 @@ CURL *hnd = curl_easy_init(); curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "GET"); -curl_easy_setopt(hnd, CURLOPT_URL, "http://mockbin.com/har?&&&"); +curl_easy_setopt(hnd, CURLOPT_URL, "http://mockbin.com/har?&&a=b&&"); CURLcode ret = curl_easy_perform(hnd); \ No newline at end of file diff --git a/test/fixtures/output/clojure/clj_http/unparseable-query.clj b/test/fixtures/output/clojure/clj_http/unparseable-query.clj index 597f745..36fc53a 100644 --- a/test/fixtures/output/clojure/clj_http/unparseable-query.clj +++ b/test/fixtures/output/clojure/clj_http/unparseable-query.clj @@ -1,3 +1,3 @@ (require '[clj-http.client :as client]) -(client/get "http://mockbin.com/har?&&&") \ No newline at end of file +(client/get "http://mockbin.com/har?&&a=b&&") \ No newline at end of file diff --git a/test/fixtures/output/csharp/httpclient/unparseable-query.cs b/test/fixtures/output/csharp/httpclient/unparseable-query.cs index 85d9c25..c0659b0 100644 --- a/test/fixtures/output/csharp/httpclient/unparseable-query.cs +++ b/test/fixtures/output/csharp/httpclient/unparseable-query.cs @@ -2,7 +2,7 @@ var request = new HttpRequestMessage { Method = HttpMethod.Get, - RequestUri = new Uri("http://mockbin.com/har?&&&"), + RequestUri = new Uri("http://mockbin.com/har?&&a=b&&"), }; using (var response = await client.SendAsync(request)) { diff --git a/test/fixtures/output/csharp/restsharp/unparseable-query.cs b/test/fixtures/output/csharp/restsharp/unparseable-query.cs index 4ecfda8..d6ad3c4 100644 --- a/test/fixtures/output/csharp/restsharp/unparseable-query.cs +++ b/test/fixtures/output/csharp/restsharp/unparseable-query.cs @@ -1,3 +1,3 @@ -var client = new RestClient("http://mockbin.com/har?&&&"); +var client = new RestClient("http://mockbin.com/har?&&a=b&&"); var request = new RestRequest(Method.GET); IRestResponse response = client.Execute(request); \ No newline at end of file diff --git a/test/fixtures/output/go/native/unparseable-query.go b/test/fixtures/output/go/native/unparseable-query.go index 45a11c7..655601e 100644 --- a/test/fixtures/output/go/native/unparseable-query.go +++ b/test/fixtures/output/go/native/unparseable-query.go @@ -8,7 +8,7 @@ import ( func main() { - url := "http://mockbin.com/har?&&&" + url := "http://mockbin.com/har?&&a=b&&" req, _ := http.NewRequest("GET", url, nil) diff --git a/test/fixtures/output/http/1.1/unparseable-query b/test/fixtures/output/http/1.1/unparseable-query index a30d520..d4e4f28 100644 --- a/test/fixtures/output/http/1.1/unparseable-query +++ b/test/fixtures/output/http/1.1/unparseable-query @@ -1,2 +1,2 @@ -GET /har?&&& HTTP/1.1 +GET /har?&&a=b&& HTTP/1.1 Host: mockbin.com \ No newline at end of file diff --git a/test/fixtures/output/java/asynchttp/unparseable-query.java b/test/fixtures/output/java/asynchttp/unparseable-query.java index 5097a3d..c6a63b3 100644 --- a/test/fixtures/output/java/asynchttp/unparseable-query.java +++ b/test/fixtures/output/java/asynchttp/unparseable-query.java @@ -1,5 +1,5 @@ AsyncHttpClient client = new DefaultAsyncHttpClient(); -client.prepare("GET", "http://mockbin.com/har?&&&") +client.prepare("GET", "http://mockbin.com/har?&&a=b&&") .execute() .toCompletableFuture() .thenAccept(System.out::println) diff --git a/test/fixtures/output/java/nethttp/unparseable-query.java b/test/fixtures/output/java/nethttp/unparseable-query.java index 64bd680..9df4b62 100644 --- a/test/fixtures/output/java/nethttp/unparseable-query.java +++ b/test/fixtures/output/java/nethttp/unparseable-query.java @@ -1,5 +1,5 @@ HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create("http://mockbin.com/har?&&&")) + .uri(URI.create("http://mockbin.com/har?&&a=b&&")) .method("GET", HttpRequest.BodyPublishers.noBody()) .build(); HttpResponse response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()); diff --git a/test/fixtures/output/java/okhttp/unparseable-query.java b/test/fixtures/output/java/okhttp/unparseable-query.java index 605aabb..b08a7d6 100644 --- a/test/fixtures/output/java/okhttp/unparseable-query.java +++ b/test/fixtures/output/java/okhttp/unparseable-query.java @@ -1,7 +1,7 @@ OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() - .url("http://mockbin.com/har?&&&") + .url("http://mockbin.com/har?&&a=b&&") .get() .build(); diff --git a/test/fixtures/output/java/unirest/unparseable-query.java b/test/fixtures/output/java/unirest/unparseable-query.java index 0d53364..21aad1f 100644 --- a/test/fixtures/output/java/unirest/unparseable-query.java +++ b/test/fixtures/output/java/unirest/unparseable-query.java @@ -1,2 +1,2 @@ -HttpResponse response = Unirest.get("http://mockbin.com/har?&&&") +HttpResponse response = Unirest.get("http://mockbin.com/har?&&a=b&&") .asString(); \ No newline at end of file diff --git a/test/fixtures/output/javascript/axios/unparseable-query.js b/test/fixtures/output/javascript/axios/unparseable-query.js index 733a6bc..a74bf9f 100644 --- a/test/fixtures/output/javascript/axios/unparseable-query.js +++ b/test/fixtures/output/javascript/axios/unparseable-query.js @@ -1,6 +1,6 @@ import axios from "axios"; -const options = {method: 'GET', url: 'http://mockbin.com/har?&&&'}; +const options = {method: 'GET', url: 'http://mockbin.com/har?&&a=b&&'}; axios.request(options).then(function (response) { console.log(response.data); diff --git a/test/fixtures/output/javascript/fetch/unparseable-query.js b/test/fixtures/output/javascript/fetch/unparseable-query.js index 10b5b9e..5e0d126 100644 --- a/test/fixtures/output/javascript/fetch/unparseable-query.js +++ b/test/fixtures/output/javascript/fetch/unparseable-query.js @@ -1,6 +1,6 @@ const options = {method: 'GET'}; -fetch('http://mockbin.com/har?&&&', options) +fetch('http://mockbin.com/har?&&a=b&&', options) .then(response => response.json()) .then(response => console.log(response)) .catch(err => console.error(err)); \ No newline at end of file diff --git a/test/fixtures/output/javascript/jquery/unparseable-query.js b/test/fixtures/output/javascript/jquery/unparseable-query.js index fdb5d51..3a59c9e 100644 --- a/test/fixtures/output/javascript/jquery/unparseable-query.js +++ b/test/fixtures/output/javascript/jquery/unparseable-query.js @@ -1,7 +1,7 @@ const settings = { "async": true, "crossDomain": true, - "url": "http://mockbin.com/har?&&&", + "url": "http://mockbin.com/har?&&a=b&&", "method": "GET", "headers": {} }; diff --git a/test/fixtures/output/javascript/xhr/unparseable-query.js b/test/fixtures/output/javascript/xhr/unparseable-query.js index 0188eb8..d955e0a 100644 --- a/test/fixtures/output/javascript/xhr/unparseable-query.js +++ b/test/fixtures/output/javascript/xhr/unparseable-query.js @@ -9,6 +9,6 @@ xhr.addEventListener("readystatechange", function () { } }); -xhr.open("GET", "http://mockbin.com/har?&&&"); +xhr.open("GET", "http://mockbin.com/har?&&a=b&&"); xhr.send(data); \ No newline at end of file diff --git a/test/fixtures/output/kotlin/okhttp/unparseable-query.kt b/test/fixtures/output/kotlin/okhttp/unparseable-query.kt index fa476db..208e62d 100644 --- a/test/fixtures/output/kotlin/okhttp/unparseable-query.kt +++ b/test/fixtures/output/kotlin/okhttp/unparseable-query.kt @@ -1,7 +1,7 @@ val client = OkHttpClient() val request = Request.Builder() - .url("http://mockbin.com/har?&&&") + .url("http://mockbin.com/har?&&a=b&&") .get() .build() diff --git a/test/fixtures/output/node/axios/unparseable-query.js b/test/fixtures/output/node/axios/unparseable-query.js index 9e39489..dac5faa 100644 --- a/test/fixtures/output/node/axios/unparseable-query.js +++ b/test/fixtures/output/node/axios/unparseable-query.js @@ -1,6 +1,6 @@ var axios = require("axios").default; -var options = {method: 'GET', url: 'http://mockbin.com/har?&&&'}; +var options = {method: 'GET', url: 'http://mockbin.com/har?&&a=b&&'}; axios.request(options).then(function (response) { console.log(response.data); diff --git a/test/fixtures/output/node/fetch/unparseable-query.js b/test/fixtures/output/node/fetch/unparseable-query.js index b06f203..7064d64 100644 --- a/test/fixtures/output/node/fetch/unparseable-query.js +++ b/test/fixtures/output/node/fetch/unparseable-query.js @@ -1,6 +1,6 @@ const fetch = require('node-fetch'); -let url = 'http://mockbin.com/har?&&&'; +let url = 'http://mockbin.com/har?&&a=b&&'; let options = {method: 'GET'}; diff --git a/test/fixtures/output/node/native/unparseable-query.js b/test/fixtures/output/node/native/unparseable-query.js index 8ee8728..b991ed0 100644 --- a/test/fixtures/output/node/native/unparseable-query.js +++ b/test/fixtures/output/node/native/unparseable-query.js @@ -4,7 +4,7 @@ const options = { "method": "GET", "hostname": "mockbin.com", "port": null, - "path": "/har?&&&", + "path": "/har?&&a=b&&", "headers": {} }; diff --git a/test/fixtures/output/node/request/unparseable-query.js b/test/fixtures/output/node/request/unparseable-query.js index 3860cc2..c10a732 100644 --- a/test/fixtures/output/node/request/unparseable-query.js +++ b/test/fixtures/output/node/request/unparseable-query.js @@ -1,6 +1,6 @@ const request = require('request'); -const options = {method: 'GET', url: 'http://mockbin.com/har?&&&'}; +const options = {method: 'GET', url: 'http://mockbin.com/har?&&a=b&&'}; request(options, function (error, response, body) { if (error) throw new Error(error); diff --git a/test/fixtures/output/node/unirest/unparseable-query.js b/test/fixtures/output/node/unirest/unparseable-query.js index 86c3dd0..f0f961e 100644 --- a/test/fixtures/output/node/unirest/unparseable-query.js +++ b/test/fixtures/output/node/unirest/unparseable-query.js @@ -1,6 +1,6 @@ const unirest = require("unirest"); -const req = unirest("GET", "http://mockbin.com/har?&&&"); +const req = unirest("GET", "http://mockbin.com/har?&&a=b&&"); req.end(function (res) { if (res.error) throw new Error(res.error); diff --git a/test/fixtures/output/objc/nsurlsession/unparseable-query.m b/test/fixtures/output/objc/nsurlsession/unparseable-query.m index 4bc5ef8..b201540 100644 --- a/test/fixtures/output/objc/nsurlsession/unparseable-query.m +++ b/test/fixtures/output/objc/nsurlsession/unparseable-query.m @@ -1,6 +1,6 @@ #import -NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://mockbin.com/har?&&&"] +NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://mockbin.com/har?&&a=b&&"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0]; [request setHTTPMethod:@"GET"]; diff --git a/test/fixtures/output/ocaml/cohttp/unparseable-query.ml b/test/fixtures/output/ocaml/cohttp/unparseable-query.ml index f46dbd8..f601513 100644 --- a/test/fixtures/output/ocaml/cohttp/unparseable-query.ml +++ b/test/fixtures/output/ocaml/cohttp/unparseable-query.ml @@ -2,7 +2,7 @@ open Cohttp_lwt_unix open Cohttp open Lwt -let uri = Uri.of_string "http://mockbin.com/har?&&&" in +let uri = Uri.of_string "http://mockbin.com/har?&&a=b&&" in Client.call `GET uri >>= fun (res, body_stream) -> diff --git a/test/fixtures/output/php/curl/unparseable-query.php b/test/fixtures/output/php/curl/unparseable-query.php index 7dc5293..8108a21 100644 --- a/test/fixtures/output/php/curl/unparseable-query.php +++ b/test/fixtures/output/php/curl/unparseable-query.php @@ -3,7 +3,7 @@ $curl = curl_init(); curl_setopt_array($curl, [ - CURLOPT_URL => 'http://mockbin.com/har?&&&', + CURLOPT_URL => 'http://mockbin.com/har?&&a=b&&', CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, diff --git a/test/fixtures/output/php/http1/unparseable-query.php b/test/fixtures/output/php/http1/unparseable-query.php index bb2f030..200d80d 100644 --- a/test/fixtures/output/php/http1/unparseable-query.php +++ b/test/fixtures/output/php/http1/unparseable-query.php @@ -1,7 +1,7 @@ setUrl('http://mockbin.com/har?&&&'); +$request->setUrl('http://mockbin.com/har?&&a=b&&'); $request->setMethod(HTTP_METH_GET); try { diff --git a/test/fixtures/output/php/http2/unparseable-query.php b/test/fixtures/output/php/http2/unparseable-query.php index c7e9f5a..52bf547 100644 --- a/test/fixtures/output/php/http2/unparseable-query.php +++ b/test/fixtures/output/php/http2/unparseable-query.php @@ -3,7 +3,7 @@ $client = new http\Client; $request = new http\Client\Request; -$request->setRequestUrl('http://mockbin.com/har?&&&'); +$request->setRequestUrl('http://mockbin.com/har?&&a=b&&'); $request->setRequestMethod('GET'); $client->enqueue($request)->send(); $response = $client->getResponse(); diff --git a/test/fixtures/output/powershell/restmethod/unparseable-query.ps1 b/test/fixtures/output/powershell/restmethod/unparseable-query.ps1 index 6a1c059..8ca0208 100644 --- a/test/fixtures/output/powershell/restmethod/unparseable-query.ps1 +++ b/test/fixtures/output/powershell/restmethod/unparseable-query.ps1 @@ -1 +1 @@ -$response = Invoke-RestMethod -Uri 'http://mockbin.com/har?&&&' -Method GET \ No newline at end of file +$response = Invoke-RestMethod -Uri 'http://mockbin.com/har?&&a=b&&' -Method GET \ No newline at end of file diff --git a/test/fixtures/output/powershell/webrequest/unparseable-query.ps1 b/test/fixtures/output/powershell/webrequest/unparseable-query.ps1 index b21147e..19bd44b 100644 --- a/test/fixtures/output/powershell/webrequest/unparseable-query.ps1 +++ b/test/fixtures/output/powershell/webrequest/unparseable-query.ps1 @@ -1 +1 @@ -$response = Invoke-WebRequest -Uri 'http://mockbin.com/har?&&&' -Method GET \ No newline at end of file +$response = Invoke-WebRequest -Uri 'http://mockbin.com/har?&&a=b&&' -Method GET \ No newline at end of file diff --git a/test/fixtures/output/python/python3/unparseable-query.py b/test/fixtures/output/python/python3/unparseable-query.py index cd9cfc5..4a74ee4 100644 --- a/test/fixtures/output/python/python3/unparseable-query.py +++ b/test/fixtures/output/python/python3/unparseable-query.py @@ -2,7 +2,7 @@ conn = http.client.HTTPConnection("mockbin.com") -conn.request("GET", "/har?&&&") +conn.request("GET", "/har?&&a=b&&") res = conn.getresponse() data = res.read() diff --git a/test/fixtures/output/python/requests/unparseable-query.py b/test/fixtures/output/python/requests/unparseable-query.py index 476de8e..af5d7bd 100644 --- a/test/fixtures/output/python/requests/unparseable-query.py +++ b/test/fixtures/output/python/requests/unparseable-query.py @@ -1,6 +1,6 @@ import requests -url = "http://mockbin.com/har?&&&" +url = "http://mockbin.com/har?&&a=b&&" response = requests.get(url) diff --git a/test/fixtures/output/r/httr/unparseable-query.r b/test/fixtures/output/r/httr/unparseable-query.r index 52d1099..b39a545 100644 --- a/test/fixtures/output/r/httr/unparseable-query.r +++ b/test/fixtures/output/r/httr/unparseable-query.r @@ -1,6 +1,6 @@ library(httr) -url <- "http://mockbin.com/har?&&&" +url <- "http://mockbin.com/har?&&a=b&&" response <- VERB("GET", url, content_type("application/octet-stream")) diff --git a/test/fixtures/output/ruby/native/unparseable-query.rb b/test/fixtures/output/ruby/native/unparseable-query.rb index c66aa82..3653394 100644 --- a/test/fixtures/output/ruby/native/unparseable-query.rb +++ b/test/fixtures/output/ruby/native/unparseable-query.rb @@ -1,7 +1,7 @@ require 'uri' require 'net/http' -url = URI("http://mockbin.com/har?&&&") +url = URI("http://mockbin.com/har?&&a=b&&") http = Net::HTTP.new(url.host, url.port) diff --git a/test/fixtures/output/shell/curl/unparseable-query.sh b/test/fixtures/output/shell/curl/unparseable-query.sh index c912c2b..1b2f29c 100644 --- a/test/fixtures/output/shell/curl/unparseable-query.sh +++ b/test/fixtures/output/shell/curl/unparseable-query.sh @@ -1,2 +1,2 @@ curl --request GET \ - --url 'http://mockbin.com/har?&&&' \ No newline at end of file + --url 'http://mockbin.com/har?&&a=b&&' \ No newline at end of file diff --git a/test/fixtures/output/shell/httpie/unparseable-query.sh b/test/fixtures/output/shell/httpie/unparseable-query.sh index 016d3ec..0a973a2 100644 --- a/test/fixtures/output/shell/httpie/unparseable-query.sh +++ b/test/fixtures/output/shell/httpie/unparseable-query.sh @@ -1 +1 @@ -http GET 'http://mockbin.com/har?&&&' \ No newline at end of file +http GET 'http://mockbin.com/har?&&a=b&&' \ No newline at end of file diff --git a/test/fixtures/output/shell/wget/unparseable-query.sh b/test/fixtures/output/shell/wget/unparseable-query.sh index cf8b52a..ef5ca27 100644 --- a/test/fixtures/output/shell/wget/unparseable-query.sh +++ b/test/fixtures/output/shell/wget/unparseable-query.sh @@ -1,4 +1,4 @@ wget --quiet \ --method GET \ --output-document \ - - 'http://mockbin.com/har?&&&' \ No newline at end of file + - 'http://mockbin.com/har?&&a=b&&' \ No newline at end of file diff --git a/test/fixtures/output/swift/nsurlsession/unparseable-query.swift b/test/fixtures/output/swift/nsurlsession/unparseable-query.swift index 0c7980c..995fb60 100644 --- a/test/fixtures/output/swift/nsurlsession/unparseable-query.swift +++ b/test/fixtures/output/swift/nsurlsession/unparseable-query.swift @@ -1,6 +1,6 @@ import Foundation -let request = NSMutableURLRequest(url: NSURL(string: "http://mockbin.com/har?&&&")! as URL, +let request = NSMutableURLRequest(url: NSURL(string: "http://mockbin.com/har?&&a=b&&")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0) request.httpMethod = "GET" diff --git a/test/fixtures/requests/unparseable-query.json b/test/fixtures/requests/unparseable-query.json index 925027b..2f2ae42 100644 --- a/test/fixtures/requests/unparseable-query.json +++ b/test/fixtures/requests/unparseable-query.json @@ -1,6 +1,6 @@ { "method": "GET", - "url": "http://mockbin.com/har?&&&", + "url": "http://mockbin.com/har?&&a=b&&", "httpVersion": "HTTP/1.1", "queryString": [] } From 03b377f081d53b2ebe93ba6a28e9af46b1cf5d05 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Mon, 22 Jul 2024 11:30:40 +0200 Subject: [PATCH 07/36] 2.1.7 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 53bc2c6..6e0a404 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@httptoolkit/httpsnippet", - "version": "2.1.6", + "version": "2.1.7", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@httptoolkit/httpsnippet", - "version": "2.1.6", + "version": "2.1.7", "license": "MIT", "dependencies": { "chalk": "^1.1.1", diff --git a/package.json b/package.json index 4e026a8..d5ccaa6 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "2.1.6", + "version": "2.1.7", "name": "@httptoolkit/httpsnippet", "description": "HTTP request snippet generator for *most* languages", "author": "Tim Perry ", From c629a3e7d99b7b5f35e9a85c25761711a8b63604 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 22 Jul 2025 06:12:56 +0000 Subject: [PATCH 08/36] chore(deps): bump form-data from 3.0.0 to 3.0.4 Bumps [form-data](https://github.com/form-data/form-data) from 3.0.0 to 3.0.4. - [Release notes](https://github.com/form-data/form-data/releases) - [Changelog](https://github.com/form-data/form-data/blob/v3.0.4/CHANGELOG.md) - [Commits](https://github.com/form-data/form-data/compare/v3.0.0...v3.0.4) --- updated-dependencies: - dependency-name: form-data dependency-version: 3.0.4 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- package-lock.json | 418 ++++++++++++++++++++++++++++++---------------- package.json | 2 +- 2 files changed, 275 insertions(+), 145 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6e0a404..a484dcf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "commander": "^2.9.0", "debug": "^2.2.0", "event-stream": "3.3.4", - "form-data": "3.0.0", + "form-data": "3.0.4", "fs-readfile-promise": "^2.0.1", "fs-writefile-promise": "^1.0.3", "har-validator": "^5.0.0" @@ -416,6 +416,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -671,6 +683,19 @@ "node": ">=6" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/duplexer": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", @@ -850,18 +875,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es-abstract/node_modules/has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/es-abstract/node_modules/object-inspect": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", @@ -915,6 +928,47 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-to-primitive": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", @@ -1714,13 +1768,15 @@ "dev": true }, "node_modules/form-data": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", - "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.4.tgz", + "integrity": "sha512-f0cRzm6dkyVYV3nPoooP8XlccPQukegwhAnpoLcXy+X+A8KfpGOoXwDr9FLZd3wzgLaBGQBE3lY93Zm/i1JvIQ==", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.35" }, "engines": { "node": ">= 6" @@ -1795,10 +1851,12 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/functional-red-black-tree": { "version": "1.0.1", @@ -1816,29 +1874,38 @@ } }, "node_modules/get-intrinsic": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.0.tgz", - "integrity": "sha512-M11rgtQp5GZMZzDL7jLTNxbDfurpzuau5uqRWDPvlHjfvg3TdScAZo96GLvhMjImrmR8uAt0FS2RLoMrfWGKlg==", - "dev": true, + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-intrinsic/node_modules/has-symbols": { + "node_modules/get-proto": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true, + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, "node_modules/get-stdin": { @@ -1896,6 +1963,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.1.15", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", @@ -2000,10 +2078,37 @@ } }, "node_modules/has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", - "dev": true, + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, "engines": { "node": ">= 0.4" } @@ -2219,18 +2324,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-regex/node_modules/has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-string": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", @@ -2401,18 +2494,6 @@ "node": ">=4.0" } }, - "node_modules/jsx-ast-utils/node_modules/has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/jsx-ast-utils/node_modules/object.assign": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", @@ -2601,20 +2682,28 @@ "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=" }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/mime-db": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", - "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dependencies": { - "mime-db": "1.40.0" + "mime-db": "1.52.0" }, "engines": { "node": ">= 0.6" @@ -3964,18 +4053,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/string.prototype.matchall/node_modules/has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", @@ -4835,6 +4912,15 @@ "get-intrinsic": "^1.0.2" } }, + "call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + } + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -5035,6 +5121,16 @@ "integrity": "sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==", "dev": true }, + "dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "requires": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + } + }, "duplexer": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", @@ -5180,12 +5276,6 @@ "string.prototype.trimstart": "^1.0.3" }, "dependencies": { - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true - }, "object-inspect": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", @@ -5226,6 +5316,35 @@ } } }, + "es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==" + }, + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" + }, + "es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "requires": { + "es-errors": "^1.3.0" + } + }, + "es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "requires": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + } + }, "es-to-primitive": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", @@ -5808,13 +5927,15 @@ "dev": true }, "form-data": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", - "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.4.tgz", + "integrity": "sha512-f0cRzm6dkyVYV3nPoooP8XlccPQukegwhAnpoLcXy+X+A8KfpGOoXwDr9FLZd3wzgLaBGQBE3lY93Zm/i1JvIQ==", "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.35" }, "dependencies": { "combined-stream": { @@ -5873,10 +5994,9 @@ "optional": true }, "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" }, "functional-red-black-tree": { "version": "1.0.1", @@ -5891,22 +6011,29 @@ "dev": true }, "get-intrinsic": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.0.tgz", - "integrity": "sha512-M11rgtQp5GZMZzDL7jLTNxbDfurpzuau5uqRWDPvlHjfvg3TdScAZo96GLvhMjImrmR8uAt0FS2RLoMrfWGKlg==", - "dev": true, + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "requires": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + } + }, + "get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - }, - "dependencies": { - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true - } + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" } }, "get-stdin": { @@ -5946,6 +6073,11 @@ "type-fest": "^0.8.1" } }, + "gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==" + }, "graceful-fs": { "version": "4.1.15", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", @@ -6022,10 +6154,25 @@ "dev": true }, "has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", - "dev": true + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==" + }, + "has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "requires": { + "has-symbols": "^1.0.3" + } + }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "requires": { + "function-bind": "^1.1.2" + } }, "he": { "version": "1.2.0", @@ -6176,14 +6323,6 @@ "dev": true, "requires": { "has-symbols": "^1.0.1" - }, - "dependencies": { - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true - } } }, "is-string": { @@ -6325,12 +6464,6 @@ "object.assign": "^4.1.2" }, "dependencies": { - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true - }, "object.assign": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", @@ -6478,17 +6611,22 @@ "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=" }, + "math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==" + }, "mime-db": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" }, "mime-types": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", - "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "requires": { - "mime-db": "1.40.0" + "mime-db": "1.52.0" } }, "minimatch": { @@ -7500,14 +7638,6 @@ "internal-slot": "^1.0.2", "regexp.prototype.flags": "^1.3.0", "side-channel": "^1.0.3" - }, - "dependencies": { - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true - } } }, "strip-ansi": { diff --git a/package.json b/package.json index d5ccaa6..c130f56 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ "commander": "^2.9.0", "debug": "^2.2.0", "event-stream": "3.3.4", - "form-data": "3.0.0", + "form-data": "3.0.4", "fs-readfile-promise": "^2.0.1", "fs-writefile-promise": "^1.0.3", "har-validator": "^5.0.0" From fc3348bd600b2e3b21b5b3653b2c847b559a94dd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Jul 2025 09:59:14 +0000 Subject: [PATCH 09/36] chore(deps): bump ajv from 6.10.0 to 6.12.6 Bumps [ajv](https://github.com/ajv-validator/ajv) from 6.10.0 to 6.12.6. - [Release notes](https://github.com/ajv-validator/ajv/releases) - [Commits](https://github.com/ajv-validator/ajv/compare/v6.10.0...v6.12.6) --- updated-dependencies: - dependency-name: ajv dependency-version: 6.12.6 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 159 ++++++---------------------------------------- 1 file changed, 18 insertions(+), 141 deletions(-) diff --git a/package-lock.json b/package-lock.json index a484dcf..e374e88 100644 --- a/package-lock.json +++ b/package-lock.json @@ -128,22 +128,6 @@ "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/@eslint/eslintrc/node_modules/debug": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", @@ -161,12 +145,6 @@ } } }, - "node_modules/@eslint/eslintrc/node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, "node_modules/@eslint/eslintrc/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -225,14 +203,18 @@ } }, "node_modules/ajv": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", - "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dependencies": { - "fast-deep-equal": "^2.0.1", + "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, "node_modules/amdefine": { @@ -829,15 +811,6 @@ "node": ">=8.6" } }, - "node_modules/enquirer/node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -1681,9 +1654,9 @@ } }, "node_modules/fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-json-stable-stringify": { "version": "2.0.0", @@ -3851,15 +3824,6 @@ "node": ">=4" } }, - "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/source-map": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", @@ -4105,22 +4069,6 @@ "node": ">=6.0.0" } }, - "node_modules/table/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/table/node_modules/ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", @@ -4130,21 +4078,6 @@ "node": ">=6" } }, - "node_modules/table/node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/table/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/table/node_modules/string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -4693,18 +4626,6 @@ "strip-json-comments": "^3.1.1" }, "dependencies": { - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, "debug": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", @@ -4714,12 +4635,6 @@ "ms": "2.1.2" } }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -4766,11 +4681,11 @@ "requires": {} }, "ajv": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", - "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "requires": { - "fast-deep-equal": "^2.0.1", + "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" @@ -5235,14 +5150,6 @@ "dev": true, "requires": { "ansi-colors": "^4.1.1" - }, - "dependencies": { - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - } } }, "error-ex": { @@ -5855,9 +5762,9 @@ } }, "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "fast-json-stable-stringify": { "version": "2.0.0", @@ -7489,12 +7396,6 @@ "requires": { "color-convert": "^1.9.0" } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true } } }, @@ -7677,36 +7578,12 @@ "string-width": "^3.0.0" }, "dependencies": { - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", From d059b81bb40bb786945e75a8a34a4abf06291698 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Jul 2025 09:59:16 +0000 Subject: [PATCH 10/36] chore(deps-dev): bump braces from 3.0.2 to 3.0.3 Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3. - [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md) - [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3) --- updated-dependencies: - dependency-name: braces dependency-version: 3.0.3 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index a484dcf..1e158f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -386,12 +386,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -1709,9 +1709,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -4888,12 +4888,12 @@ } }, "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "requires": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" } }, "browser-stdout": { @@ -5880,9 +5880,9 @@ } }, "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "requires": { "to-regex-range": "^5.0.1" From 8fde5e74d64d6a5d8f7c73c0a4ffea7445f07c3d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Jul 2025 09:59:18 +0000 Subject: [PATCH 11/36] chore(deps-dev): bump json5 from 1.0.1 to 1.0.2 Bumps [json5](https://github.com/json5/json5) from 1.0.1 to 1.0.2. - [Release notes](https://github.com/json5/json5/releases) - [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md) - [Commits](https://github.com/json5/json5/compare/v1.0.1...v1.0.2) --- updated-dependencies: - dependency-name: json5 dependency-version: 1.0.2 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index a484dcf..5675536 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2470,9 +2470,9 @@ "dev": true }, "node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "dependencies": { "minimist": "^1.2.0" @@ -6446,9 +6446,9 @@ "dev": true }, "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "requires": { "minimist": "^1.2.0" From 9ba9fae0698b254d74a8e6fae12ee54473fa2da0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Mart=C3=ADnez=20Rinc=C3=B3n?= Date: Sun, 2 Nov 2025 22:16:55 +0100 Subject: [PATCH 12/36] feat: implement Sprint RestClient target --- TARGETS.md | 10 +++ src/targets/java/index.js | 3 +- src/targets/java/restclient.js | 81 +++++++++++++++++++ test/fixtures/available-targets.json | 6 ++ .../restclient/application-form-encoded.java | 10 +++ .../java/restclient/application-json.java | 10 +++ .../output/java/restclient/compression.java | 8 ++ .../output/java/restclient/cookies.java | 9 +++ .../output/java/restclient/custom-method.java | 7 ++ .../fixtures/output/java/restclient/full.java | 13 +++ .../output/java/restclient/headers.java | 10 +++ .../output/java/restclient/https.java | 7 ++ .../java/restclient/jsonObj-multiline.java | 10 +++ .../java/restclient/jsonObj-null-value.java | 10 +++ .../output/java/restclient/malicious.java | 25 ++++++ .../java/restclient/multipart-data.java | 10 +++ .../java/restclient/multipart-file.java | 10 +++ .../java/restclient/multipart-form-data.java | 10 +++ .../output/java/restclient/nested.java | 7 ++ .../output/java/restclient/query.java | 7 ++ .../output/java/restclient/short.java | 7 ++ .../output/java/restclient/text-plain.java | 10 +++ .../java/restclient/unparseable-query.java | 7 ++ test/targets/java/restclient.js | 5 ++ 24 files changed, 291 insertions(+), 1 deletion(-) create mode 100644 src/targets/java/restclient.js create mode 100644 test/fixtures/output/java/restclient/application-form-encoded.java create mode 100644 test/fixtures/output/java/restclient/application-json.java create mode 100644 test/fixtures/output/java/restclient/compression.java create mode 100644 test/fixtures/output/java/restclient/cookies.java create mode 100644 test/fixtures/output/java/restclient/custom-method.java create mode 100644 test/fixtures/output/java/restclient/full.java create mode 100644 test/fixtures/output/java/restclient/headers.java create mode 100644 test/fixtures/output/java/restclient/https.java create mode 100644 test/fixtures/output/java/restclient/jsonObj-multiline.java create mode 100644 test/fixtures/output/java/restclient/jsonObj-null-value.java create mode 100644 test/fixtures/output/java/restclient/malicious.java create mode 100644 test/fixtures/output/java/restclient/multipart-data.java create mode 100644 test/fixtures/output/java/restclient/multipart-file.java create mode 100644 test/fixtures/output/java/restclient/multipart-form-data.java create mode 100644 test/fixtures/output/java/restclient/nested.java create mode 100644 test/fixtures/output/java/restclient/query.java create mode 100644 test/fixtures/output/java/restclient/short.java create mode 100644 test/fixtures/output/java/restclient/text-plain.java create mode 100644 test/fixtures/output/java/restclient/unparseable-query.java create mode 100644 test/targets/java/restclient.js diff --git a/TARGETS.md b/TARGETS.md index 08d9986..786fcc4 100644 --- a/TARGETS.md +++ b/TARGETS.md @@ -40,6 +40,16 @@ Currently the following output targets are supported: | --------- | ------- | -------------------------------- | | `indent` | ` ` | line break & indent output value | +### [RestClient](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/RestClient.html) + +> Spring Framework REST client + +###### Options + +| Option | Default | Description | +| --------- | ------- | -------------------------------- | +| `indent` | ` ` | line break & indent output value | + ---- ## JavaScript diff --git a/src/targets/java/index.js b/src/targets/java/index.js index 37b0db7..ca0b259 100644 --- a/src/targets/java/index.js +++ b/src/targets/java/index.js @@ -11,5 +11,6 @@ module.exports = { okhttp: require('./okhttp'), unirest: require('./unirest'), asynchttp: require('./asynchttp'), - nethttp: require('./nethttp') + nethttp: require('./nethttp'), + restclient: require('./restclient') } diff --git a/src/targets/java/restclient.js b/src/targets/java/restclient.js new file mode 100644 index 0000000..dd98097 --- /dev/null +++ b/src/targets/java/restclient.js @@ -0,0 +1,81 @@ +/** + * @description + * HTTP code snippet generator for Java using Spring RestClient. + * + * @author + * @jamezrin + * + * for any questions or issues regarding the generated code snippet, please open an issue mentioning the author. + */ + +'use strict' + +const CodeBuilder = require('../../helpers/code-builder') + +const standardMethods = ['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'TRACE'] + +module.exports = function (source, options) { + const opts = Object.assign({ + indent: ' ' + }, options) + + const code = new CodeBuilder(opts.indent) + + code.push('RestClient restClient = RestClient.create();') + .blank() + + code.push('ResponseEntity response = restClient') + + if (standardMethods.includes(source.method.toUpperCase())) { + code.push(1, '.method(HttpMethod.%s)', source.method.toUpperCase()) + } else { + code.push(1, '.method(HttpMethod.valueOf("%s"))', source.method.toUpperCase()) + } + + code.push(1, '.uri("%s")', source.fullUrl) + + if (source.cookies && source.cookies.length) { + source.cookies.forEach(function (cookie) { + code.push(1, '.cookie("%s", "%s")', cookie.name, cookie.value) + }) + } + + const headers = Object.keys(source.allHeaders).filter(function (key) { + return key.toLowerCase() !== 'cookie' + }) + if (headers.length) { + headers.forEach(function (key) { + code.push(1, '.header("%s", "%qd")', key, source.allHeaders[key]) + }) + } + + if (source.postData && source.postData.text) { + if (source.postData.mimeType === 'application/json') { + code.push(1, '.contentType(MediaType.APPLICATION_JSON)') + code.push(1, '.body(%s)', JSON.stringify(source.postData.text)) + } else if (source.postData.mimeType === 'application/x-www-form-urlencoded') { + code.push(1, '.contentType(MediaType.APPLICATION_FORM_URLENCODED)') + code.push(1, '.body(%s)', JSON.stringify(source.postData.text)) + } else if (source.postData.mimeType && source.postData.mimeType.startsWith('multipart/form-data')) { + code.push(1, '.contentType(MediaType.parseMediaType("multipart/form-data"))') + code.push(1, '.body(%s)', JSON.stringify(source.postData.text)) + } else { + if (source.postData.mimeType) { + code.push(1, '.contentType(MediaType.parseMediaType("%s"))', source.postData.mimeType) + } + code.push(1, '.body(%s)', JSON.stringify(source.postData.text)) + } + } + + code.push(1, '.retrieve()') + code.push(1, '.toEntity(String.class);') + + return code.join() +} + +module.exports.info = { + key: 'restclient', + title: 'Spring RestClient', + link: 'https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/RestClient.html', + description: 'Spring Framework REST client' +} diff --git a/test/fixtures/available-targets.json b/test/fixtures/available-targets.json index 7ad7857..fa36970 100644 --- a/test/fixtures/available-targets.json +++ b/test/fixtures/available-targets.json @@ -226,6 +226,12 @@ "title": "java.net.http", "link": "https://openjdk.java.net/groups/net/httpclient/intro.html", "description": "Java Standardized HTTP Client API" + }, + { + "key": "restclient", + "title": "Spring RestClient", + "link": "https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/RestClient.html", + "description": "Spring Framework REST client" } ] }, diff --git a/test/fixtures/output/java/restclient/application-form-encoded.java b/test/fixtures/output/java/restclient/application-form-encoded.java new file mode 100644 index 0000000..a3b49de --- /dev/null +++ b/test/fixtures/output/java/restclient/application-form-encoded.java @@ -0,0 +1,10 @@ +RestClient restClient = RestClient.create(); + +ResponseEntity response = restClient + .method(HttpMethod.POST) + .uri("http://mockbin.com/har") + .header("content-type", "application/x-www-form-urlencoded") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .body("foo=bar&hello=world") + .retrieve() + .toEntity(String.class); \ No newline at end of file diff --git a/test/fixtures/output/java/restclient/application-json.java b/test/fixtures/output/java/restclient/application-json.java new file mode 100644 index 0000000..ebd7a8e --- /dev/null +++ b/test/fixtures/output/java/restclient/application-json.java @@ -0,0 +1,10 @@ +RestClient restClient = RestClient.create(); + +ResponseEntity response = restClient + .method(HttpMethod.POST) + .uri("http://mockbin.com/har") + .header("content-type", "application/json") + .contentType(MediaType.APPLICATION_JSON) + .body("{\"number\":1,\"string\":\"f\\\"oo\",\"arr\":[1,2,3],\"nested\":{\"a\":\"b\"},\"arr_mix\":[1,\"a\",{\"arr_mix_nested\":{}}],\"boolean\":false}") + .retrieve() + .toEntity(String.class); \ No newline at end of file diff --git a/test/fixtures/output/java/restclient/compression.java b/test/fixtures/output/java/restclient/compression.java new file mode 100644 index 0000000..056a80b --- /dev/null +++ b/test/fixtures/output/java/restclient/compression.java @@ -0,0 +1,8 @@ +RestClient restClient = RestClient.create(); + +ResponseEntity response = restClient + .method(HttpMethod.GET) + .uri("http://mockbin.com/har") + .header("accept-encoding", "deflate, gzip, br") + .retrieve() + .toEntity(String.class); \ No newline at end of file diff --git a/test/fixtures/output/java/restclient/cookies.java b/test/fixtures/output/java/restclient/cookies.java new file mode 100644 index 0000000..624d1fd --- /dev/null +++ b/test/fixtures/output/java/restclient/cookies.java @@ -0,0 +1,9 @@ +RestClient restClient = RestClient.create(); + +ResponseEntity response = restClient + .method(HttpMethod.POST) + .uri("http://mockbin.com/har") + .cookie("foo", "bar") + .cookie("bar", "baz") + .retrieve() + .toEntity(String.class); diff --git a/test/fixtures/output/java/restclient/custom-method.java b/test/fixtures/output/java/restclient/custom-method.java new file mode 100644 index 0000000..70eafc5 --- /dev/null +++ b/test/fixtures/output/java/restclient/custom-method.java @@ -0,0 +1,7 @@ +RestClient restClient = RestClient.create(); + +ResponseEntity response = restClient + .method(HttpMethod.valueOf("PROPFIND")) + .uri("http://mockbin.com/har") + .retrieve() + .toEntity(String.class); diff --git a/test/fixtures/output/java/restclient/full.java b/test/fixtures/output/java/restclient/full.java new file mode 100644 index 0000000..83327f0 --- /dev/null +++ b/test/fixtures/output/java/restclient/full.java @@ -0,0 +1,13 @@ +RestClient restClient = RestClient.create(); + +ResponseEntity response = restClient + .method(HttpMethod.POST) + .uri("http://mockbin.com/har?foo=bar&foo=baz&baz=abc&key=value") + .cookie("foo", "bar") + .cookie("bar", "baz") + .header("accept", "application/json") + .header("content-type", "application/x-www-form-urlencoded") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .body("foo=bar") + .retrieve() + .toEntity(String.class); diff --git a/test/fixtures/output/java/restclient/headers.java b/test/fixtures/output/java/restclient/headers.java new file mode 100644 index 0000000..229d844 --- /dev/null +++ b/test/fixtures/output/java/restclient/headers.java @@ -0,0 +1,10 @@ +RestClient restClient = RestClient.create(); + +ResponseEntity response = restClient + .method(HttpMethod.GET) + .uri("http://mockbin.com/har") + .header("accept", "application/json") + .header("x-foo", "Bar") + .header("quoted-value", "\"quoted\" 'string'") + .retrieve() + .toEntity(String.class); \ No newline at end of file diff --git a/test/fixtures/output/java/restclient/https.java b/test/fixtures/output/java/restclient/https.java new file mode 100644 index 0000000..0946263 --- /dev/null +++ b/test/fixtures/output/java/restclient/https.java @@ -0,0 +1,7 @@ +RestClient restClient = RestClient.create(); + +ResponseEntity response = restClient + .method(HttpMethod.GET) + .uri("https://mockbin.com/har") + .retrieve() + .toEntity(String.class); \ No newline at end of file diff --git a/test/fixtures/output/java/restclient/jsonObj-multiline.java b/test/fixtures/output/java/restclient/jsonObj-multiline.java new file mode 100644 index 0000000..ae0c92b --- /dev/null +++ b/test/fixtures/output/java/restclient/jsonObj-multiline.java @@ -0,0 +1,10 @@ +RestClient restClient = RestClient.create(); + +ResponseEntity response = restClient + .method(HttpMethod.POST) + .uri("http://mockbin.com/har") + .header("content-type", "application/json") + .contentType(MediaType.APPLICATION_JSON) + .body("{\n \"foo\": \"bar\"\n}") + .retrieve() + .toEntity(String.class); \ No newline at end of file diff --git a/test/fixtures/output/java/restclient/jsonObj-null-value.java b/test/fixtures/output/java/restclient/jsonObj-null-value.java new file mode 100644 index 0000000..f1b6a21 --- /dev/null +++ b/test/fixtures/output/java/restclient/jsonObj-null-value.java @@ -0,0 +1,10 @@ +RestClient restClient = RestClient.create(); + +ResponseEntity response = restClient + .method(HttpMethod.POST) + .uri("http://mockbin.com/har") + .header("content-type", "application/json") + .contentType(MediaType.APPLICATION_JSON) + .body("{\"foo\":null}") + .retrieve() + .toEntity(String.class); \ No newline at end of file diff --git a/test/fixtures/output/java/restclient/malicious.java b/test/fixtures/output/java/restclient/malicious.java new file mode 100644 index 0000000..535a860 --- /dev/null +++ b/test/fixtures/output/java/restclient/malicious.java @@ -0,0 +1,25 @@ +RestClient restClient = RestClient.create(); + +ResponseEntity response = restClient + .method(HttpMethod.POST) + .uri("http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//?'=squote-key-test&squote-value-test='&%22=dquote-key-test&dquote-value-test=%22&%60=backtick-key-test&backtick-value-test=%60&%24(=dollar-parenthesis-key-test&dollar-parenthesis-value-test=%24(&%23%7B=hash-brace-key-test&hash-brace-value-test=%23%7B&%25(=percent-parenthesis-key-test&percent-parenthesis-value-test=%25(&%25%7B=percent-brace-key-test&percent-brace-value-test=%25%7B&%7B%7B=double-brace-key-test&double-brace-value-test=%7B%7B&%5C0=null-key-test&null-value-test=%5C0&%25s=string-fmt-key-test&string-fmt-value-test=%25s&%5C=slash-key-test&slash-value-test=%5C") + .header("'", "squote-key-test") + .header("squote-value-test", "'") + .header("dquote-value-test", "\"") + .header("`", "backtick-key-test") + .header("backtick-value-test", "`") + .header("$", "dollar-key-test") + .header("dollar-parenthesis-value-test", "$(") + .header("#", "hash-key-test") + .header("hash-brace-value-test", "#{") + .header("%", "percent-key-test") + .header("percent-parenthesis-value-test", "%(") + .header("percent-brace-value-test", "%{") + .header("double-brace-value-test", "{{") + .header("null-value-test", "\\0") + .header("string-fmt-value-test", "%s") + .header("slash-value-test", "\\") + .contentType(MediaType.parseMediaType("text/plain")) + .body("' \" ` $( #{ %( %{ {{ \\0 %s \\") + .retrieve() + .toEntity(String.class); \ No newline at end of file diff --git a/test/fixtures/output/java/restclient/multipart-data.java b/test/fixtures/output/java/restclient/multipart-data.java new file mode 100644 index 0000000..842ac6e --- /dev/null +++ b/test/fixtures/output/java/restclient/multipart-data.java @@ -0,0 +1,10 @@ +RestClient restClient = RestClient.create(); + +ResponseEntity response = restClient + .method(HttpMethod.POST) + .uri("http://mockbin.com/har") + .header("content-type", "multipart/form-data; boundary=---011000010111000001101001") + .contentType(MediaType.parseMediaType("multipart/form-data")) + .body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"; filename=\"hello.txt\"\r\nContent-Type: text/plain\r\n\r\nHello World\r\n-----011000010111000001101001--\r\n") + .retrieve() + .toEntity(String.class); \ No newline at end of file diff --git a/test/fixtures/output/java/restclient/multipart-file.java b/test/fixtures/output/java/restclient/multipart-file.java new file mode 100644 index 0000000..bc60ffe --- /dev/null +++ b/test/fixtures/output/java/restclient/multipart-file.java @@ -0,0 +1,10 @@ +RestClient restClient = RestClient.create(); + +ResponseEntity response = restClient + .method(HttpMethod.POST) + .uri("http://mockbin.com/har") + .header("content-type", "multipart/form-data; boundary=---011000010111000001101001") + .contentType(MediaType.parseMediaType("multipart/form-data")) + .body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"; filename=\"hello.txt\"\r\nContent-Type: text/plain\r\n\r\n\r\n-----011000010111000001101001--\r\n") + .retrieve() + .toEntity(String.class); \ No newline at end of file diff --git a/test/fixtures/output/java/restclient/multipart-form-data.java b/test/fixtures/output/java/restclient/multipart-form-data.java new file mode 100644 index 0000000..c1422d0 --- /dev/null +++ b/test/fixtures/output/java/restclient/multipart-form-data.java @@ -0,0 +1,10 @@ +RestClient restClient = RestClient.create(); + +ResponseEntity response = restClient + .method(HttpMethod.POST) + .uri("http://mockbin.com/har") + .header("Content-Type", "multipart/form-data; boundary=---011000010111000001101001") + .contentType(MediaType.parseMediaType("multipart/form-data")) + .body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"\r\n\r\nbar\r\n-----011000010111000001101001--\r\n") + .retrieve() + .toEntity(String.class); \ No newline at end of file diff --git a/test/fixtures/output/java/restclient/nested.java b/test/fixtures/output/java/restclient/nested.java new file mode 100644 index 0000000..1a11770 --- /dev/null +++ b/test/fixtures/output/java/restclient/nested.java @@ -0,0 +1,7 @@ +RestClient restClient = RestClient.create(); + +ResponseEntity response = restClient + .method(HttpMethod.GET) + .uri("http://mockbin.com/har?foo%5Bbar%5D=baz%2Czap&fiz=buz&key=value") + .retrieve() + .toEntity(String.class); \ No newline at end of file diff --git a/test/fixtures/output/java/restclient/query.java b/test/fixtures/output/java/restclient/query.java new file mode 100644 index 0000000..f7df5fd --- /dev/null +++ b/test/fixtures/output/java/restclient/query.java @@ -0,0 +1,7 @@ +RestClient restClient = RestClient.create(); + +ResponseEntity response = restClient + .method(HttpMethod.GET) + .uri("http://mockbin.com/har?foo=bar&foo=baz&baz=abc&key=value") + .retrieve() + .toEntity(String.class); \ No newline at end of file diff --git a/test/fixtures/output/java/restclient/short.java b/test/fixtures/output/java/restclient/short.java new file mode 100644 index 0000000..b100f40 --- /dev/null +++ b/test/fixtures/output/java/restclient/short.java @@ -0,0 +1,7 @@ +RestClient restClient = RestClient.create(); + +ResponseEntity response = restClient + .method(HttpMethod.GET) + .uri("http://mockbin.com/har") + .retrieve() + .toEntity(String.class); \ No newline at end of file diff --git a/test/fixtures/output/java/restclient/text-plain.java b/test/fixtures/output/java/restclient/text-plain.java new file mode 100644 index 0000000..1a64732 --- /dev/null +++ b/test/fixtures/output/java/restclient/text-plain.java @@ -0,0 +1,10 @@ +RestClient restClient = RestClient.create(); + +ResponseEntity response = restClient + .method(HttpMethod.POST) + .uri("http://mockbin.com/har") + .header("content-type", "text/plain") + .contentType(MediaType.parseMediaType("text/plain")) + .body("Hello World") + .retrieve() + .toEntity(String.class); \ No newline at end of file diff --git a/test/fixtures/output/java/restclient/unparseable-query.java b/test/fixtures/output/java/restclient/unparseable-query.java new file mode 100644 index 0000000..6d64f6c --- /dev/null +++ b/test/fixtures/output/java/restclient/unparseable-query.java @@ -0,0 +1,7 @@ +RestClient restClient = RestClient.create(); + +ResponseEntity response = restClient + .method(HttpMethod.GET) + .uri("http://mockbin.com/har?&&a=b&&") + .retrieve() + .toEntity(String.class); \ No newline at end of file diff --git a/test/targets/java/restclient.js b/test/targets/java/restclient.js new file mode 100644 index 0000000..9ad8c17 --- /dev/null +++ b/test/targets/java/restclient.js @@ -0,0 +1,5 @@ +'use strict' + +require('should') + +module.exports = function (snippet, fixtures) {} From f1b2251729e5284b9500872858d0ea26f3187ec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Mart=C3=ADnez=20Rinc=C3=B3n?= Date: Sun, 2 Nov 2025 23:12:13 +0100 Subject: [PATCH 13/36] refactor: query and content-type --- src/targets/java/restclient.js | 76 ++++++++++++++----- .../fixtures/output/java/restclient/full.java | 8 +- .../output/java/restclient/malicious.java | 30 +++++++- .../java/restclient/multipart-data.java | 4 +- .../java/restclient/multipart-file.java | 4 +- .../java/restclient/multipart-form-data.java | 4 +- .../output/java/restclient/nested.java | 9 ++- .../output/java/restclient/query.java | 10 ++- .../output/java/restclient/text-plain.java | 4 +- 9 files changed, 115 insertions(+), 34 deletions(-) diff --git a/src/targets/java/restclient.js b/src/targets/java/restclient.js index dd98097..96bfebd 100644 --- a/src/targets/java/restclient.js +++ b/src/targets/java/restclient.js @@ -12,8 +12,39 @@ const CodeBuilder = require('../../helpers/code-builder') +// Based off org.springframework.http.HttpMethod const standardMethods = ['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'TRACE'] +// Based off org.springframework.http.MediaType +const standardMediaTypes = { + 'application/atom+xml': 'APPLICATION_ATOM_XML', + 'application/cbor': 'APPLICATION_CBOR', + 'application/x-www-form-urlencoded': 'APPLICATION_FORM_URLENCODED', + 'application/graphql-response+json': 'APPLICATION_GRAPHQL_RESPONSE', + 'application/json': 'APPLICATION_JSON', + 'application/x-ndjson': 'APPLICATION_NDJSON', + 'application/octet-stream': 'APPLICATION_OCTET_STREAM', + 'application/pdf': 'APPLICATION_PDF', + 'application/problem+json': 'APPLICATION_PROBLEM_JSON', + 'application/problem+xml': 'APPLICATION_PROBLEM_XML', + 'application/x-protobuf': 'APPLICATION_PROTOBUF', + 'application/rss+xml': 'APPLICATION_RSS_XML', + 'application/xhtml+xml': 'APPLICATION_XHTML_XML', + 'application/xml': 'APPLICATION_XML', + 'application/yaml': 'APPLICATION_YAML', + 'image/gif': 'IMAGE_GIF', + 'image/jpeg': 'IMAGE_JPEG', + 'image/png': 'IMAGE_PNG', + 'multipart/form-data': 'MULTIPART_FORM_DATA', + 'multipart/mixed': 'MULTIPART_MIXED', + 'multipart/related': 'MULTIPART_RELATED', + 'text/event-stream': 'TEXT_EVENT_STREAM', + 'text/html': 'TEXT_HTML', + 'text/markdown': 'TEXT_MARKDOWN', + 'text/plain': 'TEXT_PLAIN', + 'text/xml': 'TEXT_XML' +} + module.exports = function (source, options) { const opts = Object.assign({ indent: ' ' @@ -32,39 +63,48 @@ module.exports = function (source, options) { code.push(1, '.method(HttpMethod.valueOf("%s"))', source.method.toUpperCase()) } - code.push(1, '.uri("%s")', source.fullUrl) + if (Object.keys(source.queryObj).length) { + code.push(1, '.uri("%s", uriBuilder -> {', source.url) + Object.keys(source.queryObj).forEach(function (key) { + const value = source.queryObj[key] + if (Array.isArray(value)) { + value.forEach(function (val) { + code.push(2, 'uriBuilder.queryParam("%qd", "%qd");', key, val) + }) + } else { + code.push(2, 'uriBuilder.queryParam("%qd", "%qd");', key, value) + } + }) + code.push(2, 'return uriBuilder.build();') + code.push(1, '})') + } else { + code.push(1, '.uri("%s")', source.url) + } if (source.cookies && source.cookies.length) { source.cookies.forEach(function (cookie) { - code.push(1, '.cookie("%s", "%s")', cookie.name, cookie.value) + code.push(1, '.cookie("%qd", "%qd")', cookie.name, cookie.value) }) } - const headers = Object.keys(source.allHeaders).filter(function (key) { - return key.toLowerCase() !== 'cookie' - }) + const headers = Object.keys(source.headersObj) if (headers.length) { headers.forEach(function (key) { - code.push(1, '.header("%s", "%qd")', key, source.allHeaders[key]) + code.push(1, '.header("%s", "%qd")', key, source.headersObj[key]) }) } if (source.postData && source.postData.text) { - if (source.postData.mimeType === 'application/json') { - code.push(1, '.contentType(MediaType.APPLICATION_JSON)') - code.push(1, '.body(%s)', JSON.stringify(source.postData.text)) - } else if (source.postData.mimeType === 'application/x-www-form-urlencoded') { - code.push(1, '.contentType(MediaType.APPLICATION_FORM_URLENCODED)') - code.push(1, '.body(%s)', JSON.stringify(source.postData.text)) - } else if (source.postData.mimeType && source.postData.mimeType.startsWith('multipart/form-data')) { - code.push(1, '.contentType(MediaType.parseMediaType("multipart/form-data"))') - code.push(1, '.body(%s)', JSON.stringify(source.postData.text)) - } else { - if (source.postData.mimeType) { + if (source.postData.mimeType) { + const mappedEnumConst = standardMediaTypes[source.postData.mimeType] + if (mappedEnumConst) { + code.push(1, '.contentType(MediaType.%s)', mappedEnumConst) + } else { code.push(1, '.contentType(MediaType.parseMediaType("%s"))', source.postData.mimeType) } - code.push(1, '.body(%s)', JSON.stringify(source.postData.text)) } + + code.push(1, '.body(%s)', JSON.stringify(source.postData.text)) } code.push(1, '.retrieve()') diff --git a/test/fixtures/output/java/restclient/full.java b/test/fixtures/output/java/restclient/full.java index 83327f0..6f2110c 100644 --- a/test/fixtures/output/java/restclient/full.java +++ b/test/fixtures/output/java/restclient/full.java @@ -2,7 +2,13 @@ ResponseEntity response = restClient .method(HttpMethod.POST) - .uri("http://mockbin.com/har?foo=bar&foo=baz&baz=abc&key=value") + .uri("http://mockbin.com/har", uriBuilder -> { + uriBuilder.queryParam("foo", "bar"); + uriBuilder.queryParam("foo", "baz"); + uriBuilder.queryParam("baz", "abc"); + uriBuilder.queryParam("key", "value"); + return uriBuilder.build(); + }) .cookie("foo", "bar") .cookie("bar", "baz") .header("accept", "application/json") diff --git a/test/fixtures/output/java/restclient/malicious.java b/test/fixtures/output/java/restclient/malicious.java index 535a860..9919ca1 100644 --- a/test/fixtures/output/java/restclient/malicious.java +++ b/test/fixtures/output/java/restclient/malicious.java @@ -2,7 +2,31 @@ ResponseEntity response = restClient .method(HttpMethod.POST) - .uri("http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//?'=squote-key-test&squote-value-test='&%22=dquote-key-test&dquote-value-test=%22&%60=backtick-key-test&backtick-value-test=%60&%24(=dollar-parenthesis-key-test&dollar-parenthesis-value-test=%24(&%23%7B=hash-brace-key-test&hash-brace-value-test=%23%7B&%25(=percent-parenthesis-key-test&percent-parenthesis-value-test=%25(&%25%7B=percent-brace-key-test&percent-brace-value-test=%25%7B&%7B%7B=double-brace-key-test&double-brace-value-test=%7B%7B&%5C0=null-key-test&null-value-test=%5C0&%25s=string-fmt-key-test&string-fmt-value-test=%25s&%5C=slash-key-test&slash-value-test=%5C") + .uri("http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//", uriBuilder -> { + uriBuilder.queryParam("'", "squote-key-test"); + uriBuilder.queryParam("squote-value-test", "'"); + uriBuilder.queryParam("\"", "dquote-key-test"); + uriBuilder.queryParam("dquote-value-test", "\""); + uriBuilder.queryParam("`", "backtick-key-test"); + uriBuilder.queryParam("backtick-value-test", "`"); + uriBuilder.queryParam("$(", "dollar-parenthesis-key-test"); + uriBuilder.queryParam("dollar-parenthesis-value-test", "$("); + uriBuilder.queryParam("#{", "hash-brace-key-test"); + uriBuilder.queryParam("hash-brace-value-test", "#{"); + uriBuilder.queryParam("%(", "percent-parenthesis-key-test"); + uriBuilder.queryParam("percent-parenthesis-value-test", "%("); + uriBuilder.queryParam("%{", "percent-brace-key-test"); + uriBuilder.queryParam("percent-brace-value-test", "%{"); + uriBuilder.queryParam("{{", "double-brace-key-test"); + uriBuilder.queryParam("double-brace-value-test", "{{"); + uriBuilder.queryParam("\\0", "null-key-test"); + uriBuilder.queryParam("null-value-test", "\\0"); + uriBuilder.queryParam("%s", "string-fmt-key-test"); + uriBuilder.queryParam("string-fmt-value-test", "%s"); + uriBuilder.queryParam("\\", "slash-key-test"); + uriBuilder.queryParam("slash-value-test", "\\"); + return uriBuilder.build(); + }) .header("'", "squote-key-test") .header("squote-value-test", "'") .header("dquote-value-test", "\"") @@ -19,7 +43,7 @@ .header("null-value-test", "\\0") .header("string-fmt-value-test", "%s") .header("slash-value-test", "\\") - .contentType(MediaType.parseMediaType("text/plain")) + .contentType(MediaType.TEXT_PLAIN) .body("' \" ` $( #{ %( %{ {{ \\0 %s \\") .retrieve() - .toEntity(String.class); \ No newline at end of file + .toEntity(String.class); diff --git a/test/fixtures/output/java/restclient/multipart-data.java b/test/fixtures/output/java/restclient/multipart-data.java index 842ac6e..611d584 100644 --- a/test/fixtures/output/java/restclient/multipart-data.java +++ b/test/fixtures/output/java/restclient/multipart-data.java @@ -4,7 +4,7 @@ .method(HttpMethod.POST) .uri("http://mockbin.com/har") .header("content-type", "multipart/form-data; boundary=---011000010111000001101001") - .contentType(MediaType.parseMediaType("multipart/form-data")) + .contentType(MediaType.MULTIPART_FORM_DATA) .body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"; filename=\"hello.txt\"\r\nContent-Type: text/plain\r\n\r\nHello World\r\n-----011000010111000001101001--\r\n") .retrieve() - .toEntity(String.class); \ No newline at end of file + .toEntity(String.class); diff --git a/test/fixtures/output/java/restclient/multipart-file.java b/test/fixtures/output/java/restclient/multipart-file.java index bc60ffe..2354491 100644 --- a/test/fixtures/output/java/restclient/multipart-file.java +++ b/test/fixtures/output/java/restclient/multipart-file.java @@ -4,7 +4,7 @@ .method(HttpMethod.POST) .uri("http://mockbin.com/har") .header("content-type", "multipart/form-data; boundary=---011000010111000001101001") - .contentType(MediaType.parseMediaType("multipart/form-data")) + .contentType(MediaType.MULTIPART_FORM_DATA) .body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"; filename=\"hello.txt\"\r\nContent-Type: text/plain\r\n\r\n\r\n-----011000010111000001101001--\r\n") .retrieve() - .toEntity(String.class); \ No newline at end of file + .toEntity(String.class); diff --git a/test/fixtures/output/java/restclient/multipart-form-data.java b/test/fixtures/output/java/restclient/multipart-form-data.java index c1422d0..4fe35c6 100644 --- a/test/fixtures/output/java/restclient/multipart-form-data.java +++ b/test/fixtures/output/java/restclient/multipart-form-data.java @@ -4,7 +4,7 @@ .method(HttpMethod.POST) .uri("http://mockbin.com/har") .header("Content-Type", "multipart/form-data; boundary=---011000010111000001101001") - .contentType(MediaType.parseMediaType("multipart/form-data")) + .contentType(MediaType.MULTIPART_FORM_DATA) .body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"\r\n\r\nbar\r\n-----011000010111000001101001--\r\n") .retrieve() - .toEntity(String.class); \ No newline at end of file + .toEntity(String.class); diff --git a/test/fixtures/output/java/restclient/nested.java b/test/fixtures/output/java/restclient/nested.java index 1a11770..53b6846 100644 --- a/test/fixtures/output/java/restclient/nested.java +++ b/test/fixtures/output/java/restclient/nested.java @@ -2,6 +2,11 @@ ResponseEntity response = restClient .method(HttpMethod.GET) - .uri("http://mockbin.com/har?foo%5Bbar%5D=baz%2Czap&fiz=buz&key=value") + .uri("http://mockbin.com/har", uriBuilder -> { + uriBuilder.queryParam("foo[bar]", "baz,zap"); + uriBuilder.queryParam("fiz", "buz"); + uriBuilder.queryParam("key", "value"); + return uriBuilder.build(); + }) .retrieve() - .toEntity(String.class); \ No newline at end of file + .toEntity(String.class); diff --git a/test/fixtures/output/java/restclient/query.java b/test/fixtures/output/java/restclient/query.java index f7df5fd..7979608 100644 --- a/test/fixtures/output/java/restclient/query.java +++ b/test/fixtures/output/java/restclient/query.java @@ -2,6 +2,12 @@ ResponseEntity response = restClient .method(HttpMethod.GET) - .uri("http://mockbin.com/har?foo=bar&foo=baz&baz=abc&key=value") + .uri("http://mockbin.com/har", uriBuilder -> { + uriBuilder.queryParam("foo", "bar"); + uriBuilder.queryParam("foo", "baz"); + uriBuilder.queryParam("baz", "abc"); + uriBuilder.queryParam("key", "value"); + return uriBuilder.build(); + }) .retrieve() - .toEntity(String.class); \ No newline at end of file + .toEntity(String.class); diff --git a/test/fixtures/output/java/restclient/text-plain.java b/test/fixtures/output/java/restclient/text-plain.java index 1a64732..1738077 100644 --- a/test/fixtures/output/java/restclient/text-plain.java +++ b/test/fixtures/output/java/restclient/text-plain.java @@ -4,7 +4,7 @@ .method(HttpMethod.POST) .uri("http://mockbin.com/har") .header("content-type", "text/plain") - .contentType(MediaType.parseMediaType("text/plain")) + .contentType(MediaType.TEXT_PLAIN) .body("Hello World") .retrieve() - .toEntity(String.class); \ No newline at end of file + .toEntity(String.class); From cd53b68efa15edccbdd4265113974655f07c09de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Mart=C3=ADnez=20Rinc=C3=B3n?= Date: Sun, 2 Nov 2025 23:19:46 +0100 Subject: [PATCH 14/36] feat: add option for specifying returned entity class --- src/targets/java/restclient.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/targets/java/restclient.js b/src/targets/java/restclient.js index 96bfebd..055f634 100644 --- a/src/targets/java/restclient.js +++ b/src/targets/java/restclient.js @@ -47,7 +47,8 @@ const standardMediaTypes = { module.exports = function (source, options) { const opts = Object.assign({ - indent: ' ' + indent: ' ', + entityClass: 'String' }, options) const code = new CodeBuilder(opts.indent) @@ -55,7 +56,7 @@ module.exports = function (source, options) { code.push('RestClient restClient = RestClient.create();') .blank() - code.push('ResponseEntity response = restClient') + code.push('ResponseEntity<%s> response = restClient', opts.entityClass) if (standardMethods.includes(source.method.toUpperCase())) { code.push(1, '.method(HttpMethod.%s)', source.method.toUpperCase()) @@ -108,7 +109,7 @@ module.exports = function (source, options) { } code.push(1, '.retrieve()') - code.push(1, '.toEntity(String.class);') + code.push(1, '.toEntity(%s.class);', opts.entityClass) return code.join() } From 1248f431b322b14a987111b52b7604edf40b3e19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Mart=C3=ADnez=20Rinc=C3=B3n?= Date: Mon, 3 Nov 2025 00:08:58 +0100 Subject: [PATCH 15/36] refactor: support multipart and general cleanup --- src/targets/java/restclient.js | 82 ++++++++++++++++--- .../restclient/application-form-encoded.java | 9 +- .../java/restclient/application-json.java | 3 +- .../fixtures/output/java/restclient/full.java | 6 +- .../java/restclient/jsonObj-multiline.java | 3 +- .../java/restclient/jsonObj-null-value.java | 3 +- .../java/restclient/multipart-data.java | 8 +- .../java/restclient/multipart-file.java | 7 +- .../java/restclient/multipart-form-data.java | 6 +- .../output/java/restclient/text-plain.java | 1 - 10 files changed, 98 insertions(+), 30 deletions(-) diff --git a/src/targets/java/restclient.js b/src/targets/java/restclient.js index 055f634..9d6a2db 100644 --- a/src/targets/java/restclient.js +++ b/src/targets/java/restclient.js @@ -12,10 +12,8 @@ const CodeBuilder = require('../../helpers/code-builder') -// Based off org.springframework.http.HttpMethod const standardMethods = ['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'TRACE'] -// Based off org.springframework.http.MediaType const standardMediaTypes = { 'application/atom+xml': 'APPLICATION_ATOM_XML', 'application/cbor': 'APPLICATION_CBOR', @@ -45,6 +43,20 @@ const standardMediaTypes = { 'text/xml': 'TEXT_XML' } +const jsonMimeTypes = [ + 'application/json', + 'text/json', + 'text/x-json', + 'application/x-json' +] + +const multipartMimeTypes = [ + 'multipart/form-data', + 'multipart/mixed', + 'multipart/related', + 'multipart/alternative' +] + module.exports = function (source, options) { const opts = Object.assign({ indent: ' ', @@ -56,6 +68,43 @@ module.exports = function (source, options) { code.push('RestClient restClient = RestClient.create();') .blank() + if (source.postData && source.postData.mimeType === 'application/x-www-form-urlencoded' && source.postData.params) { + code.push('MultiValueMap formDataMap = new LinkedMultiValueMap<>();') + source.postData.params.forEach(function (param) { + code.push('formDataMap.add("%qd", "%qd");', param.name, param.value) + }) + code.blank() + } + + if (source.postData && multipartMimeTypes.includes(source.postData.mimeType) && source.postData.params) { + code.push('MultipartBodyBuilder multipartBuilder = new MultipartBodyBuilder();') + + source.postData.params.forEach(function (param) { + if (param.fileName) { + if (param.value) { + code.push('multipartBuilder.part("%s", "%qd")', param.name, param.value) + code.push(1, '.filename("%s")', param.fileName) + } else { + code.push('multipartBuilder.part("%s", new FileSystemResource("%s"))', param.name, param.fileName) + } + + if (param.contentType) { + const mediaTypeConstant = standardMediaTypes[param.contentType] + if (mediaTypeConstant) { + code.push(1, '.contentType(MediaType.%s);', mediaTypeConstant) + } else { + code.push(1, '.contentType(MediaType.parseMediaType("%s"));', param.contentType) + } + } else { + code.push(1, ';') + } + } else { + code.push('multipartBuilder.part("%s", "%qd");', param.name, param.value || '') + } + }) + code.blank() + } + code.push('ResponseEntity<%s> response = restClient', opts.entityClass) if (standardMethods.includes(source.method.toUpperCase())) { @@ -91,21 +140,30 @@ module.exports = function (source, options) { const headers = Object.keys(source.headersObj) if (headers.length) { headers.forEach(function (key) { - code.push(1, '.header("%s", "%qd")', key, source.headersObj[key]) + if (key.toLowerCase() !== 'content-type') { + code.push(1, '.header("%s", "%qd")', key, source.headersObj[key]) + } }) } - if (source.postData && source.postData.text) { - if (source.postData.mimeType) { - const mappedEnumConst = standardMediaTypes[source.postData.mimeType] - if (mappedEnumConst) { - code.push(1, '.contentType(MediaType.%s)', mappedEnumConst) - } else { - code.push(1, '.contentType(MediaType.parseMediaType("%s"))', source.postData.mimeType) - } + if (source.postData && (source.postData.params || source.postData.text)) { + const mediaTypeEnumConstant = standardMediaTypes[source.postData.mimeType] + + if (mediaTypeEnumConstant) { + code.push(1, '.contentType(MediaType.%s)', mediaTypeEnumConstant) + } else { + code.push(1, '.contentType(MediaType.parseMediaType("%s"))', source.postData.mimeType) } - code.push(1, '.body(%s)', JSON.stringify(source.postData.text)) + if (source.postData.mimeType === 'application/x-www-form-urlencoded' && source.postData.params) { + code.push(1, '.body(formDataMap)') + } else if (multipartMimeTypes.includes(source.postData.mimeType) && source.postData.params) { + code.push(1, '.body(multipartBuilder.build())') + } else if (source.postData.text) { + code.push(1, '.body(%s)', JSON.stringify(source.postData.text)) + } else if (source.postData.jsonObj && jsonMimeTypes.includes(source.postData.mimeType)) { + code.push(1, '.body(%s)', JSON.stringify(JSON.stringify(source.postData.jsonObj))) + } } code.push(1, '.retrieve()') diff --git a/test/fixtures/output/java/restclient/application-form-encoded.java b/test/fixtures/output/java/restclient/application-form-encoded.java index a3b49de..63b17ff 100644 --- a/test/fixtures/output/java/restclient/application-form-encoded.java +++ b/test/fixtures/output/java/restclient/application-form-encoded.java @@ -1,10 +1,13 @@ RestClient restClient = RestClient.create(); +MultiValueMap formDataMap = new LinkedMultiValueMap<>(); +formDataMap.add("foo", "bar"); +formDataMap.add("hello", "world"); + ResponseEntity response = restClient .method(HttpMethod.POST) .uri("http://mockbin.com/har") - .header("content-type", "application/x-www-form-urlencoded") .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .body("foo=bar&hello=world") + .body(formDataMap) .retrieve() - .toEntity(String.class); \ No newline at end of file + .toEntity(String.class); diff --git a/test/fixtures/output/java/restclient/application-json.java b/test/fixtures/output/java/restclient/application-json.java index ebd7a8e..5d12031 100644 --- a/test/fixtures/output/java/restclient/application-json.java +++ b/test/fixtures/output/java/restclient/application-json.java @@ -3,8 +3,7 @@ ResponseEntity response = restClient .method(HttpMethod.POST) .uri("http://mockbin.com/har") - .header("content-type", "application/json") .contentType(MediaType.APPLICATION_JSON) .body("{\"number\":1,\"string\":\"f\\\"oo\",\"arr\":[1,2,3],\"nested\":{\"a\":\"b\"},\"arr_mix\":[1,\"a\",{\"arr_mix_nested\":{}}],\"boolean\":false}") .retrieve() - .toEntity(String.class); \ No newline at end of file + .toEntity(String.class); diff --git a/test/fixtures/output/java/restclient/full.java b/test/fixtures/output/java/restclient/full.java index 6f2110c..8126f6d 100644 --- a/test/fixtures/output/java/restclient/full.java +++ b/test/fixtures/output/java/restclient/full.java @@ -1,5 +1,8 @@ RestClient restClient = RestClient.create(); +MultiValueMap formDataMap = new LinkedMultiValueMap<>(); +formDataMap.add("foo", "bar"); + ResponseEntity response = restClient .method(HttpMethod.POST) .uri("http://mockbin.com/har", uriBuilder -> { @@ -12,8 +15,7 @@ .cookie("foo", "bar") .cookie("bar", "baz") .header("accept", "application/json") - .header("content-type", "application/x-www-form-urlencoded") .contentType(MediaType.APPLICATION_FORM_URLENCODED) - .body("foo=bar") + .body(formDataMap) .retrieve() .toEntity(String.class); diff --git a/test/fixtures/output/java/restclient/jsonObj-multiline.java b/test/fixtures/output/java/restclient/jsonObj-multiline.java index ae0c92b..71a2fbe 100644 --- a/test/fixtures/output/java/restclient/jsonObj-multiline.java +++ b/test/fixtures/output/java/restclient/jsonObj-multiline.java @@ -3,8 +3,7 @@ ResponseEntity response = restClient .method(HttpMethod.POST) .uri("http://mockbin.com/har") - .header("content-type", "application/json") .contentType(MediaType.APPLICATION_JSON) .body("{\n \"foo\": \"bar\"\n}") .retrieve() - .toEntity(String.class); \ No newline at end of file + .toEntity(String.class); diff --git a/test/fixtures/output/java/restclient/jsonObj-null-value.java b/test/fixtures/output/java/restclient/jsonObj-null-value.java index f1b6a21..8b3f17b 100644 --- a/test/fixtures/output/java/restclient/jsonObj-null-value.java +++ b/test/fixtures/output/java/restclient/jsonObj-null-value.java @@ -3,8 +3,7 @@ ResponseEntity response = restClient .method(HttpMethod.POST) .uri("http://mockbin.com/har") - .header("content-type", "application/json") .contentType(MediaType.APPLICATION_JSON) .body("{\"foo\":null}") .retrieve() - .toEntity(String.class); \ No newline at end of file + .toEntity(String.class); diff --git a/test/fixtures/output/java/restclient/multipart-data.java b/test/fixtures/output/java/restclient/multipart-data.java index 611d584..ef5d723 100644 --- a/test/fixtures/output/java/restclient/multipart-data.java +++ b/test/fixtures/output/java/restclient/multipart-data.java @@ -1,10 +1,14 @@ RestClient restClient = RestClient.create(); +MultipartBodyBuilder multipartBuilder = new MultipartBodyBuilder(); +multipartBuilder.part("foo", "Hello World") + .filename("hello.txt") + .contentType(MediaType.TEXT_PLAIN); + ResponseEntity response = restClient .method(HttpMethod.POST) .uri("http://mockbin.com/har") - .header("content-type", "multipart/form-data; boundary=---011000010111000001101001") .contentType(MediaType.MULTIPART_FORM_DATA) - .body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"; filename=\"hello.txt\"\r\nContent-Type: text/plain\r\n\r\nHello World\r\n-----011000010111000001101001--\r\n") + .body(multipartBuilder.build()) .retrieve() .toEntity(String.class); diff --git a/test/fixtures/output/java/restclient/multipart-file.java b/test/fixtures/output/java/restclient/multipart-file.java index 2354491..1144288 100644 --- a/test/fixtures/output/java/restclient/multipart-file.java +++ b/test/fixtures/output/java/restclient/multipart-file.java @@ -1,10 +1,13 @@ RestClient restClient = RestClient.create(); +MultipartBodyBuilder multipartBuilder = new MultipartBodyBuilder(); +multipartBuilder.part("foo", new FileSystemResource("test/fixtures/files/hello.txt")) + .contentType(MediaType.TEXT_PLAIN); + ResponseEntity response = restClient .method(HttpMethod.POST) .uri("http://mockbin.com/har") - .header("content-type", "multipart/form-data; boundary=---011000010111000001101001") .contentType(MediaType.MULTIPART_FORM_DATA) - .body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"; filename=\"hello.txt\"\r\nContent-Type: text/plain\r\n\r\n\r\n-----011000010111000001101001--\r\n") + .body(multipartBuilder.build()) .retrieve() .toEntity(String.class); diff --git a/test/fixtures/output/java/restclient/multipart-form-data.java b/test/fixtures/output/java/restclient/multipart-form-data.java index 4fe35c6..604d426 100644 --- a/test/fixtures/output/java/restclient/multipart-form-data.java +++ b/test/fixtures/output/java/restclient/multipart-form-data.java @@ -1,10 +1,12 @@ RestClient restClient = RestClient.create(); +MultipartBodyBuilder multipartBuilder = new MultipartBodyBuilder(); +multipartBuilder.part("foo", "bar"); + ResponseEntity response = restClient .method(HttpMethod.POST) .uri("http://mockbin.com/har") - .header("Content-Type", "multipart/form-data; boundary=---011000010111000001101001") .contentType(MediaType.MULTIPART_FORM_DATA) - .body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"\r\n\r\nbar\r\n-----011000010111000001101001--\r\n") + .body(multipartBuilder.build()) .retrieve() .toEntity(String.class); diff --git a/test/fixtures/output/java/restclient/text-plain.java b/test/fixtures/output/java/restclient/text-plain.java index 1738077..8aef2bf 100644 --- a/test/fixtures/output/java/restclient/text-plain.java +++ b/test/fixtures/output/java/restclient/text-plain.java @@ -3,7 +3,6 @@ ResponseEntity response = restClient .method(HttpMethod.POST) .uri("http://mockbin.com/har") - .header("content-type", "text/plain") .contentType(MediaType.TEXT_PLAIN) .body("Hello World") .retrieve() From 24ed2ab8ddc817a652967853a5dd4823fcc5a949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Mart=C3=ADnez=20Rinc=C3=B3n?= Date: Mon, 3 Nov 2025 00:54:05 +0100 Subject: [PATCH 16/36] chore: rename option for entity class and document it --- TARGETS.md | 7 ++++--- src/targets/java/restclient.js | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/TARGETS.md b/TARGETS.md index 786fcc4..e855002 100644 --- a/TARGETS.md +++ b/TARGETS.md @@ -46,9 +46,10 @@ Currently the following output targets are supported: ###### Options -| Option | Default | Description | -| --------- | ------- | -------------------------------- | -| `indent` | ` ` | line break & indent output value | +| Option | Default | Description | +| ------------ | -------- | -------------------------------- | +| `indent` | ` ` | line break & indent output value | +| `entityType` | `String` | Java type for the entity | ---- diff --git a/src/targets/java/restclient.js b/src/targets/java/restclient.js index 9d6a2db..07b672c 100644 --- a/src/targets/java/restclient.js +++ b/src/targets/java/restclient.js @@ -60,7 +60,7 @@ const multipartMimeTypes = [ module.exports = function (source, options) { const opts = Object.assign({ indent: ' ', - entityClass: 'String' + entityType: 'String' }, options) const code = new CodeBuilder(opts.indent) @@ -105,7 +105,7 @@ module.exports = function (source, options) { code.blank() } - code.push('ResponseEntity<%s> response = restClient', opts.entityClass) + code.push('ResponseEntity<%s> response = restClient', opts.entityType) if (standardMethods.includes(source.method.toUpperCase())) { code.push(1, '.method(HttpMethod.%s)', source.method.toUpperCase()) @@ -167,7 +167,7 @@ module.exports = function (source, options) { } code.push(1, '.retrieve()') - code.push(1, '.toEntity(%s.class);', opts.entityClass) + code.push(1, '.toEntity(%s.class);', opts.entityType) return code.join() } From 7b5e1180d5ecf45712bd07cd947bc1779d99a8b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Mart=C3=ADnez=20Rinc=C3=B3n?= Date: Mon, 3 Nov 2025 21:45:49 +0100 Subject: [PATCH 17/36] refactor: body building --- src/targets/java/restclient.js | 101 +++++++++++++++++---------------- 1 file changed, 53 insertions(+), 48 deletions(-) diff --git a/src/targets/java/restclient.js b/src/targets/java/restclient.js index 07b672c..78d4d74 100644 --- a/src/targets/java/restclient.js +++ b/src/targets/java/restclient.js @@ -43,13 +43,6 @@ const standardMediaTypes = { 'text/xml': 'TEXT_XML' } -const jsonMimeTypes = [ - 'application/json', - 'text/json', - 'text/x-json', - 'application/x-json' -] - const multipartMimeTypes = [ 'multipart/form-data', 'multipart/mixed', @@ -63,46 +56,59 @@ module.exports = function (source, options) { entityType: 'String' }, options) + const state = { + bodyType: null + } + const code = new CodeBuilder(opts.indent) code.push('RestClient restClient = RestClient.create();') .blank() - if (source.postData && source.postData.mimeType === 'application/x-www-form-urlencoded' && source.postData.params) { - code.push('MultiValueMap formDataMap = new LinkedMultiValueMap<>();') - source.postData.params.forEach(function (param) { - code.push('formDataMap.add("%qd", "%qd");', param.name, param.value) - }) - code.blank() - } + if (source.postData) { + if (source.postData.params && source.postData.mimeType === 'application/x-www-form-urlencoded') { + state.bodyType = 'form' - if (source.postData && multipartMimeTypes.includes(source.postData.mimeType) && source.postData.params) { - code.push('MultipartBodyBuilder multipartBuilder = new MultipartBodyBuilder();') + code.push('MultiValueMap formDataMap = new LinkedMultiValueMap<>();') - source.postData.params.forEach(function (param) { - if (param.fileName) { - if (param.value) { - code.push('multipartBuilder.part("%s", "%qd")', param.name, param.value) - code.push(1, '.filename("%s")', param.fileName) - } else { - code.push('multipartBuilder.part("%s", new FileSystemResource("%s"))', param.name, param.fileName) - } + source.postData.params.forEach(function (param) { + code.push('formDataMap.add("%qd", "%qd");', param.name, param.value) + }) + + code.blank() + } else if (source.postData.params && multipartMimeTypes.includes(source.postData.mimeType)) { + state.bodyType = 'multipart' - if (param.contentType) { - const mediaTypeConstant = standardMediaTypes[param.contentType] - if (mediaTypeConstant) { - code.push(1, '.contentType(MediaType.%s);', mediaTypeConstant) + code.push('MultipartBodyBuilder multipartBuilder = new MultipartBodyBuilder();') + + source.postData.params.forEach(function (param) { + if (param.fileName) { + if (param.value) { + code.push('multipartBuilder.part("%s", "%qd")', param.name, param.value) + code.push(1, '.filename("%s")', param.fileName) } else { - code.push(1, '.contentType(MediaType.parseMediaType("%s"));', param.contentType) + code.push('multipartBuilder.part("%s", new FileSystemResource("%s"))', param.name, param.fileName) + } + + if (param.contentType) { + const mediaTypeConstant = standardMediaTypes[param.contentType] + if (mediaTypeConstant) { + code.push(1, '.contentType(MediaType.%s);', mediaTypeConstant) + } else { + code.push(1, '.contentType(MediaType.parseMediaType("%s"));', param.contentType) + } + } else { + code.push(1, ';') } } else { - code.push(1, ';') + code.push('multipartBuilder.part("%s", "%qd");', param.name, param.value || '') } - } else { - code.push('multipartBuilder.part("%s", "%qd");', param.name, param.value || '') - } - }) - code.blank() + }) + + code.blank() + } else if (source.postData.text) { + state.bodyType = 'plaintext' + } } code.push('ResponseEntity<%s> response = restClient', opts.entityType) @@ -146,23 +152,22 @@ module.exports = function (source, options) { }) } - if (source.postData && (source.postData.params || source.postData.text)) { - const mediaTypeEnumConstant = standardMediaTypes[source.postData.mimeType] - - if (mediaTypeEnumConstant) { - code.push(1, '.contentType(MediaType.%s)', mediaTypeEnumConstant) - } else { - code.push(1, '.contentType(MediaType.parseMediaType("%s"))', source.postData.mimeType) + if (source.postData && state.bodyType) { + if (source.postData.mimeType) { + const mediaTypeEnumConstant = standardMediaTypes[source.postData.mimeType] + if (mediaTypeEnumConstant) { + code.push(1, '.contentType(MediaType.%s)', mediaTypeEnumConstant) + } else { + code.push(1, '.contentType(MediaType.parseMediaType("%s"))', source.postData.mimeType) + } } - if (source.postData.mimeType === 'application/x-www-form-urlencoded' && source.postData.params) { + if (state.bodyType === 'form') { code.push(1, '.body(formDataMap)') - } else if (multipartMimeTypes.includes(source.postData.mimeType) && source.postData.params) { + } else if (state.bodyType === 'multipart') { code.push(1, '.body(multipartBuilder.build())') - } else if (source.postData.text) { - code.push(1, '.body(%s)', JSON.stringify(source.postData.text)) - } else if (source.postData.jsonObj && jsonMimeTypes.includes(source.postData.mimeType)) { - code.push(1, '.body(%s)', JSON.stringify(JSON.stringify(source.postData.jsonObj))) + } else if (state.bodyType === 'plaintext') { + code.push(1, '.body("%qd")', source.postData.text) } } From 22ddd55aaad7389ecbe473bd2eb3a35f999fadf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Mart=C3=ADnez=20Rinc=C3=B3n?= Date: Mon, 3 Nov 2025 22:39:15 +0100 Subject: [PATCH 18/36] refactor: dedup code --- src/targets/java/restclient.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/targets/java/restclient.js b/src/targets/java/restclient.js index 78d4d74..a4fbeb5 100644 --- a/src/targets/java/restclient.js +++ b/src/targets/java/restclient.js @@ -121,16 +121,15 @@ module.exports = function (source, options) { if (Object.keys(source.queryObj).length) { code.push(1, '.uri("%s", uriBuilder -> {', source.url) + Object.keys(source.queryObj).forEach(function (key) { const value = source.queryObj[key] - if (Array.isArray(value)) { - value.forEach(function (val) { - code.push(2, 'uriBuilder.queryParam("%qd", "%qd");', key, val) - }) - } else { - code.push(2, 'uriBuilder.queryParam("%qd", "%qd");', key, value) - } + const iterable = Array.isArray(value) ? value : [value] + iterable.forEach(function (val) { + code.push(2, 'uriBuilder.queryParam("%qd", "%qd");', key, val) + }) }) + code.push(2, 'return uriBuilder.build();') code.push(1, '})') } else { From d5cfcb086f88508ae94c8617835a6143424f5013 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Thu, 6 Nov 2025 15:03:48 +0100 Subject: [PATCH 19/36] Set up trusted publishing --- .github/workflows/ci.yml | 67 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fb074a8..8cd4118 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,14 +7,16 @@ jobs: strategy: matrix: - node-version: [10.x, 12.x, 14.x, 16.x, '*'] + node-version: [10.x, 12.x, 14.x, 16.x, 22.x, '*'] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} + cache: 'npm' + cache-dependency-path: 'package.json' - uses: shivammathur/setup-php@v2 with: @@ -22,3 +24,62 @@ jobs: - run: npm ci - run: npm test + + publish: + name: Publish to npm + needs: build + if: startsWith(github.ref, 'refs/tags/v') + runs-on: ubuntu-latest + environment: + name: npm + url: https://www.npmjs.com/package/@httptoolkit/httpsnippet + permissions: + contents: read + id-token: write + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: '22.x' + registry-url: 'https://registry.npmjs.org' + cache: 'npm' + cache-dependency-path: 'package.json' + + - run: npm ci + + - name: Verify tag matches package.json version + id: version-check + run: | + TAG_VERSION=${GITHUB_REF#refs/tags/v} + PACKAGE_VERSION=$(node -p "require('./package.json').version") + if [ "$TAG_VERSION" != "$PACKAGE_VERSION" ]; then + echo "Error: Tag version (v$TAG_VERSION) does not match package.json version ($PACKAGE_VERSION)" + exit 1 + fi + echo "✓ Tag version matches package.json version: $PACKAGE_VERSION" + + # Check if version matches strict X.Y.Z format (stable release) + if echo "$PACKAGE_VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$'; then + echo "Stable release version detected: $PACKAGE_VERSION" + echo "is_prerelease=false" >> $GITHUB_OUTPUT + else + echo "Prerelease version detected: $PACKAGE_VERSION" + echo "is_prerelease=true" >> $GITHUB_OUTPUT + fi + + # Make sure we have the latest npm for publishing: + - run: npm install -g npm@latest + + - name: Publish to npm + run: | + if [ "${{ steps.version-check.outputs.is_prerelease }}" == "true" ]; then + echo "Publishing untagged prerelease" + npm publish --provenance --tag test + # We have to publish with a tag (so we use 'test') but we can clean it up: + npm dist-tag rm @httptoolkit/httpsnippet test --silent + else + echo "Publishing stable release with 'latest' tag" + npm publish --provenance + fi \ No newline at end of file From 3402ff34da416bcdd3b5715e263c2e67cd6c11a0 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Thu, 6 Nov 2025 15:04:34 +0100 Subject: [PATCH 20/36] 2.2.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9041981..24c7d4b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@httptoolkit/httpsnippet", - "version": "2.1.7", + "version": "2.2.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@httptoolkit/httpsnippet", - "version": "2.1.7", + "version": "2.2.0", "license": "MIT", "dependencies": { "chalk": "^1.1.1", diff --git a/package.json b/package.json index c130f56..6d7199e 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "2.1.7", + "version": "2.2.0", "name": "@httptoolkit/httpsnippet", "description": "HTTP request snippet generator for *most* languages", "author": "Tim Perry ", From 24c5dfdbc30b50999f8d01a2efc6c8de01ecb150 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Wed, 12 Nov 2025 11:45:29 +0100 Subject: [PATCH 21/36] BREAKING: Bump required Node version to 22 (LTS) --- .github/workflows/ci.yml | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8cd4118..2adf676 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ jobs: strategy: matrix: - node-version: [10.x, 12.x, 14.x, 16.x, 22.x, '*'] + node-version: [20.x, 22.x, '*'] steps: - uses: actions/checkout@v4 diff --git a/package.json b/package.json index 6d7199e..2c31308 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "xmlhttprequest" ], "engines": { - "node": ">=10" + "node": ">=22" }, "files": [ "bin", From 4b745a2432b814b1e09de1417b82a60bad4bdc33 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Wed, 12 Nov 2025 12:10:48 +0100 Subject: [PATCH 22/36] Tiny cleanup for request data initialization This primarily came from an upstream fix, which isn't relevant here, but this makes that a bit clearer. --- src/index.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/index.js b/src/index.js index 565d039..2d093d4 100644 --- a/src/index.js +++ b/src/index.js @@ -34,12 +34,12 @@ const HTTPSnippet = function (data) { entries.forEach(function (entry) { // add optional properties to make validation successful - entry.request.httpVersion = entry.request.httpVersion || 'HTTP/1.1' - entry.request.queryString = entry.request.queryString || [] - entry.request.headers = entry.request.headers || [] - entry.request.cookies = entry.request.cookies || [] - entry.request.postData = entry.request.postData || {} - entry.request.postData.mimeType = entry.request.postData.mimeType || 'application/octet-stream' + entry.request.httpVersion ||= 'HTTP/1.1' + entry.request.queryString ||= [] + entry.request.headers ||= [] + entry.request.cookies ||= [] + entry.request.postData ||= {} + entry.request.postData.mimeType ||= 'application/octet-stream' entry.request.bodySize = 0 entry.request.headersSize = 0 From 5924fcde940e7d8de16190816fc594c88179de35 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Wed, 12 Nov 2025 12:12:24 +0100 Subject: [PATCH 23/36] Add new Crystal language target Taken from upstream --- src/targets/crystal/index.js | 12 ++++ src/targets/crystal/native.js | 68 +++++++++++++++++++ src/targets/index.js | 1 + test/fixtures/available-targets.json | 14 ++++ .../native/application-form-encoded.cr | 10 +++ .../output/crystal/native/application-json.cr | 10 +++ .../output/crystal/native/compression.cr | 9 +++ .../fixtures/output/crystal/native/cookies.cr | 9 +++ .../output/crystal/native/custom-method.cr | 6 ++ test/fixtures/output/crystal/native/full.cr | 12 ++++ .../fixtures/output/crystal/native/headers.cr | 11 +++ test/fixtures/output/crystal/native/https.cr | 6 ++ .../crystal/native/jsonObj-multiline.cr | 10 +++ .../crystal/native/jsonObj-null-value.cr | 10 +++ .../output/crystal/native/malicious.cr | 25 +++++++ .../output/crystal/native/multipart-data.cr | 10 +++ .../output/crystal/native/multipart-file.cr | 10 +++ .../crystal/native/multipart-form-data.cr | 10 +++ test/fixtures/output/crystal/native/nested.cr | 6 ++ test/fixtures/output/crystal/native/query.cr | 6 ++ test/fixtures/output/crystal/native/short.cr | 6 ++ .../output/crystal/native/text-plain.cr | 10 +++ .../crystal/native/unparseable-query.cr | 6 ++ test/targets/crystal/native.js | 3 + 24 files changed, 280 insertions(+) create mode 100644 src/targets/crystal/index.js create mode 100644 src/targets/crystal/native.js create mode 100644 test/fixtures/output/crystal/native/application-form-encoded.cr create mode 100644 test/fixtures/output/crystal/native/application-json.cr create mode 100644 test/fixtures/output/crystal/native/compression.cr create mode 100644 test/fixtures/output/crystal/native/cookies.cr create mode 100644 test/fixtures/output/crystal/native/custom-method.cr create mode 100644 test/fixtures/output/crystal/native/full.cr create mode 100644 test/fixtures/output/crystal/native/headers.cr create mode 100644 test/fixtures/output/crystal/native/https.cr create mode 100644 test/fixtures/output/crystal/native/jsonObj-multiline.cr create mode 100644 test/fixtures/output/crystal/native/jsonObj-null-value.cr create mode 100644 test/fixtures/output/crystal/native/malicious.cr create mode 100644 test/fixtures/output/crystal/native/multipart-data.cr create mode 100644 test/fixtures/output/crystal/native/multipart-file.cr create mode 100644 test/fixtures/output/crystal/native/multipart-form-data.cr create mode 100644 test/fixtures/output/crystal/native/nested.cr create mode 100644 test/fixtures/output/crystal/native/query.cr create mode 100644 test/fixtures/output/crystal/native/short.cr create mode 100644 test/fixtures/output/crystal/native/text-plain.cr create mode 100644 test/fixtures/output/crystal/native/unparseable-query.cr create mode 100644 test/targets/crystal/native.js diff --git a/src/targets/crystal/index.js b/src/targets/crystal/index.js new file mode 100644 index 0000000..b1f84a2 --- /dev/null +++ b/src/targets/crystal/index.js @@ -0,0 +1,12 @@ +'use strict' + +module.exports = { + info: { + key: 'crystal', + title: 'Crystal', + extname: '.cr', + default: 'native' + }, + + native: require('./native') +} diff --git a/src/targets/crystal/native.js b/src/targets/crystal/native.js new file mode 100644 index 0000000..c284baa --- /dev/null +++ b/src/targets/crystal/native.js @@ -0,0 +1,68 @@ +/** + * @description + * HTTP code snippet generator for native Crystal + * + * @author + * @yanecc + * + * for any questions or issues regarding the generated code snippet, please open an issue mentioning the author. + */ + +const CodeBuilder = require('../../helpers/code-builder') + +const { escape } = require('../../helpers/format') + +module.exports = function ({ method: rawMethod, fullUrl, postData, allHeaders }, options = {}) { + const { insecureSkipVerify = false } = options + + const code = new CodeBuilder() + + code.push('require "http/client"') + + code.blank() + + code.push(`url = "${fullUrl}"`) + + const headers = Object.keys(allHeaders) + if (headers.length) { + code.push('headers = HTTP::Headers{') + headers.forEach(key => { + code.push(` "${key}" => "${escape(allHeaders[key])}"`) + }) + code.push('}') + } + + if (postData.text) { + code.push(`reqBody = ${JSON.stringify(postData.text)}`) + } + + code.blank() + + const method = rawMethod.toUpperCase() + const methods = ['GET', 'POST', 'HEAD', 'DELETE', 'PATCH', 'PUT', 'OPTIONS'] + + const headersContext = headers.length ? ', headers: headers' : '' + const bodyContext = postData.text ? ', body: reqBody' : '' + const sslContext = insecureSkipVerify ? ', tls: OpenSSL::SSL::Context::Client.insecure' : '' + + if (methods.includes(method)) { + code.push( + `response = HTTP::Client.${method.toLowerCase()} url${headersContext}${bodyContext}${sslContext}` + ) + } else { + code.push( + `response = HTTP::Client.exec "${method}", url${headersContext}${bodyContext}${sslContext}` + ) + } + + code.push('puts response.body') + + return code.join() +} + +module.exports.info = { + key: 'native', + title: 'http::client', + link: 'https://crystal-lang.org/api/master/HTTP/Client.html', + description: 'Crystal HTTP client' +} diff --git a/src/targets/index.js b/src/targets/index.js index dd90b48..b6921e6 100644 --- a/src/targets/index.js +++ b/src/targets/index.js @@ -3,6 +3,7 @@ module.exports = { c: require('./c'), clojure: require('./clojure'), + crystal: require('./crystal'), csharp: require('./csharp'), go: require('./go'), http: require('./http'), diff --git a/test/fixtures/available-targets.json b/test/fixtures/available-targets.json index fa36970..e6877a4 100644 --- a/test/fixtures/available-targets.json +++ b/test/fixtures/available-targets.json @@ -358,5 +358,19 @@ "description": "An HTTP Request Client Library" } ] + }, + { + "key": "crystal", + "title": "Crystal", + "extname": ".cr", + "default": "native", + "clients": [ + { + "key": "native", + "title": "http::client", + "link": "https://crystal-lang.org/api/master/HTTP/Client.html", + "description": "Crystal HTTP client" + } + ] } ] diff --git a/test/fixtures/output/crystal/native/application-form-encoded.cr b/test/fixtures/output/crystal/native/application-form-encoded.cr new file mode 100644 index 0000000..1a88422 --- /dev/null +++ b/test/fixtures/output/crystal/native/application-form-encoded.cr @@ -0,0 +1,10 @@ +require "http/client" + +url = "http://mockbin.com/har" +headers = HTTP::Headers{ + "content-type" => "application/x-www-form-urlencoded" +} +reqBody = "foo=bar&hello=world" + +response = HTTP::Client.post url, headers: headers, body: reqBody +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/crystal/native/application-json.cr b/test/fixtures/output/crystal/native/application-json.cr new file mode 100644 index 0000000..1389c2f --- /dev/null +++ b/test/fixtures/output/crystal/native/application-json.cr @@ -0,0 +1,10 @@ +require "http/client" + +url = "http://mockbin.com/har" +headers = HTTP::Headers{ + "content-type" => "application/json" +} +reqBody = "{\"number\":1,\"string\":\"f\\\"oo\",\"arr\":[1,2,3],\"nested\":{\"a\":\"b\"},\"arr_mix\":[1,\"a\",{\"arr_mix_nested\":{}}],\"boolean\":false}" + +response = HTTP::Client.post url, headers: headers, body: reqBody +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/crystal/native/compression.cr b/test/fixtures/output/crystal/native/compression.cr new file mode 100644 index 0000000..7658836 --- /dev/null +++ b/test/fixtures/output/crystal/native/compression.cr @@ -0,0 +1,9 @@ +require "http/client" + +url = "http://mockbin.com/har" +headers = HTTP::Headers{ + "accept-encoding" => "deflate, gzip, br" +} + +response = HTTP::Client.get url, headers: headers +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/crystal/native/cookies.cr b/test/fixtures/output/crystal/native/cookies.cr new file mode 100644 index 0000000..70d45c1 --- /dev/null +++ b/test/fixtures/output/crystal/native/cookies.cr @@ -0,0 +1,9 @@ +require "http/client" + +url = "http://mockbin.com/har" +headers = HTTP::Headers{ + "cookie" => "foo=bar; bar=baz" +} + +response = HTTP::Client.post url, headers: headers +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/crystal/native/custom-method.cr b/test/fixtures/output/crystal/native/custom-method.cr new file mode 100644 index 0000000..ee1852b --- /dev/null +++ b/test/fixtures/output/crystal/native/custom-method.cr @@ -0,0 +1,6 @@ +require "http/client" + +url = "http://mockbin.com/har" + +response = HTTP::Client.exec "PROPFIND", url +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/crystal/native/full.cr b/test/fixtures/output/crystal/native/full.cr new file mode 100644 index 0000000..edd8f4c --- /dev/null +++ b/test/fixtures/output/crystal/native/full.cr @@ -0,0 +1,12 @@ +require "http/client" + +url = "http://mockbin.com/har?foo=bar&foo=baz&baz=abc&key=value" +headers = HTTP::Headers{ + "cookie" => "foo=bar; bar=baz" + "accept" => "application/json" + "content-type" => "application/x-www-form-urlencoded" +} +reqBody = "foo=bar" + +response = HTTP::Client.post url, headers: headers, body: reqBody +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/crystal/native/headers.cr b/test/fixtures/output/crystal/native/headers.cr new file mode 100644 index 0000000..1061d33 --- /dev/null +++ b/test/fixtures/output/crystal/native/headers.cr @@ -0,0 +1,11 @@ +require "http/client" + +url = "http://mockbin.com/har" +headers = HTTP::Headers{ + "accept" => "application/json" + "x-foo" => "Bar" + "quoted-value" => "\"quoted\" 'string'" +} + +response = HTTP::Client.get url, headers: headers +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/crystal/native/https.cr b/test/fixtures/output/crystal/native/https.cr new file mode 100644 index 0000000..c9fa4fd --- /dev/null +++ b/test/fixtures/output/crystal/native/https.cr @@ -0,0 +1,6 @@ +require "http/client" + +url = "https://mockbin.com/har" + +response = HTTP::Client.get url +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/crystal/native/jsonObj-multiline.cr b/test/fixtures/output/crystal/native/jsonObj-multiline.cr new file mode 100644 index 0000000..12ce719 --- /dev/null +++ b/test/fixtures/output/crystal/native/jsonObj-multiline.cr @@ -0,0 +1,10 @@ +require "http/client" + +url = "http://mockbin.com/har" +headers = HTTP::Headers{ + "content-type" => "application/json" +} +reqBody = "{\n \"foo\": \"bar\"\n}" + +response = HTTP::Client.post url, headers: headers, body: reqBody +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/crystal/native/jsonObj-null-value.cr b/test/fixtures/output/crystal/native/jsonObj-null-value.cr new file mode 100644 index 0000000..053961c --- /dev/null +++ b/test/fixtures/output/crystal/native/jsonObj-null-value.cr @@ -0,0 +1,10 @@ +require "http/client" + +url = "http://mockbin.com/har" +headers = HTTP::Headers{ + "content-type" => "application/json" +} +reqBody = "{\"foo\":null}" + +response = HTTP::Client.post url, headers: headers, body: reqBody +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/crystal/native/malicious.cr b/test/fixtures/output/crystal/native/malicious.cr new file mode 100644 index 0000000..e8374f3 --- /dev/null +++ b/test/fixtures/output/crystal/native/malicious.cr @@ -0,0 +1,25 @@ +require "http/client" + +url = "http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//?'=squote-key-test&squote-value-test='&%22=dquote-key-test&dquote-value-test=%22&%60=backtick-key-test&backtick-value-test=%60&%24(=dollar-parenthesis-key-test&dollar-parenthesis-value-test=%24(&%23%7B=hash-brace-key-test&hash-brace-value-test=%23%7B&%25(=percent-parenthesis-key-test&percent-parenthesis-value-test=%25(&%25%7B=percent-brace-key-test&percent-brace-value-test=%25%7B&%7B%7B=double-brace-key-test&double-brace-value-test=%7B%7B&%5C0=null-key-test&null-value-test=%5C0&%25s=string-fmt-key-test&string-fmt-value-test=%25s&%5C=slash-key-test&slash-value-test=%5C" +headers = HTTP::Headers{ + "'" => "squote-key-test" + "squote-value-test" => "'" + "dquote-value-test" => "\"" + "`" => "backtick-key-test" + "backtick-value-test" => "`" + "$" => "dollar-key-test" + "dollar-parenthesis-value-test" => "$(" + "#" => "hash-key-test" + "hash-brace-value-test" => "#{" + "%" => "percent-key-test" + "percent-parenthesis-value-test" => "%(" + "percent-brace-value-test" => "%{" + "double-brace-value-test" => "{{" + "null-value-test" => "\\0" + "string-fmt-value-test" => "%s" + "slash-value-test" => "\\" +} +reqBody = "' \" ` $( #{ %( %{ {{ \\0 %s \\" + +response = HTTP::Client.post url, headers: headers, body: reqBody +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/crystal/native/multipart-data.cr b/test/fixtures/output/crystal/native/multipart-data.cr new file mode 100644 index 0000000..96f265a --- /dev/null +++ b/test/fixtures/output/crystal/native/multipart-data.cr @@ -0,0 +1,10 @@ +require "http/client" + +url = "http://mockbin.com/har" +headers = HTTP::Headers{ + "content-type" => "multipart/form-data; boundary=---011000010111000001101001" +} +reqBody = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"; filename=\"hello.txt\"\r\nContent-Type: text/plain\r\n\r\nHello World\r\n-----011000010111000001101001--\r\n" + +response = HTTP::Client.post url, headers: headers, body: reqBody +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/crystal/native/multipart-file.cr b/test/fixtures/output/crystal/native/multipart-file.cr new file mode 100644 index 0000000..1555da8 --- /dev/null +++ b/test/fixtures/output/crystal/native/multipart-file.cr @@ -0,0 +1,10 @@ +require "http/client" + +url = "http://mockbin.com/har" +headers = HTTP::Headers{ + "content-type" => "multipart/form-data; boundary=---011000010111000001101001" +} +reqBody = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"; filename=\"hello.txt\"\r\nContent-Type: text/plain\r\n\r\n\r\n-----011000010111000001101001--\r\n" + +response = HTTP::Client.post url, headers: headers, body: reqBody +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/crystal/native/multipart-form-data.cr b/test/fixtures/output/crystal/native/multipart-form-data.cr new file mode 100644 index 0000000..d5216d7 --- /dev/null +++ b/test/fixtures/output/crystal/native/multipart-form-data.cr @@ -0,0 +1,10 @@ +require "http/client" + +url = "http://mockbin.com/har" +headers = HTTP::Headers{ + "Content-Type" => "multipart/form-data; boundary=---011000010111000001101001" +} +reqBody = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"\r\n\r\nbar\r\n-----011000010111000001101001--\r\n" + +response = HTTP::Client.post url, headers: headers, body: reqBody +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/crystal/native/nested.cr b/test/fixtures/output/crystal/native/nested.cr new file mode 100644 index 0000000..f6fbf4b --- /dev/null +++ b/test/fixtures/output/crystal/native/nested.cr @@ -0,0 +1,6 @@ +require "http/client" + +url = "http://mockbin.com/har?foo%5Bbar%5D=baz%2Czap&fiz=buz&key=value" + +response = HTTP::Client.get url +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/crystal/native/query.cr b/test/fixtures/output/crystal/native/query.cr new file mode 100644 index 0000000..cacc2b3 --- /dev/null +++ b/test/fixtures/output/crystal/native/query.cr @@ -0,0 +1,6 @@ +require "http/client" + +url = "http://mockbin.com/har?foo=bar&foo=baz&baz=abc&key=value" + +response = HTTP::Client.get url +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/crystal/native/short.cr b/test/fixtures/output/crystal/native/short.cr new file mode 100644 index 0000000..0715616 --- /dev/null +++ b/test/fixtures/output/crystal/native/short.cr @@ -0,0 +1,6 @@ +require "http/client" + +url = "http://mockbin.com/har" + +response = HTTP::Client.get url +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/crystal/native/text-plain.cr b/test/fixtures/output/crystal/native/text-plain.cr new file mode 100644 index 0000000..8890116 --- /dev/null +++ b/test/fixtures/output/crystal/native/text-plain.cr @@ -0,0 +1,10 @@ +require "http/client" + +url = "http://mockbin.com/har" +headers = HTTP::Headers{ + "content-type" => "text/plain" +} +reqBody = "Hello World" + +response = HTTP::Client.post url, headers: headers, body: reqBody +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/crystal/native/unparseable-query.cr b/test/fixtures/output/crystal/native/unparseable-query.cr new file mode 100644 index 0000000..83b1dd7 --- /dev/null +++ b/test/fixtures/output/crystal/native/unparseable-query.cr @@ -0,0 +1,6 @@ +require "http/client" + +url = "http://mockbin.com/har?&&a=b&&" + +response = HTTP::Client.get url +puts response.body \ No newline at end of file diff --git a/test/targets/crystal/native.js b/test/targets/crystal/native.js new file mode 100644 index 0000000..b77cc77 --- /dev/null +++ b/test/targets/crystal/native.js @@ -0,0 +1,3 @@ +'use strict' + +module.exports = function (snippet, fixtures) {} From 48201c2aacf80431f29dc1ed78aab7d8f3d7e882 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Wed, 12 Nov 2025 12:39:48 +0100 Subject: [PATCH 24/36] Add new Rust Reqwest target Taken from upstream --- src/helpers/code-builder.js | 12 + src/targets/index.js | 1 + src/targets/rust/helpers.js | 93 ++++ src/targets/rust/index.js | 12 + src/targets/rust/reqwest.js | 238 ++++++++++ test/fixtures/available-targets.json | 440 +++++++++--------- .../rust/reqwest/application-form-encoded.rs | 29 ++ .../output/rust/reqwest/application-json.rs | 33 ++ .../output/rust/reqwest/compression.rs | 22 + test/fixtures/output/rust/reqwest/cookies.rs | 22 + .../output/rust/reqwest/custom-method.rs | 19 + test/fixtures/output/rust/reqwest/full.rs | 35 ++ test/fixtures/output/rust/reqwest/headers.rs | 24 + test/fixtures/output/rust/reqwest/https.rs | 18 + .../output/rust/reqwest/jsonObj-multiline.rs | 26 ++ .../output/rust/reqwest/jsonObj-null-value.rs | 26 ++ .../fixtures/output/rust/reqwest/malicious.rs | 67 +++ .../output/rust/reqwest/multipart-data.rs | 33 ++ .../output/rust/reqwest/multipart-file.rs | 33 ++ .../rust/reqwest/multipart-form-data.rs | 24 + test/fixtures/output/rust/reqwest/nested.rs | 25 + test/fixtures/output/rust/reqwest/query.rs | 25 + test/fixtures/output/rust/reqwest/short.rs | 18 + .../output/rust/reqwest/text-plain.rs | 26 ++ .../output/rust/reqwest/unparseable-query.rs | 18 + test/targets/rust/reqwest.js | 3 + 26 files changed, 1109 insertions(+), 213 deletions(-) create mode 100644 src/targets/rust/helpers.js create mode 100644 src/targets/rust/index.js create mode 100644 src/targets/rust/reqwest.js create mode 100644 test/fixtures/output/rust/reqwest/application-form-encoded.rs create mode 100644 test/fixtures/output/rust/reqwest/application-json.rs create mode 100644 test/fixtures/output/rust/reqwest/compression.rs create mode 100644 test/fixtures/output/rust/reqwest/cookies.rs create mode 100644 test/fixtures/output/rust/reqwest/custom-method.rs create mode 100644 test/fixtures/output/rust/reqwest/full.rs create mode 100644 test/fixtures/output/rust/reqwest/headers.rs create mode 100644 test/fixtures/output/rust/reqwest/https.rs create mode 100644 test/fixtures/output/rust/reqwest/jsonObj-multiline.rs create mode 100644 test/fixtures/output/rust/reqwest/jsonObj-null-value.rs create mode 100644 test/fixtures/output/rust/reqwest/malicious.rs create mode 100644 test/fixtures/output/rust/reqwest/multipart-data.rs create mode 100644 test/fixtures/output/rust/reqwest/multipart-file.rs create mode 100644 test/fixtures/output/rust/reqwest/multipart-form-data.rs create mode 100644 test/fixtures/output/rust/reqwest/nested.rs create mode 100644 test/fixtures/output/rust/reqwest/query.rs create mode 100644 test/fixtures/output/rust/reqwest/short.rs create mode 100644 test/fixtures/output/rust/reqwest/text-plain.rs create mode 100644 test/fixtures/output/rust/reqwest/unparseable-query.rs create mode 100644 test/targets/rust/reqwest.js diff --git a/src/helpers/code-builder.js b/src/helpers/code-builder.js index 62a8f21..245f3d7 100644 --- a/src/helpers/code-builder.js +++ b/src/helpers/code-builder.js @@ -93,6 +93,18 @@ CodeBuilder.prototype.blank = function () { return this } +/** + * Add the line to the end of the last line. Creates a new line + * if no lines exist yet. + */ +CodeBuilder.prototype.pushToLast = function (line) { + if (!this.code) { + this.push(line) + } + const updatedLine = `${this.code[this.code.length - 1]}${line}` + this.code[this.code.length - 1] = updatedLine +} + /** * Concatenate all current lines using the given lineJoin * @return {string} diff --git a/src/targets/index.js b/src/targets/index.js index b6921e6..9687e9d 100644 --- a/src/targets/index.js +++ b/src/targets/index.js @@ -18,6 +18,7 @@ module.exports = { python: require('./python'), r: require('./r'), ruby: require('./ruby'), + rust: require('./rust'), shell: require('./shell'), swift: require('./swift') } diff --git a/src/targets/rust/helpers.js b/src/targets/rust/helpers.js new file mode 100644 index 0000000..bddf6c1 --- /dev/null +++ b/src/targets/rust/helpers.js @@ -0,0 +1,93 @@ +'use strict' + +const util = require('util') + +function concatValues ( + concatType, + values, + pretty, + indentation, + indentLevel +) { + const currentIndent = indentation.repeat(indentLevel) + const closingBraceIndent = indentation.repeat(indentLevel - 1) + const join = pretty ? `,\n${currentIndent}` : ', ' + const openingBrace = concatType === 'object' ? 'json!({' : '(' + const closingBrace = concatType === 'object' ? '})' : ')' + + if (pretty) { + return `${openingBrace}\n${currentIndent}${values.join( + join + )}\n${closingBraceIndent}${closingBrace}` + } + + return `${openingBrace}${values.join(join)}${closingBrace}` +} + +/** + * Create a valid Rust string of a literal value using serde_json according to its type. + * + * @param {*} value Any Javascript literal + * @param {Object} opts Target options + * @return {string} + */ +exports.literalRepresentation = ( + value, + opts, + indentLevel +) => { + /* + * Note: this version is almost entirely borrowed from the Python client helper. The + * only real modification involves the braces and the types. The helper + * could potentially be parameterised for reuse. + */ + indentLevel = indentLevel === undefined ? 1 : indentLevel + 1 + + switch (Object.prototype.toString.call(value)) { + case '[object Number]': + return value + + case '[object Array]': { + let pretty = false + const valuesRep = value.map(v => { + // Switch to prettify if the value is a dict with more than one key. + if (Object.prototype.toString.call(v) === '[object Object]') { + pretty = Object.keys(v).length > 1 + } + return exports.literalRepresentation(v, opts, indentLevel) + }) + return concatValues('array', valuesRep, pretty, opts.indent, indentLevel) + } + + case '[object Object]': { + const keyValuePairs = [] + for (const k in value) { + keyValuePairs.push( + util.format('%s: %s', + exports.literalRepresentation(k, opts, indentLevel), + exports.literalRepresentation(value[k], opts, indentLevel) + ) + ) + } + return concatValues( + 'object', + keyValuePairs, + opts.pretty && keyValuePairs.length > 1, + opts.indent, + indentLevel + ) + } + + case '[object Null]': + return 'json!(null)' + + case '[object Boolean]': + return value ? 'true' : 'false' + + default: + if (value === null || value === undefined) { + return '' + } + return JSON.stringify(value) + } +} diff --git a/src/targets/rust/index.js b/src/targets/rust/index.js new file mode 100644 index 0000000..011dadf --- /dev/null +++ b/src/targets/rust/index.js @@ -0,0 +1,12 @@ +'use strict' + +module.exports = { + info: { + key: 'rust', + title: 'Rust', + extname: '.rs', + default: 'reqwest' + }, + + reqwest: require('./reqwest') +} diff --git a/src/targets/rust/reqwest.js b/src/targets/rust/reqwest.js new file mode 100644 index 0000000..e381015 --- /dev/null +++ b/src/targets/rust/reqwest.js @@ -0,0 +1,238 @@ +/** + * @description + * HTTP code snippet generator for Rust using reqwest + * + * @author + * @Benjscho + * + * for any questions or issues regarding the generated code snippet, please open an issue mentioning the author. + */ + +const CodeBuilder = require('../../helpers/code-builder') +const { escape } = require('../../helpers/format') +const { literalRepresentation } = require('./helpers') + +module.exports = ({ queryObj, url, postData, allHeaders, method }, options) => { + const opts = { + indent: ' ', + pretty: true, + ...options + } + + let indentLevel = 0 + + // start snippet + const code = new CodeBuilder(opts.indent) + + // import reqwest + code.push(indentLevel, 'use reqwest;') + code.blank() + + // start async main for tokio + code.push(indentLevel, '#[tokio::main]') + code.push(indentLevel, 'pub async fn main() {') + indentLevel += 1 + + // add url + code.push(indentLevel, `let url = "${url}";`) + code.blank() + + let hasQuery = false + // construct query string + if (Object.keys(queryObj).length) { + hasQuery = true + code.push(indentLevel, 'let querystring = [') + indentLevel += 1 + for (const [key, value] of Object.entries(queryObj)) { + code.push(indentLevel, `("${escape(key)}", "${escape(value)}"),`) + } + indentLevel -= 1 + code.push(indentLevel, '];') + code.blank() + } + + // construct payload + let payload = {} + const files = {} + + let hasFiles = false + let hasForm = false + let hasBody = false + let jsonPayload = false + let isMultipart = false + switch (postData.mimeType) { + case 'application/json': + if (postData.jsonObj) { + code.push( + indentLevel, + `let payload = ${literalRepresentation(postData.jsonObj, opts, indentLevel)};` + ) + } + jsonPayload = true + break + + case 'multipart/form-data': + isMultipart = true + + if (!postData.params) { + code.push(indentLevel, 'let form = reqwest::multipart::Form::new()') + code.push(indentLevel + 1, '.text("", "");') + break + } + + payload = {} + postData.params.forEach(p => { + if (p.fileName) { + files[p.name] = p.fileName + hasFiles = true + } else { + payload[p.name] = p.value + } + }) + + if (hasFiles) { + for (const line of fileToPartString) { + code.push(indentLevel, line) + } + code.blank() + } + code.push(indentLevel, 'let form = reqwest::multipart::Form::new()') + + for (const [name, fileName] of Object.entries(files)) { + code.push(indentLevel + 1, `.part("${name}", file_to_part("${fileName}").await)`) + } + for (const [name, value] of Object.entries(payload)) { + code.push(indentLevel + 1, `.text("${name}", "${value}")`) + } + code.pushToLast(';') + + break + + default: { + if (postData.mimeType === 'application/x-www-form-urlencoded' && postData.paramsObj) { + code.push( + indentLevel, + `let payload = ${literalRepresentation(postData.paramsObj, opts, indentLevel)};` + ) + hasForm = true + break + } + + if (postData.text) { + code.push( + indentLevel, + `let payload = ${literalRepresentation(postData.text, opts, indentLevel)};` + ) + hasBody = true + break + } + } + } + + if (hasForm || jsonPayload || hasBody) { + code.unshift('use serde_json::json;') + code.blank() + } + + let hasHeaders = false + // construct headers + if (Object.keys(allHeaders).length) { + hasHeaders = true + code.push(indentLevel, 'let mut headers = reqwest::header::HeaderMap::new();') + for (const [key, value] of Object.entries(allHeaders)) { + // Skip setting content-type if there is a file, as this header will + // cause the request to hang, and reqwest will set it for us. + if (key.toLowerCase() === 'content-type' && isMultipart) { + continue + } + code.push( + indentLevel, + `headers.insert("${escape(key)}", ${literalRepresentation(value, opts)}.parse().unwrap());` + ) + } + code.blank() + } + + // construct client + code.push(indentLevel, 'let client = reqwest::Client::new();') + + // construct query + switch (method) { + case 'POST': + code.push(indentLevel, 'let response = client.post(url)') + break + + case 'GET': + code.push(indentLevel, 'let response = client.get(url)') + break + + default: { + code.push( + indentLevel, + `let response = client.request(reqwest::Method::from_str("${method}").unwrap(), url)` + ) + code.unshift('use std::str::FromStr;') + break + } + } + + if (hasQuery) { + code.push(indentLevel + 1, '.query(&querystring)') + } + + if (isMultipart) { + code.push(indentLevel + 1, '.multipart(form)') + } + + if (hasHeaders) { + code.push(indentLevel + 1, '.headers(headers)') + } + + if (jsonPayload) { + code.push(indentLevel + 1, '.json(&payload)') + } + + if (hasForm) { + code.push(indentLevel + 1, '.form(&payload)') + } + + if (hasBody) { + code.push(indentLevel + 1, '.body(payload)') + } + + // send query + code.push(indentLevel + 1, '.send()') + code.push(indentLevel + 1, '.await;') + code.blank() + + // Print response + code.push(indentLevel, 'let results = response.unwrap()') + code.push(indentLevel + 1, '.json::()') + code.push(indentLevel + 1, '.await') + code.push(indentLevel + 1, '.unwrap();') + code.blank() + + code.push(indentLevel, 'dbg!(results);') + + code.push('}\n') + + return code.join() +} + +const fileToPartString = [ + 'async fn file_to_part(file_name: &\'static str) -> reqwest::multipart::Part {', + ' let file = tokio::fs::File::open(file_name).await.unwrap();', + ' let stream = tokio_util::codec::FramedRead::new(file, tokio_util::codec::BytesCodec::new());', + ' let body = reqwest::Body::wrap_stream(stream);', + ' reqwest::multipart::Part::stream(body)', + ' .file_name(file_name)', + ' .mime_str("text/plain").unwrap()', + '}' +] + +module.exports.info = { + key: 'reqwest', + title: 'reqwest', + link: 'https://docs.rs/reqwest/latest/reqwest/', + description: 'reqwest HTTP library' +} diff --git a/test/fixtures/available-targets.json b/test/fixtures/available-targets.json index e6877a4..63d14fa 100644 --- a/test/fixtures/available-targets.json +++ b/test/fixtures/available-targets.json @@ -1,65 +1,129 @@ [ { - "key": "shell", - "title": "Shell", - "extname": ".sh", - "default": "curl", + "key": "c", + "title": "C", + "extname": ".c", + "default": "libcurl", "clients": [ { - "key": "curl", - "title": "cURL", - "link": "http://curl.haxx.se/", - "description": "cURL is a command line tool and library for transferring data with URL syntax" - }, + "key": "libcurl", + "title": "Libcurl", + "link": "http://curl.haxx.se/libcurl/", + "description": "Simple REST and HTTP API Client for C" + } + ] + }, + { + "key": "clojure", + "title": "Clojure", + "extname": ".clj", + "default": "clj_http", + "clients": [ { - "key": "httpie", - "title": "HTTPie", - "link": "http://httpie.org/", - "description": "a CLI, cURL-like tool for humans" + "key": "clj_http", + "title": "clj-http", + "link": "https://github.com/dakrone/clj-http", + "description": "An idiomatic clojure http client wrapping the apache client." + } + ] + }, + { + "key": "crystal", + "title": "Crystal", + "extname": ".cr", + "default": "native", + "clients": [ + { + "key": "native", + "title": "http::client", + "link": "https://crystal-lang.org/api/master/HTTP/Client.html", + "description": "Crystal HTTP client" + } + ] + }, + { + "key": "csharp", + "title": "C#", + "extname": ".cs", + "default": "restsharp", + "clients": [ + { + "key": "restsharp", + "title": "RestSharp", + "link": "http://restsharp.org/", + "description": "Simple REST and HTTP API Client for .NET" }, { - "key": "wget", - "title": "Wget", - "link": "https://www.gnu.org/software/wget/", - "description": "a free software package for retrieving files using HTTP, HTTPS" + "key": "httpclient", + "title": "HttpClient", + "link": "https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient", + "description": ".NET Standard HTTP Client" } ] }, { - "key": "node", - "title": "Node.js", - "extname": ".js", + "key": "go", + "title": "Go", + "extname": ".go", "default": "native", "clients": [ { "key": "native", - "title": "HTTP", - "link": "http://nodejs.org/api/http.html#http_http_request_options_callback", - "description": "Node.js native HTTP interface" - }, + "title": "NewRequest", + "link": "http://golang.org/pkg/net/http/#NewRequest", + "description": "Golang HTTP client request" + } + ] + }, + { + "key": "http", + "title": "HTTP", + "extname": "", + "default": "1.1", + "clients": [ { - "key": "request", - "title": "Request", - "link": "https://github.com/request/request", - "description": "Simplified HTTP request client" + "key": "1.1", + "title": "HTTP/1.1", + "link": "https://tools.ietf.org/html/rfc7230", + "description": "HTTP/1.1 request string in accordance with RFC 7230" + } + ] + }, + { + "key": "java", + "title": "Java", + "extname": ".java", + "default": "unirest", + "clients": [ + { + "key": "okhttp", + "title": "OkHttp", + "link": "http://square.github.io/okhttp/", + "description": "An HTTP Request Client Library" }, { "key": "unirest", "title": "Unirest", - "link": "http://unirest.io/nodejs.html", + "link": "http://unirest.io/java.html", "description": "Lightweight HTTP Request Client Library" }, { - "key": "axios", - "title": "Axios", - "link": "https://github.com/axios/axios", - "description": "Promise based HTTP client for the browser and node.js" + "key": "asynchttp", + "title": "AsyncHttp", + "link": "https://github.com/AsyncHttpClient/async-http-client", + "description": "Asynchronous Http and WebSocket Client library for Java" }, { - "key": "fetch", - "title": "Fetch", - "link": "https://github.com/bitinn/node-fetch", - "description": "Simplified HTTP node-fetch client" + "key": "nethttp", + "title": "java.net.http", + "link": "https://openjdk.java.net/groups/net/httpclient/intro.html", + "description": "Java Standardized HTTP Client API" + }, + { + "key": "restclient", + "title": "Spring RestClient", + "link": "https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/RestClient.html", + "description": "Spring Framework REST client" } ] }, @@ -96,62 +160,54 @@ ] }, { - "key": "ocaml", - "title": "OCaml", - "extname": ".ml", - "default": "cohttp", + "key": "kotlin", + "title": "Kotlin", + "extname": ".kt", + "default": "okhttp", "clients": [ { - "key": "cohttp", - "title": "CoHTTP", - "link": "https://github.com/mirage/ocaml-cohttp", - "description": "Cohttp is a very lightweight HTTP server using Lwt or Async for OCaml" + "key": "okhttp", + "title": "OkHttp", + "link": "http://square.github.io/okhttp/", + "description": "An HTTP Request Client Library" } ] }, { - "key": "php", - "title": "PHP", - "extname": ".php", - "default": "curl", + "key": "node", + "title": "Node.js", + "extname": ".js", + "default": "native", "clients": [ { - "key": "curl", - "title": "cURL", - "link": "http://php.net/manual/en/book.curl.php", - "description": "PHP with ext-curl" + "key": "native", + "title": "HTTP", + "link": "http://nodejs.org/api/http.html#http_http_request_options_callback", + "description": "Node.js native HTTP interface" }, { - "key": "http1", - "title": "HTTP v1", - "link": "http://php.net/manual/en/book.http.php", - "description": "PHP with pecl/http v1" + "key": "request", + "title": "Request", + "link": "https://github.com/request/request", + "description": "Simplified HTTP request client" }, { - "key": "http2", - "title": "HTTP v2", - "link": "http://devel-m6w6.rhcloud.com/mdref/http", - "description": "PHP with pecl/http v2" - } - ] - }, - { - "key": "python", - "title": "Python", - "extname": ".py", - "default": "python3", - "clients": [ + "key": "unirest", + "title": "Unirest", + "link": "http://unirest.io/nodejs.html", + "description": "Lightweight HTTP Request Client Library" + }, { - "key": "python3", - "title": "http.client", - "link": "https://docs.python.org/3/library/http.client.html", - "description": "Python3 HTTP Client" + "key": "axios", + "title": "Axios", + "link": "https://github.com/axios/axios", + "description": "Promise based HTTP client for the browser and node.js" }, { - "key": "requests", - "title": "Requests", - "link": "http://docs.python-requests.org/en/latest/api/#requests.request", - "description": "Requests HTTP library" + "key": "fetch", + "title": "Fetch", + "link": "https://github.com/bitinn/node-fetch", + "description": "Simplified HTTP node-fetch client" } ] }, @@ -170,130 +226,82 @@ ] }, { - "key": "swift", - "title": "Swift", - "extname": ".swift", - "default": "nsurlsession", - "clients": [ - { - "key": "nsurlsession", - "title": "NSURLSession", - "link": "https://developer.apple.com/library/mac/documentation/Foundation/Reference/NSURLSession_class/index.html", - "description": "Foundation's NSURLSession request" - } - ] - }, - { - "key": "go", - "title": "Go", - "extname": ".go", - "default": "native", + "key": "ocaml", + "title": "OCaml", + "extname": ".ml", + "default": "cohttp", "clients": [ { - "key": "native", - "title": "NewRequest", - "link": "http://golang.org/pkg/net/http/#NewRequest", - "description": "Golang HTTP client request" + "key": "cohttp", + "title": "CoHTTP", + "link": "https://github.com/mirage/ocaml-cohttp", + "description": "Cohttp is a very lightweight HTTP server using Lwt or Async for OCaml" } ] }, { - "key": "java", - "title": "Java", - "extname": ".java", - "default": "unirest", + "key": "php", + "title": "PHP", + "extname": ".php", + "default": "curl", "clients": [ { - "key": "okhttp", - "title": "OkHttp", - "link": "http://square.github.io/okhttp/", - "description": "An HTTP Request Client Library" - }, - { - "key": "unirest", - "title": "Unirest", - "link": "http://unirest.io/java.html", - "description": "Lightweight HTTP Request Client Library" - }, - { - "key": "asynchttp", - "title": "AsyncHttp", - "link": "https://github.com/AsyncHttpClient/async-http-client", - "description": "Asynchronous Http and WebSocket Client library for Java" + "key": "curl", + "title": "cURL", + "link": "http://php.net/manual/en/book.curl.php", + "description": "PHP with ext-curl" }, { - "key": "nethttp", - "title": "java.net.http", - "link": "https://openjdk.java.net/groups/net/httpclient/intro.html", - "description": "Java Standardized HTTP Client API" + "key": "http1", + "title": "HTTP v1", + "link": "http://php.net/manual/en/book.http.php", + "description": "PHP with pecl/http v1" }, { - "key": "restclient", - "title": "Spring RestClient", - "link": "https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/RestClient.html", - "description": "Spring Framework REST client" - } - ] - }, - { - "key": "ruby", - "title": "Ruby", - "extname": ".rb", - "default": "native", - "clients": [ - { - "key": "native", - "title": "net::http", - "link": "http://ruby-doc.org/stdlib-2.2.1/libdoc/net/http/rdoc/Net/HTTP.html", - "description": "Ruby HTTP client" + "key": "http2", + "title": "HTTP v2", + "link": "http://devel-m6w6.rhcloud.com/mdref/http", + "description": "PHP with pecl/http v2" } ] }, { - "key": "csharp", - "title": "C#", - "extname": ".cs", - "default": "restsharp", + "key": "powershell", + "title": "Powershell", + "extname": ".ps1", + "default": "webrequest", "clients": [ { - "key": "restsharp", - "title": "RestSharp", - "link": "http://restsharp.org/", - "description": "Simple REST and HTTP API Client for .NET" + "key": "webrequest", + "title": "Invoke-WebRequest", + "link": "https://docs.microsoft.com/en-us/powershell/module/Microsoft.PowerShell.Utility/Invoke-WebRequest", + "description": "Powershell Invoke-WebRequest client" }, { - "key": "httpclient", - "title": "HttpClient", - "link": "https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient", - "description": ".NET Standard HTTP Client" + "key": "restmethod", + "title": "Invoke-RestMethod", + "link": "https://docs.microsoft.com/en-us/powershell/module/Microsoft.PowerShell.Utility/Invoke-RestMethod", + "description": "Powershell Invoke-RestMethod client" } ] }, { - "key": "clojure", - "title": "Clojure", - "extname": ".clj", - "default": "clj_http", + "key": "python", + "title": "Python", + "extname": ".py", + "default": "python3", "clients": [ { - "key": "clj_http", - "title": "clj-http", - "link": "https://github.com/dakrone/clj-http", - "description": "An idiomatic clojure http client wrapping the apache client." - } - ] - }, - { - "key": "c", - "title": "C", - "extname": ".c", - "default": "libcurl", - "clients": [ + "key": "python3", + "title": "http.client", + "link": "https://docs.python.org/3/library/http.client.html", + "description": "Python3 HTTP Client" + }, { - "key": "libcurl", - "title": "Libcurl", - "link": "http://curl.haxx.se/libcurl/", - "description": "Simple REST and HTTP API Client for C" + "key": "requests", + "title": "Requests", + "link": "http://docs.python-requests.org/en/latest/api/#requests.request", + "description": "Requests HTTP library" } ] }, @@ -312,64 +320,70 @@ ] }, { - "default": "webrequest", - "extname": ".ps1", - "key": "powershell", - "title": "Powershell", + "key": "ruby", + "title": "Ruby", + "extname": ".rb", + "default": "native", "clients": [ { - "description": "Powershell Invoke-WebRequest client", - "key": "webrequest", - "link": "https://docs.microsoft.com/en-us/powershell/module/Microsoft.PowerShell.Utility/Invoke-WebRequest", - "title": "Invoke-WebRequest" - }, - { - "description": "Powershell Invoke-RestMethod client", - "key": "restmethod", - "link": "https://docs.microsoft.com/en-us/powershell/module/Microsoft.PowerShell.Utility/Invoke-RestMethod", - "title": "Invoke-RestMethod" + "key": "native", + "title": "net::http", + "link": "http://ruby-doc.org/stdlib-2.2.1/libdoc/net/http/rdoc/Net/HTTP.html", + "description": "Ruby HTTP client" } ] }, { - "default": "1.1", - "extname": "", - "key": "http", - "title": "HTTP", + "key": "rust", + "title": "Rust", + "extname": ".rs", + "default": "reqwest", "clients": [ { - "description": "HTTP/1.1 request string in accordance with RFC 7230", - "key": "1.1", - "link": "https://tools.ietf.org/html/rfc7230", - "title": "HTTP/1.1" + "key": "reqwest", + "title": "reqwest", + "link": "https://docs.rs/reqwest/latest/reqwest/", + "description": "reqwest HTTP library" } ] }, { - "key": "kotlin", - "title": "Kotlin", - "extname": ".kt", - "default": "okhttp", + "key": "shell", + "title": "Shell", + "extname": ".sh", + "default": "curl", "clients": [ { - "key": "okhttp", - "title": "OkHttp", - "link": "http://square.github.io/okhttp/", - "description": "An HTTP Request Client Library" + "key": "curl", + "title": "cURL", + "link": "http://curl.haxx.se/", + "description": "cURL is a command line tool and library for transferring data with URL syntax" + }, + { + "key": "httpie", + "title": "HTTPie", + "link": "http://httpie.org/", + "description": "a CLI, cURL-like tool for humans" + }, + { + "key": "wget", + "title": "Wget", + "link": "https://www.gnu.org/software/wget/", + "description": "a free software package for retrieving files using HTTP, HTTPS" } ] }, { - "key": "crystal", - "title": "Crystal", - "extname": ".cr", - "default": "native", + "key": "swift", + "title": "Swift", + "extname": ".swift", + "default": "nsurlsession", "clients": [ { - "key": "native", - "title": "http::client", - "link": "https://crystal-lang.org/api/master/HTTP/Client.html", - "description": "Crystal HTTP client" + "key": "nsurlsession", + "title": "NSURLSession", + "link": "https://developer.apple.com/library/mac/documentation/Foundation/Reference/NSURLSession_class/index.html", + "description": "Foundation's NSURLSession request" } ] } diff --git a/test/fixtures/output/rust/reqwest/application-form-encoded.rs b/test/fixtures/output/rust/reqwest/application-form-encoded.rs new file mode 100644 index 0000000..4a96f4a --- /dev/null +++ b/test/fixtures/output/rust/reqwest/application-form-encoded.rs @@ -0,0 +1,29 @@ +use serde_json::json; +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "http://mockbin.com/har"; + + let payload = json!({ + "foo": "bar", + "hello": "world" + }); + + let mut headers = reqwest::header::HeaderMap::new(); + headers.insert("content-type", "application/x-www-form-urlencoded".parse().unwrap()); + + let client = reqwest::Client::new(); + let response = client.post(url) + .headers(headers) + .form(&payload) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} \ No newline at end of file diff --git a/test/fixtures/output/rust/reqwest/application-json.rs b/test/fixtures/output/rust/reqwest/application-json.rs new file mode 100644 index 0000000..d3105ac --- /dev/null +++ b/test/fixtures/output/rust/reqwest/application-json.rs @@ -0,0 +1,33 @@ +use serde_json::json; +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "http://mockbin.com/har"; + + let payload = json!({ + "number": 1, + "string": "f\"oo", + "arr": (1, 2, 3), + "nested": json!({"a": "b"}), + "arr_mix": (1, "a", json!({"arr_mix_nested": json!({})})), + "boolean": false + }); + + let mut headers = reqwest::header::HeaderMap::new(); + headers.insert("content-type", "application/json".parse().unwrap()); + + let client = reqwest::Client::new(); + let response = client.post(url) + .headers(headers) + .json(&payload) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} \ No newline at end of file diff --git a/test/fixtures/output/rust/reqwest/compression.rs b/test/fixtures/output/rust/reqwest/compression.rs new file mode 100644 index 0000000..df4fdb4 --- /dev/null +++ b/test/fixtures/output/rust/reqwest/compression.rs @@ -0,0 +1,22 @@ +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "http://mockbin.com/har"; + + let mut headers = reqwest::header::HeaderMap::new(); + headers.insert("accept-encoding", "deflate, gzip, br".parse().unwrap()); + + let client = reqwest::Client::new(); + let response = client.get(url) + .headers(headers) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} \ No newline at end of file diff --git a/test/fixtures/output/rust/reqwest/cookies.rs b/test/fixtures/output/rust/reqwest/cookies.rs new file mode 100644 index 0000000..c420b5a --- /dev/null +++ b/test/fixtures/output/rust/reqwest/cookies.rs @@ -0,0 +1,22 @@ +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "http://mockbin.com/har"; + + let mut headers = reqwest::header::HeaderMap::new(); + headers.insert("cookie", "foo=bar; bar=baz".parse().unwrap()); + + let client = reqwest::Client::new(); + let response = client.post(url) + .headers(headers) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} \ No newline at end of file diff --git a/test/fixtures/output/rust/reqwest/custom-method.rs b/test/fixtures/output/rust/reqwest/custom-method.rs new file mode 100644 index 0000000..449e46c --- /dev/null +++ b/test/fixtures/output/rust/reqwest/custom-method.rs @@ -0,0 +1,19 @@ +use std::str::FromStr; +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "http://mockbin.com/har"; + + let client = reqwest::Client::new(); + let response = client.request(reqwest::Method::from_str("PROPFIND").unwrap(), url) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} \ No newline at end of file diff --git a/test/fixtures/output/rust/reqwest/full.rs b/test/fixtures/output/rust/reqwest/full.rs new file mode 100644 index 0000000..486a102 --- /dev/null +++ b/test/fixtures/output/rust/reqwest/full.rs @@ -0,0 +1,35 @@ +use serde_json::json; +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "http://mockbin.com/har"; + + let querystring = [ + ("foo", "barbaz"), + ("baz", "abc"), + ("key", "value"), + ]; + + let payload = json!({"foo": "bar"}); + + let mut headers = reqwest::header::HeaderMap::new(); + headers.insert("cookie", "foo=bar; bar=baz".parse().unwrap()); + headers.insert("accept", "application/json".parse().unwrap()); + headers.insert("content-type", "application/x-www-form-urlencoded".parse().unwrap()); + + let client = reqwest::Client::new(); + let response = client.post(url) + .query(&querystring) + .headers(headers) + .form(&payload) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} \ No newline at end of file diff --git a/test/fixtures/output/rust/reqwest/headers.rs b/test/fixtures/output/rust/reqwest/headers.rs new file mode 100644 index 0000000..59cfbbc --- /dev/null +++ b/test/fixtures/output/rust/reqwest/headers.rs @@ -0,0 +1,24 @@ +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "http://mockbin.com/har"; + + let mut headers = reqwest::header::HeaderMap::new(); + headers.insert("accept", "application/json".parse().unwrap()); + headers.insert("x-foo", "Bar".parse().unwrap()); + headers.insert("quoted-value", "\"quoted\" 'string'".parse().unwrap()); + + let client = reqwest::Client::new(); + let response = client.get(url) + .headers(headers) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} \ No newline at end of file diff --git a/test/fixtures/output/rust/reqwest/https.rs b/test/fixtures/output/rust/reqwest/https.rs new file mode 100644 index 0000000..2b783c2 --- /dev/null +++ b/test/fixtures/output/rust/reqwest/https.rs @@ -0,0 +1,18 @@ +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "https://mockbin.com/har"; + + let client = reqwest::Client::new(); + let response = client.get(url) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} \ No newline at end of file diff --git a/test/fixtures/output/rust/reqwest/jsonObj-multiline.rs b/test/fixtures/output/rust/reqwest/jsonObj-multiline.rs new file mode 100644 index 0000000..c883631 --- /dev/null +++ b/test/fixtures/output/rust/reqwest/jsonObj-multiline.rs @@ -0,0 +1,26 @@ +use serde_json::json; +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "http://mockbin.com/har"; + + let payload = json!({"foo": "bar"}); + + let mut headers = reqwest::header::HeaderMap::new(); + headers.insert("content-type", "application/json".parse().unwrap()); + + let client = reqwest::Client::new(); + let response = client.post(url) + .headers(headers) + .json(&payload) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} \ No newline at end of file diff --git a/test/fixtures/output/rust/reqwest/jsonObj-null-value.rs b/test/fixtures/output/rust/reqwest/jsonObj-null-value.rs new file mode 100644 index 0000000..daa72c9 --- /dev/null +++ b/test/fixtures/output/rust/reqwest/jsonObj-null-value.rs @@ -0,0 +1,26 @@ +use serde_json::json; +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "http://mockbin.com/har"; + + let payload = json!({"foo": json!(null)}); + + let mut headers = reqwest::header::HeaderMap::new(); + headers.insert("content-type", "application/json".parse().unwrap()); + + let client = reqwest::Client::new(); + let response = client.post(url) + .headers(headers) + .json(&payload) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} \ No newline at end of file diff --git a/test/fixtures/output/rust/reqwest/malicious.rs b/test/fixtures/output/rust/reqwest/malicious.rs new file mode 100644 index 0000000..f6e19d1 --- /dev/null +++ b/test/fixtures/output/rust/reqwest/malicious.rs @@ -0,0 +1,67 @@ +use serde_json::json; +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//"; + + let querystring = [ + ("'", "squote-key-test"), + ("squote-value-test", "'"), + ("\"", "dquote-key-test"), + ("dquote-value-test", "\""), + ("`", "backtick-key-test"), + ("backtick-value-test", "`"), + ("$(", "dollar-parenthesis-key-test"), + ("dollar-parenthesis-value-test", "$("), + ("#{", "hash-brace-key-test"), + ("hash-brace-value-test", "#{"), + ("%(", "percent-parenthesis-key-test"), + ("percent-parenthesis-value-test", "%("), + ("%{", "percent-brace-key-test"), + ("percent-brace-value-test", "%{"), + ("{{", "double-brace-key-test"), + ("double-brace-value-test", "{{"), + ("\\0", "null-key-test"), + ("null-value-test", "\\0"), + ("%s", "string-fmt-key-test"), + ("string-fmt-value-test", "%s"), + ("\\", "slash-key-test"), + ("slash-value-test", "\\"), + ]; + + let payload = "' \" ` $( #{ %( %{ {{ \\0 %s \\"; + + let mut headers = reqwest::header::HeaderMap::new(); + headers.insert("'", "squote-key-test".parse().unwrap()); + headers.insert("squote-value-test", "'".parse().unwrap()); + headers.insert("dquote-value-test", "\"".parse().unwrap()); + headers.insert("`", "backtick-key-test".parse().unwrap()); + headers.insert("backtick-value-test", "`".parse().unwrap()); + headers.insert("$", "dollar-key-test".parse().unwrap()); + headers.insert("dollar-parenthesis-value-test", "$(".parse().unwrap()); + headers.insert("#", "hash-key-test".parse().unwrap()); + headers.insert("hash-brace-value-test", "#{".parse().unwrap()); + headers.insert("%", "percent-key-test".parse().unwrap()); + headers.insert("percent-parenthesis-value-test", "%(".parse().unwrap()); + headers.insert("percent-brace-value-test", "%{".parse().unwrap()); + headers.insert("double-brace-value-test", "{{".parse().unwrap()); + headers.insert("null-value-test", "\\0".parse().unwrap()); + headers.insert("string-fmt-value-test", "%s".parse().unwrap()); + headers.insert("slash-value-test", "\\".parse().unwrap()); + + let client = reqwest::Client::new(); + let response = client.post(url) + .query(&querystring) + .headers(headers) + .body(payload) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} \ No newline at end of file diff --git a/test/fixtures/output/rust/reqwest/multipart-data.rs b/test/fixtures/output/rust/reqwest/multipart-data.rs new file mode 100644 index 0000000..ae79cbf --- /dev/null +++ b/test/fixtures/output/rust/reqwest/multipart-data.rs @@ -0,0 +1,33 @@ +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "http://mockbin.com/har"; + + async fn file_to_part(file_name: &'static str) -> reqwest::multipart::Part { + let file = tokio::fs::File::open(file_name).await.unwrap(); + let stream = tokio_util::codec::FramedRead::new(file, tokio_util::codec::BytesCodec::new()); + let body = reqwest::Body::wrap_stream(stream); + reqwest::multipart::Part::stream(body) + .file_name(file_name) + .mime_str("text/plain").unwrap() + } + + let form = reqwest::multipart::Form::new() + .part("foo", file_to_part("hello.txt").await); + let mut headers = reqwest::header::HeaderMap::new(); + + let client = reqwest::Client::new(); + let response = client.post(url) + .multipart(form) + .headers(headers) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} \ No newline at end of file diff --git a/test/fixtures/output/rust/reqwest/multipart-file.rs b/test/fixtures/output/rust/reqwest/multipart-file.rs new file mode 100644 index 0000000..64f372b --- /dev/null +++ b/test/fixtures/output/rust/reqwest/multipart-file.rs @@ -0,0 +1,33 @@ +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "http://mockbin.com/har"; + + async fn file_to_part(file_name: &'static str) -> reqwest::multipart::Part { + let file = tokio::fs::File::open(file_name).await.unwrap(); + let stream = tokio_util::codec::FramedRead::new(file, tokio_util::codec::BytesCodec::new()); + let body = reqwest::Body::wrap_stream(stream); + reqwest::multipart::Part::stream(body) + .file_name(file_name) + .mime_str("text/plain").unwrap() + } + + let form = reqwest::multipart::Form::new() + .part("foo", file_to_part("test/fixtures/files/hello.txt").await); + let mut headers = reqwest::header::HeaderMap::new(); + + let client = reqwest::Client::new(); + let response = client.post(url) + .multipart(form) + .headers(headers) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} \ No newline at end of file diff --git a/test/fixtures/output/rust/reqwest/multipart-form-data.rs b/test/fixtures/output/rust/reqwest/multipart-form-data.rs new file mode 100644 index 0000000..a2907cc --- /dev/null +++ b/test/fixtures/output/rust/reqwest/multipart-form-data.rs @@ -0,0 +1,24 @@ +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "http://mockbin.com/har"; + + let form = reqwest::multipart::Form::new() + .text("foo", "bar"); + let mut headers = reqwest::header::HeaderMap::new(); + + let client = reqwest::Client::new(); + let response = client.post(url) + .multipart(form) + .headers(headers) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} \ No newline at end of file diff --git a/test/fixtures/output/rust/reqwest/nested.rs b/test/fixtures/output/rust/reqwest/nested.rs new file mode 100644 index 0000000..77ddc19 --- /dev/null +++ b/test/fixtures/output/rust/reqwest/nested.rs @@ -0,0 +1,25 @@ +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "http://mockbin.com/har"; + + let querystring = [ + ("foo[bar]", "baz,zap"), + ("fiz", "buz"), + ("key", "value"), + ]; + + let client = reqwest::Client::new(); + let response = client.get(url) + .query(&querystring) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} \ No newline at end of file diff --git a/test/fixtures/output/rust/reqwest/query.rs b/test/fixtures/output/rust/reqwest/query.rs new file mode 100644 index 0000000..753741c --- /dev/null +++ b/test/fixtures/output/rust/reqwest/query.rs @@ -0,0 +1,25 @@ +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "http://mockbin.com/har"; + + let querystring = [ + ("foo", "barbaz"), + ("baz", "abc"), + ("key", "value"), + ]; + + let client = reqwest::Client::new(); + let response = client.get(url) + .query(&querystring) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} \ No newline at end of file diff --git a/test/fixtures/output/rust/reqwest/short.rs b/test/fixtures/output/rust/reqwest/short.rs new file mode 100644 index 0000000..4250488 --- /dev/null +++ b/test/fixtures/output/rust/reqwest/short.rs @@ -0,0 +1,18 @@ +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "http://mockbin.com/har"; + + let client = reqwest::Client::new(); + let response = client.get(url) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} \ No newline at end of file diff --git a/test/fixtures/output/rust/reqwest/text-plain.rs b/test/fixtures/output/rust/reqwest/text-plain.rs new file mode 100644 index 0000000..3a47ddf --- /dev/null +++ b/test/fixtures/output/rust/reqwest/text-plain.rs @@ -0,0 +1,26 @@ +use serde_json::json; +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "http://mockbin.com/har"; + + let payload = "Hello World"; + + let mut headers = reqwest::header::HeaderMap::new(); + headers.insert("content-type", "text/plain".parse().unwrap()); + + let client = reqwest::Client::new(); + let response = client.post(url) + .headers(headers) + .body(payload) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} \ No newline at end of file diff --git a/test/fixtures/output/rust/reqwest/unparseable-query.rs b/test/fixtures/output/rust/reqwest/unparseable-query.rs new file mode 100644 index 0000000..c402cdf --- /dev/null +++ b/test/fixtures/output/rust/reqwest/unparseable-query.rs @@ -0,0 +1,18 @@ +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "http://mockbin.com/har?&&a=b&&"; + + let client = reqwest::Client::new(); + let response = client.get(url) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} \ No newline at end of file diff --git a/test/targets/rust/reqwest.js b/test/targets/rust/reqwest.js new file mode 100644 index 0000000..b77cc77 --- /dev/null +++ b/test/targets/rust/reqwest.js @@ -0,0 +1,3 @@ +'use strict' + +module.exports = function (snippet, fixtures) {} From 36231a35c25284c57b2c80eef09cccf0627bb2f7 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Wed, 12 Nov 2025 12:43:28 +0100 Subject: [PATCH 25/36] Support any method for Powershell Taken from upstream --- src/targets/powershell/common.js | 21 +++++++++++++------ .../powershell/restmethod/custom-method.ps1 | 2 +- .../powershell/webrequest/custom-method.ps1 | 2 +- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/targets/powershell/common.js b/src/targets/powershell/common.js index aa5497e..9254300 100644 --- a/src/targets/powershell/common.js +++ b/src/targets/powershell/common.js @@ -14,11 +14,19 @@ const psSqEscape = function (input) { module.exports = function (command) { return function (source, options) { const code = new CodeBuilder() - const methods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'] - - if (methods.indexOf(source.method.toUpperCase()) === -1) { - return 'Method not supported' - } + const methods = [ + 'DEFAULT', + 'DELETE', + 'GET', + 'HEAD', + 'MERGE', + 'OPTIONS', + 'PATCH', + 'POST', + 'PUT', + 'TRACE' + ] + const methodArg = methods.includes(source.method.toUpperCase()) ? '-Method' : '-CustomMethod' const commandOptions = [] @@ -66,9 +74,10 @@ module.exports = function (command) { ) } - code.push("$response = %s -Uri '%s' -Method %s %s", + code.push("$response = %s -Uri '%s' %s %s %s", command, psSqEscape(source.fullUrl), + methodArg, source.method, commandOptions.join(' ') ) diff --git a/test/fixtures/output/powershell/restmethod/custom-method.ps1 b/test/fixtures/output/powershell/restmethod/custom-method.ps1 index 5e5237a..acbd914 100644 --- a/test/fixtures/output/powershell/restmethod/custom-method.ps1 +++ b/test/fixtures/output/powershell/restmethod/custom-method.ps1 @@ -1 +1 @@ -Method not supported +$response = Invoke-RestMethod -Uri 'http://mockbin.com/har' -CustomMethod PROPFIND \ No newline at end of file diff --git a/test/fixtures/output/powershell/webrequest/custom-method.ps1 b/test/fixtures/output/powershell/webrequest/custom-method.ps1 index 5e5237a..5f587e4 100644 --- a/test/fixtures/output/powershell/webrequest/custom-method.ps1 +++ b/test/fixtures/output/powershell/webrequest/custom-method.ps1 @@ -1 +1 @@ -Method not supported +$response = Invoke-WebRequest -Uri 'http://mockbin.com/har' -CustomMethod PROPFIND \ No newline at end of file From 3d3c0d0a0615d97993b7a5dc9e4ea13480431eee Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Wed, 12 Nov 2025 14:28:36 +0100 Subject: [PATCH 26/36] Fix RestSharp snippets Extending equivalent upstream change --- src/targets/csharp/restsharp.js | 20 ++++++++++++++----- .../restsharp/application-form-encoded.cs | 6 +++--- .../csharp/restsharp/application-json.cs | 6 +++--- .../output/csharp/restsharp/compression.cs | 6 +++--- .../output/csharp/restsharp/cookies.cs | 6 +++--- .../output/csharp/restsharp/custom-method.cs | 2 +- test/fixtures/output/csharp/restsharp/full.cs | 6 +++--- .../output/csharp/restsharp/headers.cs | 6 +++--- .../fixtures/output/csharp/restsharp/https.cs | 6 +++--- .../csharp/restsharp/jsonObj-multiline.cs | 6 +++--- .../csharp/restsharp/jsonObj-null-value.cs | 6 +++--- .../output/csharp/restsharp/malicious.cs | 8 ++++---- .../output/csharp/restsharp/multipart-data.cs | 6 +++--- .../output/csharp/restsharp/multipart-file.cs | 6 +++--- .../csharp/restsharp/multipart-form-data.cs | 6 +++--- .../output/csharp/restsharp/nested.cs | 6 +++--- .../fixtures/output/csharp/restsharp/query.cs | 6 +++--- .../fixtures/output/csharp/restsharp/short.cs | 6 +++--- .../output/csharp/restsharp/text-plain.cs | 6 +++--- .../csharp/restsharp/unparseable-query.cs | 6 +++--- 20 files changed, 71 insertions(+), 61 deletions(-) diff --git a/src/targets/csharp/restsharp.js b/src/targets/csharp/restsharp.js index 373f996..63a4df1 100644 --- a/src/targets/csharp/restsharp.js +++ b/src/targets/csharp/restsharp.js @@ -1,17 +1,25 @@ 'use strict' const CodeBuilder = require('../../helpers/code-builder') +const { escape } = require('../../helpers/format') const helpers = require('../../helpers/headers') module.exports = function (source, options) { const code = new CodeBuilder() const methods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'] + function toPascalCase (str) { + return str.replace( + /\w+/g, + word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase() + ) + } + if (methods.indexOf(source.method.toUpperCase()) === -1) { return 'Method not supported' } else { - code.push('var client = new RestClient("%s");', source.fullUrl) - code.push('var request = new RestRequest(Method.%s);', source.method.toUpperCase()) + code.push('var client = new RestClient("%s//%s");', source.uriObj.protocol, source.uriObj.host) + code.push('var request = new RestRequest("%s", Method.%s);', escape(source.uriObj.path), toPascalCase(source.method)) } // Add headers, including the cookies @@ -32,14 +40,16 @@ module.exports = function (source, options) { } if (source.postData.text) { + const contentTypeHeader = helpers.getHeader(source.allHeaders, 'content-type') + code.push( - 'request.AddParameter("%s", %s, ParameterType.RequestBody);', - helpers.getHeader(source.allHeaders, 'content-type'), + 'request.AddParameter(%s, %s, ParameterType.RequestBody);', + contentTypeHeader ? `"${escape(contentTypeHeader)}"` : 'null', JSON.stringify(source.postData.text) ) } - code.push('IRestResponse response = client.Execute(request);') + code.push('var response = client.Execute(request);') return code.join() } diff --git a/test/fixtures/output/csharp/restsharp/application-form-encoded.cs b/test/fixtures/output/csharp/restsharp/application-form-encoded.cs index 96f3f8b..2959968 100644 --- a/test/fixtures/output/csharp/restsharp/application-form-encoded.cs +++ b/test/fixtures/output/csharp/restsharp/application-form-encoded.cs @@ -1,5 +1,5 @@ -var client = new RestClient("http://mockbin.com/har"); -var request = new RestRequest(Method.POST); +var client = new RestClient("http://mockbin.com"); +var request = new RestRequest("/har", Method.Post); request.AddHeader("content-type", "application/x-www-form-urlencoded"); request.AddParameter("application/x-www-form-urlencoded", "foo=bar&hello=world", ParameterType.RequestBody); -IRestResponse response = client.Execute(request); +var response = client.Execute(request); \ No newline at end of file diff --git a/test/fixtures/output/csharp/restsharp/application-json.cs b/test/fixtures/output/csharp/restsharp/application-json.cs index 30a977b..5f1559b 100644 --- a/test/fixtures/output/csharp/restsharp/application-json.cs +++ b/test/fixtures/output/csharp/restsharp/application-json.cs @@ -1,5 +1,5 @@ -var client = new RestClient("http://mockbin.com/har"); -var request = new RestRequest(Method.POST); +var client = new RestClient("http://mockbin.com"); +var request = new RestRequest("/har", Method.Post); request.AddHeader("content-type", "application/json"); request.AddParameter("application/json", "{\"number\":1,\"string\":\"f\\\"oo\",\"arr\":[1,2,3],\"nested\":{\"a\":\"b\"},\"arr_mix\":[1,\"a\",{\"arr_mix_nested\":{}}],\"boolean\":false}", ParameterType.RequestBody); -IRestResponse response = client.Execute(request); +var response = client.Execute(request); \ No newline at end of file diff --git a/test/fixtures/output/csharp/restsharp/compression.cs b/test/fixtures/output/csharp/restsharp/compression.cs index c3f7c28..f7bab10 100644 --- a/test/fixtures/output/csharp/restsharp/compression.cs +++ b/test/fixtures/output/csharp/restsharp/compression.cs @@ -1,4 +1,4 @@ -var client = new RestClient("http://mockbin.com/har"); -var request = new RestRequest(Method.GET); +var client = new RestClient("http://mockbin.com"); +var request = new RestRequest("/har", Method.Get); request.AddHeader("accept-encoding", "deflate, gzip, br"); -IRestResponse response = client.Execute(request); \ No newline at end of file +var response = client.Execute(request); \ No newline at end of file diff --git a/test/fixtures/output/csharp/restsharp/cookies.cs b/test/fixtures/output/csharp/restsharp/cookies.cs index 910b4f5..6e4d410 100644 --- a/test/fixtures/output/csharp/restsharp/cookies.cs +++ b/test/fixtures/output/csharp/restsharp/cookies.cs @@ -1,5 +1,5 @@ -var client = new RestClient("http://mockbin.com/har"); -var request = new RestRequest(Method.POST); +var client = new RestClient("http://mockbin.com"); +var request = new RestRequest("/har", Method.Post); request.AddCookie("foo", "bar"); request.AddCookie("bar", "baz"); -IRestResponse response = client.Execute(request); +var response = client.Execute(request); \ No newline at end of file diff --git a/test/fixtures/output/csharp/restsharp/custom-method.cs b/test/fixtures/output/csharp/restsharp/custom-method.cs index 5e5237a..8eb41a6 100644 --- a/test/fixtures/output/csharp/restsharp/custom-method.cs +++ b/test/fixtures/output/csharp/restsharp/custom-method.cs @@ -1 +1 @@ -Method not supported +Method not supported \ No newline at end of file diff --git a/test/fixtures/output/csharp/restsharp/full.cs b/test/fixtures/output/csharp/restsharp/full.cs index 2a326cc..6642d48 100644 --- a/test/fixtures/output/csharp/restsharp/full.cs +++ b/test/fixtures/output/csharp/restsharp/full.cs @@ -1,8 +1,8 @@ -var client = new RestClient("http://mockbin.com/har?foo=bar&foo=baz&baz=abc&key=value"); -var request = new RestRequest(Method.POST); +var client = new RestClient("http://mockbin.com"); +var request = new RestRequest("/har?foo=bar&foo=baz&baz=abc&key=value", Method.Post); request.AddHeader("accept", "application/json"); request.AddHeader("content-type", "application/x-www-form-urlencoded"); request.AddCookie("foo", "bar"); request.AddCookie("bar", "baz"); request.AddParameter("application/x-www-form-urlencoded", "foo=bar", ParameterType.RequestBody); -IRestResponse response = client.Execute(request); +var response = client.Execute(request); \ No newline at end of file diff --git a/test/fixtures/output/csharp/restsharp/headers.cs b/test/fixtures/output/csharp/restsharp/headers.cs index febda66..345f140 100644 --- a/test/fixtures/output/csharp/restsharp/headers.cs +++ b/test/fixtures/output/csharp/restsharp/headers.cs @@ -1,6 +1,6 @@ -var client = new RestClient("http://mockbin.com/har"); -var request = new RestRequest(Method.GET); +var client = new RestClient("http://mockbin.com"); +var request = new RestRequest("/har", Method.Get); request.AddHeader("accept", "application/json"); request.AddHeader("x-foo", "Bar"); request.AddHeader("quoted-value", "\"quoted\" 'string'"); -IRestResponse response = client.Execute(request); +var response = client.Execute(request); \ No newline at end of file diff --git a/test/fixtures/output/csharp/restsharp/https.cs b/test/fixtures/output/csharp/restsharp/https.cs index 8be49d7..97355f7 100644 --- a/test/fixtures/output/csharp/restsharp/https.cs +++ b/test/fixtures/output/csharp/restsharp/https.cs @@ -1,3 +1,3 @@ -var client = new RestClient("https://mockbin.com/har"); -var request = new RestRequest(Method.GET); -IRestResponse response = client.Execute(request); +var client = new RestClient("https://mockbin.com"); +var request = new RestRequest("/har", Method.Get); +var response = client.Execute(request); \ No newline at end of file diff --git a/test/fixtures/output/csharp/restsharp/jsonObj-multiline.cs b/test/fixtures/output/csharp/restsharp/jsonObj-multiline.cs index 20a7577..b3062e3 100644 --- a/test/fixtures/output/csharp/restsharp/jsonObj-multiline.cs +++ b/test/fixtures/output/csharp/restsharp/jsonObj-multiline.cs @@ -1,5 +1,5 @@ -var client = new RestClient("http://mockbin.com/har"); -var request = new RestRequest(Method.POST); +var client = new RestClient("http://mockbin.com"); +var request = new RestRequest("/har", Method.Post); request.AddHeader("content-type", "application/json"); request.AddParameter("application/json", "{\n \"foo\": \"bar\"\n}", ParameterType.RequestBody); -IRestResponse response = client.Execute(request); +var response = client.Execute(request); \ No newline at end of file diff --git a/test/fixtures/output/csharp/restsharp/jsonObj-null-value.cs b/test/fixtures/output/csharp/restsharp/jsonObj-null-value.cs index fda9215..1eb3388 100644 --- a/test/fixtures/output/csharp/restsharp/jsonObj-null-value.cs +++ b/test/fixtures/output/csharp/restsharp/jsonObj-null-value.cs @@ -1,5 +1,5 @@ -var client = new RestClient("http://mockbin.com/har"); -var request = new RestRequest(Method.POST); +var client = new RestClient("http://mockbin.com"); +var request = new RestRequest("/har", Method.Post); request.AddHeader("content-type", "application/json"); request.AddParameter("application/json", "{\"foo\":null}", ParameterType.RequestBody); -IRestResponse response = client.Execute(request); +var response = client.Execute(request); \ No newline at end of file diff --git a/test/fixtures/output/csharp/restsharp/malicious.cs b/test/fixtures/output/csharp/restsharp/malicious.cs index 02140dd..0c80d86 100644 --- a/test/fixtures/output/csharp/restsharp/malicious.cs +++ b/test/fixtures/output/csharp/restsharp/malicious.cs @@ -1,5 +1,5 @@ -var client = new RestClient("http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//?'=squote-key-test&squote-value-test='&%22=dquote-key-test&dquote-value-test=%22&%60=backtick-key-test&backtick-value-test=%60&%24(=dollar-parenthesis-key-test&dollar-parenthesis-value-test=%24(&%23%7B=hash-brace-key-test&hash-brace-value-test=%23%7B&%25(=percent-parenthesis-key-test&percent-parenthesis-value-test=%25(&%25%7B=percent-brace-key-test&percent-brace-value-test=%25%7B&%7B%7B=double-brace-key-test&double-brace-value-test=%7B%7B&%5C0=null-key-test&null-value-test=%5C0&%25s=string-fmt-key-test&string-fmt-value-test=%25s&%5C=slash-key-test&slash-value-test=%5C"); -var request = new RestRequest(Method.POST); +var client = new RestClient("http://example.test"); +var request = new RestRequest("/%27%22%60$(%(%%7B%7B%7B/0%s//?'=squote-key-test&squote-value-test='&%22=dquote-key-test&dquote-value-test=%22&%60=backtick-key-test&backtick-value-test=%60&%24(=dollar-parenthesis-key-test&dollar-parenthesis-value-test=%24(&%23%7B=hash-brace-key-test&hash-brace-value-test=%23%7B&%25(=percent-parenthesis-key-test&percent-parenthesis-value-test=%25(&%25%7B=percent-brace-key-test&percent-brace-value-test=%25%7B&%7B%7B=double-brace-key-test&double-brace-value-test=%7B%7B&%5C0=null-key-test&null-value-test=%5C0&%25s=string-fmt-key-test&string-fmt-value-test=%25s&%5C=slash-key-test&slash-value-test=%5C", Method.Post); request.AddHeader("'", "squote-key-test"); request.AddHeader("squote-value-test", "'"); request.AddHeader("dquote-value-test", "\""); @@ -16,5 +16,5 @@ request.AddHeader("null-value-test", "\\0"); request.AddHeader("string-fmt-value-test", "%s"); request.AddHeader("slash-value-test", "\\"); -request.AddParameter("undefined", "' \" ` $( #{ %( %{ {{ \\0 %s \\", ParameterType.RequestBody); -IRestResponse response = client.Execute(request); \ No newline at end of file +request.AddParameter(null, "' \" ` $( #{ %( %{ {{ \\0 %s \\", ParameterType.RequestBody); +var response = client.Execute(request); \ No newline at end of file diff --git a/test/fixtures/output/csharp/restsharp/multipart-data.cs b/test/fixtures/output/csharp/restsharp/multipart-data.cs index 9db5bec..4d48b37 100644 --- a/test/fixtures/output/csharp/restsharp/multipart-data.cs +++ b/test/fixtures/output/csharp/restsharp/multipart-data.cs @@ -1,5 +1,5 @@ -var client = new RestClient("http://mockbin.com/har"); -var request = new RestRequest(Method.POST); +var client = new RestClient("http://mockbin.com"); +var request = new RestRequest("/har", Method.Post); request.AddHeader("content-type", "multipart/form-data; boundary=---011000010111000001101001"); request.AddParameter("multipart/form-data; boundary=---011000010111000001101001", "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"; filename=\"hello.txt\"\r\nContent-Type: text/plain\r\n\r\nHello World\r\n-----011000010111000001101001--\r\n", ParameterType.RequestBody); -IRestResponse response = client.Execute(request); +var response = client.Execute(request); \ No newline at end of file diff --git a/test/fixtures/output/csharp/restsharp/multipart-file.cs b/test/fixtures/output/csharp/restsharp/multipart-file.cs index d91e66b..d449324 100644 --- a/test/fixtures/output/csharp/restsharp/multipart-file.cs +++ b/test/fixtures/output/csharp/restsharp/multipart-file.cs @@ -1,5 +1,5 @@ -var client = new RestClient("http://mockbin.com/har"); -var request = new RestRequest(Method.POST); +var client = new RestClient("http://mockbin.com"); +var request = new RestRequest("/har", Method.Post); request.AddHeader("content-type", "multipart/form-data; boundary=---011000010111000001101001"); request.AddParameter("multipart/form-data; boundary=---011000010111000001101001", "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"; filename=\"hello.txt\"\r\nContent-Type: text/plain\r\n\r\n\r\n-----011000010111000001101001--\r\n", ParameterType.RequestBody); -IRestResponse response = client.Execute(request); +var response = client.Execute(request); \ No newline at end of file diff --git a/test/fixtures/output/csharp/restsharp/multipart-form-data.cs b/test/fixtures/output/csharp/restsharp/multipart-form-data.cs index aae6aa5..bae66ae 100644 --- a/test/fixtures/output/csharp/restsharp/multipart-form-data.cs +++ b/test/fixtures/output/csharp/restsharp/multipart-form-data.cs @@ -1,5 +1,5 @@ -var client = new RestClient("http://mockbin.com/har"); -var request = new RestRequest(Method.POST); +var client = new RestClient("http://mockbin.com"); +var request = new RestRequest("/har", Method.Post); request.AddHeader("Content-Type", "multipart/form-data; boundary=---011000010111000001101001"); request.AddParameter("multipart/form-data; boundary=---011000010111000001101001", "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"\r\n\r\nbar\r\n-----011000010111000001101001--\r\n", ParameterType.RequestBody); -IRestResponse response = client.Execute(request); +var response = client.Execute(request); \ No newline at end of file diff --git a/test/fixtures/output/csharp/restsharp/nested.cs b/test/fixtures/output/csharp/restsharp/nested.cs index fbc0fd7..ba3dc6e 100644 --- a/test/fixtures/output/csharp/restsharp/nested.cs +++ b/test/fixtures/output/csharp/restsharp/nested.cs @@ -1,3 +1,3 @@ -var client = new RestClient("http://mockbin.com/har?foo%5Bbar%5D=baz%2Czap&fiz=buz&key=value"); -var request = new RestRequest(Method.GET); -IRestResponse response = client.Execute(request); +var client = new RestClient("http://mockbin.com"); +var request = new RestRequest("/har?foo%5Bbar%5D=baz%2Czap&fiz=buz&key=value", Method.Get); +var response = client.Execute(request); \ No newline at end of file diff --git a/test/fixtures/output/csharp/restsharp/query.cs b/test/fixtures/output/csharp/restsharp/query.cs index 9384530..36fdee0 100644 --- a/test/fixtures/output/csharp/restsharp/query.cs +++ b/test/fixtures/output/csharp/restsharp/query.cs @@ -1,3 +1,3 @@ -var client = new RestClient("http://mockbin.com/har?foo=bar&foo=baz&baz=abc&key=value"); -var request = new RestRequest(Method.GET); -IRestResponse response = client.Execute(request); +var client = new RestClient("http://mockbin.com"); +var request = new RestRequest("/har?foo=bar&foo=baz&baz=abc&key=value", Method.Get); +var response = client.Execute(request); \ No newline at end of file diff --git a/test/fixtures/output/csharp/restsharp/short.cs b/test/fixtures/output/csharp/restsharp/short.cs index eb5c9f5..1312efe 100644 --- a/test/fixtures/output/csharp/restsharp/short.cs +++ b/test/fixtures/output/csharp/restsharp/short.cs @@ -1,3 +1,3 @@ -var client = new RestClient("http://mockbin.com/har"); -var request = new RestRequest(Method.GET); -IRestResponse response = client.Execute(request); +var client = new RestClient("http://mockbin.com"); +var request = new RestRequest("/har", Method.Get); +var response = client.Execute(request); \ No newline at end of file diff --git a/test/fixtures/output/csharp/restsharp/text-plain.cs b/test/fixtures/output/csharp/restsharp/text-plain.cs index 958eb97..5789fa7 100644 --- a/test/fixtures/output/csharp/restsharp/text-plain.cs +++ b/test/fixtures/output/csharp/restsharp/text-plain.cs @@ -1,5 +1,5 @@ -var client = new RestClient("http://mockbin.com/har"); -var request = new RestRequest(Method.POST); +var client = new RestClient("http://mockbin.com"); +var request = new RestRequest("/har", Method.Post); request.AddHeader("content-type", "text/plain"); request.AddParameter("text/plain", "Hello World", ParameterType.RequestBody); -IRestResponse response = client.Execute(request); +var response = client.Execute(request); \ No newline at end of file diff --git a/test/fixtures/output/csharp/restsharp/unparseable-query.cs b/test/fixtures/output/csharp/restsharp/unparseable-query.cs index d6ad3c4..2089b1b 100644 --- a/test/fixtures/output/csharp/restsharp/unparseable-query.cs +++ b/test/fixtures/output/csharp/restsharp/unparseable-query.cs @@ -1,3 +1,3 @@ -var client = new RestClient("http://mockbin.com/har?&&a=b&&"); -var request = new RestRequest(Method.GET); -IRestResponse response = client.Execute(request); \ No newline at end of file +var client = new RestClient("http://mockbin.com"); +var request = new RestRequest("/har?&&a=b&&", Method.Get); +var response = client.Execute(request); \ No newline at end of file From 7eb486667b8c1ee92472694ad72992719ecda166 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Wed, 12 Nov 2025 14:48:12 +0100 Subject: [PATCH 27/36] Add Ruby Faraday target Based on upstream --- src/targets/ruby/faraday.js | 104 ++++++++++++++++++ src/targets/ruby/index.js | 3 +- test/fixtures/available-targets.json | 6 + .../ruby/faraday/application-form-encoded.rb | 18 +++ .../output/ruby/faraday/application-json.rb | 13 +++ .../output/ruby/faraday/compression.rb | 12 ++ test/fixtures/output/ruby/faraday/cookies.rb | 12 ++ .../output/ruby/faraday/custom-method.rb | 1 + test/fixtures/output/ruby/faraday/full.rb | 22 ++++ test/fixtures/output/ruby/faraday/headers.rb | 14 +++ test/fixtures/output/ruby/faraday/https.rb | 11 ++ .../output/ruby/faraday/jsonObj-multiline.rb | 13 +++ .../output/ruby/faraday/jsonObj-null-value.rb | 13 +++ .../fixtures/output/ruby/faraday/malicious.rb | 50 +++++++++ .../output/ruby/faraday/multipart-data.rb | 13 +++ .../output/ruby/faraday/multipart-file.rb | 13 +++ .../ruby/faraday/multipart-form-data.rb | 13 +++ test/fixtures/output/ruby/faraday/nested.rb | 14 +++ test/fixtures/output/ruby/faraday/query.rb | 14 +++ test/fixtures/output/ruby/faraday/short.rb | 11 ++ .../output/ruby/faraday/text-plain.rb | 13 +++ .../output/ruby/faraday/unparseable-query.rb | 11 ++ test/targets/ruby/faraday.js | 3 + 23 files changed, 396 insertions(+), 1 deletion(-) create mode 100644 src/targets/ruby/faraday.js create mode 100644 test/fixtures/output/ruby/faraday/application-form-encoded.rb create mode 100644 test/fixtures/output/ruby/faraday/application-json.rb create mode 100644 test/fixtures/output/ruby/faraday/compression.rb create mode 100644 test/fixtures/output/ruby/faraday/cookies.rb create mode 100644 test/fixtures/output/ruby/faraday/custom-method.rb create mode 100644 test/fixtures/output/ruby/faraday/full.rb create mode 100644 test/fixtures/output/ruby/faraday/headers.rb create mode 100644 test/fixtures/output/ruby/faraday/https.rb create mode 100644 test/fixtures/output/ruby/faraday/jsonObj-multiline.rb create mode 100644 test/fixtures/output/ruby/faraday/jsonObj-null-value.rb create mode 100644 test/fixtures/output/ruby/faraday/malicious.rb create mode 100644 test/fixtures/output/ruby/faraday/multipart-data.rb create mode 100644 test/fixtures/output/ruby/faraday/multipart-file.rb create mode 100644 test/fixtures/output/ruby/faraday/multipart-form-data.rb create mode 100644 test/fixtures/output/ruby/faraday/nested.rb create mode 100644 test/fixtures/output/ruby/faraday/query.rb create mode 100644 test/fixtures/output/ruby/faraday/short.rb create mode 100644 test/fixtures/output/ruby/faraday/text-plain.rb create mode 100644 test/fixtures/output/ruby/faraday/unparseable-query.rb create mode 100644 test/targets/ruby/faraday.js diff --git a/src/targets/ruby/faraday.js b/src/targets/ruby/faraday.js new file mode 100644 index 0000000..87657ea --- /dev/null +++ b/src/targets/ruby/faraday.js @@ -0,0 +1,104 @@ +const CodeBuilder = require('../../helpers/code-builder') + +module.exports = ({ uriObj, queryObj, method: rawMethod, postData, allHeaders }) => { + const code = new CodeBuilder() + + // To support custom methods we check for the supported methods + // and if doesn't exist then we build a custom class for it + const method = rawMethod.toUpperCase() + const methods = [ + 'GET', + 'POST', + 'HEAD', + 'DELETE', + 'PATCH', + 'PUT', + 'OPTIONS', + 'COPY', + 'LOCK', + 'UNLOCK', + 'MOVE', + 'TRACE' + ] + + if (!methods.includes(method)) { + code.push(`# Faraday cannot currently run ${method} requests. Please use another client.`) + return code.join() + } + + code.push("require 'faraday'") + code.blank() + + // Write body to beginning of script + if (postData.mimeType === 'application/x-www-form-urlencoded') { + if (postData.params) { + code.push('data = {') + postData.params.forEach(param => { + code.push(` :${param.name} => ${JSON.stringify(param.value)},`) + }) + code.push('}') + code.blank() + } + } + + code.push('conn = Faraday.new(') + code.push(` url: '${uriObj.protocol}//${uriObj.host}',`) + if (allHeaders['content-type'] || allHeaders['Content-Type']) { + code.push(` headers: {'Content-Type' => '${allHeaders['content-type'] || allHeaders['Content-Type']}'}`) + } + code.push(')') + + code.blank() + code.push(`response = conn.${method.toLowerCase()}('${uriObj.pathname}') do |req|`) + + const headers = Object.keys(allHeaders) + if (headers.length) { + headers.forEach(key => { + if (key.toLowerCase() !== 'content-type') { + code.push(" req.headers['%qs'] = '%qs'", key, allHeaders[key]) + } + }) + } + + Object.keys(queryObj).forEach(name => { + const value = queryObj[name] + if (Array.isArray(value)) { + code.push(` req.params['%qs'] = ${JSON.stringify(value)}`, name) + } else { + code.push(" req.params['%qs'] = '%qs'", name, value) + } + }) + + switch (postData.mimeType) { + case 'application/x-www-form-urlencoded': + if (postData.params) { + code.push(' req.body = URI.encode_www_form(data)') + } + break + + case 'application/json': + if (postData.jsonObj) { + code.push(` req.body = ${JSON.stringify(postData.text)}`) + } + break + + default: + if (postData.text) { + code.push(` req.body = ${JSON.stringify(postData.text)}`) + } + } + + code.push('end') + code.blank() + code.push('puts response.status') + code.push('puts response.body') + + return code.join() +} + +module.exports.info = { + key: 'faraday', + title: 'faraday', + link: 'https://github.com/lostisland/faraday', + description: 'Faraday HTTP client' +} diff --git a/src/targets/ruby/index.js b/src/targets/ruby/index.js index 1118a1b..184399b 100644 --- a/src/targets/ruby/index.js +++ b/src/targets/ruby/index.js @@ -8,5 +8,6 @@ module.exports = { default: 'native' }, - native: require('./native') + native: require('./native'), + faraday: require('./faraday') } diff --git a/test/fixtures/available-targets.json b/test/fixtures/available-targets.json index 63d14fa..b8b2618 100644 --- a/test/fixtures/available-targets.json +++ b/test/fixtures/available-targets.json @@ -330,6 +330,12 @@ "title": "net::http", "link": "http://ruby-doc.org/stdlib-2.2.1/libdoc/net/http/rdoc/Net/HTTP.html", "description": "Ruby HTTP client" + }, + { + "key": "faraday", + "title": "faraday", + "link": "https://github.com/lostisland/faraday", + "description": "Faraday HTTP client" } ] }, diff --git a/test/fixtures/output/ruby/faraday/application-form-encoded.rb b/test/fixtures/output/ruby/faraday/application-form-encoded.rb new file mode 100644 index 0000000..9f15c8a --- /dev/null +++ b/test/fixtures/output/ruby/faraday/application-form-encoded.rb @@ -0,0 +1,18 @@ +require 'faraday' + +data = { + :foo => "bar", + :hello => "world", +} + +conn = Faraday.new( + url: 'http://mockbin.com', + headers: {'Content-Type' => 'application/x-www-form-urlencoded'} +) + +response = conn.post('/har') do |req| + req.body = URI.encode_www_form(data) +end + +puts response.status +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/ruby/faraday/application-json.rb b/test/fixtures/output/ruby/faraday/application-json.rb new file mode 100644 index 0000000..2c22a0e --- /dev/null +++ b/test/fixtures/output/ruby/faraday/application-json.rb @@ -0,0 +1,13 @@ +require 'faraday' + +conn = Faraday.new( + url: 'http://mockbin.com', + headers: {'Content-Type' => 'application/json'} +) + +response = conn.post('/har') do |req| + req.body = "{\"number\":1,\"string\":\"f\\\"oo\",\"arr\":[1,2,3],\"nested\":{\"a\":\"b\"},\"arr_mix\":[1,\"a\",{\"arr_mix_nested\":{}}],\"boolean\":false}" +end + +puts response.status +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/ruby/faraday/compression.rb b/test/fixtures/output/ruby/faraday/compression.rb new file mode 100644 index 0000000..4c0f30b --- /dev/null +++ b/test/fixtures/output/ruby/faraday/compression.rb @@ -0,0 +1,12 @@ +require 'faraday' + +conn = Faraday.new( + url: 'http://mockbin.com', +) + +response = conn.get('/har') do |req| + req.headers['accept-encoding'] = 'deflate, gzip, br' +end + +puts response.status +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/ruby/faraday/cookies.rb b/test/fixtures/output/ruby/faraday/cookies.rb new file mode 100644 index 0000000..5c884d7 --- /dev/null +++ b/test/fixtures/output/ruby/faraday/cookies.rb @@ -0,0 +1,12 @@ +require 'faraday' + +conn = Faraday.new( + url: 'http://mockbin.com', +) + +response = conn.post('/har') do |req| + req.headers['cookie'] = 'foo=bar; bar=baz' +end + +puts response.status +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/ruby/faraday/custom-method.rb b/test/fixtures/output/ruby/faraday/custom-method.rb new file mode 100644 index 0000000..213ada5 --- /dev/null +++ b/test/fixtures/output/ruby/faraday/custom-method.rb @@ -0,0 +1 @@ +# Faraday cannot currently run PROPFIND requests. Please use another client. \ No newline at end of file diff --git a/test/fixtures/output/ruby/faraday/full.rb b/test/fixtures/output/ruby/faraday/full.rb new file mode 100644 index 0000000..00cf3c6 --- /dev/null +++ b/test/fixtures/output/ruby/faraday/full.rb @@ -0,0 +1,22 @@ +require 'faraday' + +data = { + :foo => "bar", +} + +conn = Faraday.new( + url: 'http://mockbin.com', + headers: {'Content-Type' => 'application/x-www-form-urlencoded'} +) + +response = conn.post('/har') do |req| + req.headers['cookie'] = 'foo=bar; bar=baz' + req.headers['accept'] = 'application/json' + req.params['foo'] = ["bar","baz"] + req.params['baz'] = 'abc' + req.params['key'] = 'value' + req.body = URI.encode_www_form(data) +end + +puts response.status +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/ruby/faraday/headers.rb b/test/fixtures/output/ruby/faraday/headers.rb new file mode 100644 index 0000000..efaaa37 --- /dev/null +++ b/test/fixtures/output/ruby/faraday/headers.rb @@ -0,0 +1,14 @@ +require 'faraday' + +conn = Faraday.new( + url: 'http://mockbin.com', +) + +response = conn.get('/har') do |req| + req.headers['accept'] = 'application/json' + req.headers['x-foo'] = 'Bar' + req.headers['quoted-value'] = '"quoted" \'string\'' +end + +puts response.status +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/ruby/faraday/https.rb b/test/fixtures/output/ruby/faraday/https.rb new file mode 100644 index 0000000..8416136 --- /dev/null +++ b/test/fixtures/output/ruby/faraday/https.rb @@ -0,0 +1,11 @@ +require 'faraday' + +conn = Faraday.new( + url: 'https://mockbin.com', +) + +response = conn.get('/har') do |req| +end + +puts response.status +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/ruby/faraday/jsonObj-multiline.rb b/test/fixtures/output/ruby/faraday/jsonObj-multiline.rb new file mode 100644 index 0000000..e6e66b0 --- /dev/null +++ b/test/fixtures/output/ruby/faraday/jsonObj-multiline.rb @@ -0,0 +1,13 @@ +require 'faraday' + +conn = Faraday.new( + url: 'http://mockbin.com', + headers: {'Content-Type' => 'application/json'} +) + +response = conn.post('/har') do |req| + req.body = "{\n \"foo\": \"bar\"\n}" +end + +puts response.status +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/ruby/faraday/jsonObj-null-value.rb b/test/fixtures/output/ruby/faraday/jsonObj-null-value.rb new file mode 100644 index 0000000..d2ecc57 --- /dev/null +++ b/test/fixtures/output/ruby/faraday/jsonObj-null-value.rb @@ -0,0 +1,13 @@ +require 'faraday' + +conn = Faraday.new( + url: 'http://mockbin.com', + headers: {'Content-Type' => 'application/json'} +) + +response = conn.post('/har') do |req| + req.body = "{\"foo\":null}" +end + +puts response.status +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/ruby/faraday/malicious.rb b/test/fixtures/output/ruby/faraday/malicious.rb new file mode 100644 index 0000000..a5423a2 --- /dev/null +++ b/test/fixtures/output/ruby/faraday/malicious.rb @@ -0,0 +1,50 @@ +require 'faraday' + +conn = Faraday.new( + url: 'http://example.test', +) + +response = conn.post('/%27%22%60$(%(%%7B%7B%7B/0%s//') do |req| + req.headers['\''] = 'squote-key-test' + req.headers['squote-value-test'] = '\'' + req.headers['dquote-value-test'] = '"' + req.headers['`'] = 'backtick-key-test' + req.headers['backtick-value-test'] = '`' + req.headers['$'] = 'dollar-key-test' + req.headers['dollar-parenthesis-value-test'] = '$(' + req.headers['#'] = 'hash-key-test' + req.headers['hash-brace-value-test'] = '#{' + req.headers['%'] = 'percent-key-test' + req.headers['percent-parenthesis-value-test'] = '%(' + req.headers['percent-brace-value-test'] = '%{' + req.headers['double-brace-value-test'] = '{{' + req.headers['null-value-test'] = '\\0' + req.headers['string-fmt-value-test'] = '%s' + req.headers['slash-value-test'] = '\\' + req.params['\''] = 'squote-key-test' + req.params['squote-value-test'] = '\'' + req.params['"'] = 'dquote-key-test' + req.params['dquote-value-test'] = '"' + req.params['`'] = 'backtick-key-test' + req.params['backtick-value-test'] = '`' + req.params['$('] = 'dollar-parenthesis-key-test' + req.params['dollar-parenthesis-value-test'] = '$(' + req.params['#{'] = 'hash-brace-key-test' + req.params['hash-brace-value-test'] = '#{' + req.params['%('] = 'percent-parenthesis-key-test' + req.params['percent-parenthesis-value-test'] = '%(' + req.params['%{'] = 'percent-brace-key-test' + req.params['percent-brace-value-test'] = '%{' + req.params['{{'] = 'double-brace-key-test' + req.params['double-brace-value-test'] = '{{' + req.params['\\0'] = 'null-key-test' + req.params['null-value-test'] = '\\0' + req.params['%s'] = 'string-fmt-key-test' + req.params['string-fmt-value-test'] = '%s' + req.params['\\'] = 'slash-key-test' + req.params['slash-value-test'] = '\\' + req.body = "' \" ` $( #{ %( %{ {{ \\0 %s \\" +end + +puts response.status +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/ruby/faraday/multipart-data.rb b/test/fixtures/output/ruby/faraday/multipart-data.rb new file mode 100644 index 0000000..225c6f6 --- /dev/null +++ b/test/fixtures/output/ruby/faraday/multipart-data.rb @@ -0,0 +1,13 @@ +require 'faraday' + +conn = Faraday.new( + url: 'http://mockbin.com', + headers: {'Content-Type' => 'multipart/form-data; boundary=---011000010111000001101001'} +) + +response = conn.post('/har') do |req| + req.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"; filename=\"hello.txt\"\r\nContent-Type: text/plain\r\n\r\nHello World\r\n-----011000010111000001101001--\r\n" +end + +puts response.status +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/ruby/faraday/multipart-file.rb b/test/fixtures/output/ruby/faraday/multipart-file.rb new file mode 100644 index 0000000..4d71689 --- /dev/null +++ b/test/fixtures/output/ruby/faraday/multipart-file.rb @@ -0,0 +1,13 @@ +require 'faraday' + +conn = Faraday.new( + url: 'http://mockbin.com', + headers: {'Content-Type' => 'multipart/form-data; boundary=---011000010111000001101001'} +) + +response = conn.post('/har') do |req| + req.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"; filename=\"hello.txt\"\r\nContent-Type: text/plain\r\n\r\n\r\n-----011000010111000001101001--\r\n" +end + +puts response.status +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/ruby/faraday/multipart-form-data.rb b/test/fixtures/output/ruby/faraday/multipart-form-data.rb new file mode 100644 index 0000000..fe3e144 --- /dev/null +++ b/test/fixtures/output/ruby/faraday/multipart-form-data.rb @@ -0,0 +1,13 @@ +require 'faraday' + +conn = Faraday.new( + url: 'http://mockbin.com', + headers: {'Content-Type' => 'multipart/form-data; boundary=---011000010111000001101001'} +) + +response = conn.post('/har') do |req| + req.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"foo\"\r\n\r\nbar\r\n-----011000010111000001101001--\r\n" +end + +puts response.status +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/ruby/faraday/nested.rb b/test/fixtures/output/ruby/faraday/nested.rb new file mode 100644 index 0000000..1a6966d --- /dev/null +++ b/test/fixtures/output/ruby/faraday/nested.rb @@ -0,0 +1,14 @@ +require 'faraday' + +conn = Faraday.new( + url: 'http://mockbin.com', +) + +response = conn.get('/har') do |req| + req.params['foo[bar]'] = 'baz,zap' + req.params['fiz'] = 'buz' + req.params['key'] = 'value' +end + +puts response.status +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/ruby/faraday/query.rb b/test/fixtures/output/ruby/faraday/query.rb new file mode 100644 index 0000000..c418c55 --- /dev/null +++ b/test/fixtures/output/ruby/faraday/query.rb @@ -0,0 +1,14 @@ +require 'faraday' + +conn = Faraday.new( + url: 'http://mockbin.com', +) + +response = conn.get('/har') do |req| + req.params['foo'] = ["bar","baz"] + req.params['baz'] = 'abc' + req.params['key'] = 'value' +end + +puts response.status +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/ruby/faraday/short.rb b/test/fixtures/output/ruby/faraday/short.rb new file mode 100644 index 0000000..8ce34f7 --- /dev/null +++ b/test/fixtures/output/ruby/faraday/short.rb @@ -0,0 +1,11 @@ +require 'faraday' + +conn = Faraday.new( + url: 'http://mockbin.com', +) + +response = conn.get('/har') do |req| +end + +puts response.status +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/ruby/faraday/text-plain.rb b/test/fixtures/output/ruby/faraday/text-plain.rb new file mode 100644 index 0000000..b253cc3 --- /dev/null +++ b/test/fixtures/output/ruby/faraday/text-plain.rb @@ -0,0 +1,13 @@ +require 'faraday' + +conn = Faraday.new( + url: 'http://mockbin.com', + headers: {'Content-Type' => 'text/plain'} +) + +response = conn.post('/har') do |req| + req.body = "Hello World" +end + +puts response.status +puts response.body \ No newline at end of file diff --git a/test/fixtures/output/ruby/faraday/unparseable-query.rb b/test/fixtures/output/ruby/faraday/unparseable-query.rb new file mode 100644 index 0000000..8ce34f7 --- /dev/null +++ b/test/fixtures/output/ruby/faraday/unparseable-query.rb @@ -0,0 +1,11 @@ +require 'faraday' + +conn = Faraday.new( + url: 'http://mockbin.com', +) + +response = conn.get('/har') do |req| +end + +puts response.status +puts response.body \ No newline at end of file diff --git a/test/targets/ruby/faraday.js b/test/targets/ruby/faraday.js new file mode 100644 index 0000000..b77cc77 --- /dev/null +++ b/test/targets/ruby/faraday.js @@ -0,0 +1,3 @@ +'use strict' + +module.exports = function (snippet, fixtures) {} From 95245aa19a3062b885bc3ea4cbc2c1242a7b2693 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Wed, 12 Nov 2025 14:54:38 +0100 Subject: [PATCH 28/36] Add update steps comment to target list test --- test/targets.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/targets.js b/test/targets.js index 58d77e3..0e4cf6c 100644 --- a/test/targets.js +++ b/test/targets.js @@ -92,6 +92,9 @@ describe('Available Targets', function () { fixtures['available-targets'].should.containEql(target) }) }) + + // Update with: + // node -e "console.log(JSON.stringify(require('.').availableTargets(), null, 2))" > ./test/fixtures/available-targets.json }) describe('Custom targets', function () { From daf56a27e790013010cc18db9613dbb1bc193abd Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Wed, 12 Nov 2025 16:13:42 +0100 Subject: [PATCH 29/36] 3.0.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 24c7d4b..517f45a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@httptoolkit/httpsnippet", - "version": "2.2.0", + "version": "3.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@httptoolkit/httpsnippet", - "version": "2.2.0", + "version": "3.0.0", "license": "MIT", "dependencies": { "chalk": "^1.1.1", diff --git a/package.json b/package.json index 2c31308..b912597 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "2.2.0", + "version": "3.0.0", "name": "@httptoolkit/httpsnippet", "description": "HTTP request snippet generator for *most* languages", "author": "Tim Perry ", From d41184ca742926e680b0489c5eecf1a9fc5d92be Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Nov 2025 19:26:05 +0000 Subject: [PATCH 30/36] chore(deps): bump nanoid in the npm_and_yarn group across 1 directory Bumps the npm_and_yarn group with 1 update in the / directory: [nanoid](https://github.com/ai/nanoid). Removes `nanoid` --- updated-dependencies: - dependency-name: nanoid dependency-version: dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] --- package-lock.json | 2023 ++++++++++++++++++++++++--------------------- package.json | 2 +- 2 files changed, 1098 insertions(+), 927 deletions(-) diff --git a/package-lock.json b/package-lock.json index 517f45a..9a9cd1a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,13 +25,13 @@ "echint": "^4.0.2", "glob": "^6.0.1", "istanbul": "^0.4.0", - "mocha": "^8.2.1", + "mocha": "^11.7.5", "require-directory": "^2.1.1", "should": "^13.2.3", "standard": "^16.0.3" }, "engines": { - "node": ">=10" + "node": ">=22" } }, "node_modules/@babel/code-frame": { @@ -163,18 +163,118 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, - "node_modules/@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", - "dev": true - }, "node_modules/abbrev": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", @@ -252,19 +352,6 @@ "node": ">=0.10.0" } }, - "node_modules/anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -348,15 +435,6 @@ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -367,18 +445,6 @@ "concat-map": "0.0.1" } }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", @@ -419,15 +485,6 @@ "node": ">=6" } }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", @@ -444,70 +501,53 @@ } }, "node_modules/chokidar": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", - "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "dev": true, "dependencies": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.5.0" + "readdirp": "^4.0.1" }, "engines": { - "node": ">= 8.10.0" + "node": ">= 14.16.0" }, - "optionalDependencies": { - "fsevents": "~2.1.2" + "funding": { + "url": "https://paulmillr.com/funding/" } }, "node_modules/cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "dependencies": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "node_modules/cliui/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true, + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, "engines": { - "node": ">=6" + "node": ">=12" } }, - "node_modules/cliui/node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, "engines": { - "node": ">=6" + "node": ">=8" } }, "node_modules/cliui/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { - "ansi-regex": "^4.1.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=6" + "node": ">=8" } }, "node_modules/color-convert": { @@ -546,9 +586,9 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "dependencies": { "path-key": "^3.1.0", @@ -591,15 +631,6 @@ "node": ">=0.10.0" } }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -636,9 +667,9 @@ } }, "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", "dev": true, "engines": { "node": ">=0.3.1" @@ -683,6 +714,12 @@ "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=" }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, "node_modules/echint": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/echint/-/echint-4.0.2.tgz", @@ -959,6 +996,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -1681,18 +1727,6 @@ "node": ">=4" } }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/find-root": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", @@ -1740,6 +1774,22 @@ "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", "dev": true }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/form-data": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.4.tgz", @@ -1808,21 +1858,6 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "node_modules/fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "deprecated": "\"Please update to latest v2.3 or v2.2\"", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -1952,15 +1987,6 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" }, - "node_modules/growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true, - "engines": { - "node": ">=4.x" - } - }, "node_modules/handlebars": { "version": "4.7.7", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", @@ -2177,18 +2203,6 @@ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/is-callable": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", @@ -2264,13 +2278,13 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, "engines": { - "node": ">=0.12.0" + "node": ">=8" } }, "node_modules/is-plain-obj": { @@ -2321,6 +2335,18 @@ "node": ">= 0.4" } }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -2393,6 +2419,21 @@ "node": ">=0.8.0" } }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -2547,15 +2588,19 @@ "dev": true }, "node_modules/log-symbols": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", - "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "dev": true, "dependencies": { - "chalk": "^4.0.0" + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/log-symbols/node_modules/ansi-styles": { @@ -2574,9 +2619,9 @@ } }, "node_modules/log-symbols/node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { "ansi-styles": "^4.1.0", @@ -2700,6 +2745,15 @@ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", @@ -2730,57 +2784,63 @@ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, "node_modules/mocha": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.2.1.tgz", - "integrity": "sha512-cuLBVfyFfFqbNR0uUKbDGXKGk+UDFe6aR4os78XIrMQpZl/nv7JYHcvP5MFIAb374b2zFXsdgEGwmzMtP0Xg8w==", - "dev": true, - "dependencies": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.4.3", - "debug": "4.2.0", - "diff": "4.0.2", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.1.6", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "3.14.0", - "log-symbols": "4.0.0", - "minimatch": "3.0.4", - "ms": "2.1.2", - "nanoid": "3.1.12", - "serialize-javascript": "5.0.1", - "strip-json-comments": "3.1.1", - "supports-color": "7.2.0", - "which": "2.0.2", - "wide-align": "1.1.3", - "workerpool": "6.0.2", - "yargs": "13.3.2", - "yargs-parser": "13.1.2", - "yargs-unparser": "2.0.0" + "version": "11.7.5", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.5.tgz", + "integrity": "sha512-mTT6RgopEYABzXWFx+GcJ+ZQ32kp4fMf0xvpZIIfSq9Z8lC/++MtcCnQ9t5FP2veYEP95FIYSvW+U9fV4xrlig==", + "dev": true, + "dependencies": { + "browser-stdout": "^1.3.1", + "chokidar": "^4.0.1", + "debug": "^4.3.5", + "diff": "^7.0.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^10.4.5", + "he": "^1.2.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^9.0.5", + "ms": "^2.1.3", + "picocolors": "^1.1.1", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^9.2.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1", + "yargs-unparser": "^2.0.0" }, "bin": { "_mocha": "bin/_mocha", - "mocha": "bin/mocha" + "mocha": "bin/mocha.js" }, "engines": { - "node": ">= 10.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/mocha/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/mocha/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" } }, "node_modules/mocha/node_modules/debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -2803,19 +2863,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mocha/node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/mocha/node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -2833,20 +2880,20 @@ } }, "node_modules/mocha/node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, - "engines": { - "node": "*" + "bin": { + "glob": "dist/esm/bin.mjs" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -2862,13 +2909,12 @@ } }, "node_modules/mocha/node_modules/js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", - "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" @@ -2889,10 +2935,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/mocha/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/mocha/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, "node_modules/mocha/node_modules/p-limit": { @@ -2947,30 +3008,18 @@ } }, "node_modules/mocha/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "dependencies": { "has-flag": "^4.0.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "node": ">=10" }, - "engines": { - "node": ">= 8" + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, "node_modules/ms": { @@ -2978,18 +3027,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, - "node_modules/nanoid": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.12.tgz", - "integrity": "sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || >=13.7" - } - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -3048,15 +3085,6 @@ "semver": "bin/semver" } }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -3185,6 +3213,12 @@ "node": ">=4" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -3242,6 +3276,28 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, "node_modules/path-type": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", @@ -3262,17 +3318,11 @@ "through": "~2.3" } }, - "node_modules/picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true }, "node_modules/pify": { "version": "2.3.0", @@ -3539,15 +3589,16 @@ } }, "node_modules/readdirp": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", - "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, "engines": { - "node": ">=8.10.0" + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/regexp.prototype.flags": { @@ -3587,12 +3638,6 @@ "node": ">=0.10.0" } }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, "node_modules/resolve": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", @@ -3641,10 +3686,24 @@ } }, "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, "node_modules/semver": { "version": "7.3.4", @@ -3680,20 +3739,14 @@ "dev": true }, "node_modules/serialize-javascript": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", - "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, "dependencies": { "randombytes": "^2.1.0" } }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -3798,6 +3851,18 @@ "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", "dev": true }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/slice-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", @@ -3966,37 +4031,104 @@ } }, "node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=4" + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, "node_modules/string-width/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/string-width/node_modules/is-fullwidth-code-point": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/string-width/node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/string.prototype.matchall": { @@ -4028,6 +4160,28 @@ "node": ">=0.10.0" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -4115,18 +4269,6 @@ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, "node_modules/tsconfig-paths": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", @@ -4223,21 +4365,6 @@ "which": "bin/which" } }, - "node_modules/which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "node_modules/wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dev": true, - "dependencies": { - "string-width": "^1.0.2 || 2" - } - }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -4254,114 +4381,199 @@ "dev": true }, "node_modules/workerpool": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.2.tgz", - "integrity": "sha512-DSNyvOpFKrNusaaUwk+ej6cBj1bmhLcBfj80elGk+ZIo5JSkq+unB1dLKEOcNfJDZgjGICfhQ0Q5TbP0PvF4+Q==", + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.4.tgz", + "integrity": "sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==", "dev": true }, "node_modules/wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "dependencies": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=6" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "ansi-regex": "^4.1.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">=6" + "node": ">=7.0.0" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "node_modules/wrap-ansi-cjs/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { - "mkdirp": "^0.5.1" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "engines": { "node": ">=8" } }, - "node_modules/xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=0.4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/y18n": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", - "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "dependencies": { + "mkdirp": "^0.5.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", @@ -4369,31 +4581,30 @@ "dev": true }, "node_modules/yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "dependencies": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" } }, "node_modules/yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" + "engines": { + "node": ">=12" } }, "node_modules/yargs-unparser": { @@ -4435,102 +4646,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/yargs/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yargs/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -4649,18 +4764,84 @@ } } }, + "@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "requires": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true + }, + "ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "requires": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + } + } + } + }, + "@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true + }, "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, - "@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", - "dev": true - }, "abbrev": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", @@ -4714,16 +4895,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" }, - "anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -4786,12 +4957,6 @@ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true - }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -4802,15 +4967,6 @@ "concat-map": "0.0.1" } }, - "braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "requires": { - "fill-range": "^7.1.1" - } - }, "browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", @@ -4842,12 +4998,6 @@ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", @@ -4861,56 +5011,38 @@ } }, "chokidar": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", - "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "dev": true, "requires": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "fsevents": "~2.1.2", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.5.0" + "readdirp": "^4.0.1" } }, "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" }, "dependencies": { "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^4.1.0" + "ansi-regex": "^5.0.1" } } } @@ -4948,9 +5080,9 @@ "dev": true }, "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "requires": { "path-key": "^3.1.0", @@ -4983,12 +5115,6 @@ "integrity": "sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8=", "dev": true }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, "deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -5016,9 +5142,9 @@ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", "dev": true }, "doctrine": { @@ -5051,6 +5177,12 @@ "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=" }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, "echint": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/echint/-/echint-4.0.2.tgz", @@ -5263,6 +5395,12 @@ "is-symbol": "^1.0.2" } }, + "escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -5786,15 +5924,6 @@ "flat-cache": "^2.0.1" } }, - "fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, "find-root": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", @@ -5833,6 +5962,16 @@ "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", "dev": true }, + "foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + } + }, "form-data": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.4.tgz", @@ -5893,13 +6032,6 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "dev": true, - "optional": true - }, "function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -5990,12 +6122,6 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true - }, "handlebars": { "version": "4.7.7", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", @@ -6154,15 +6280,6 @@ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, "is-callable": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", @@ -6211,10 +6328,10 @@ "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", "dev": true }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true }, "is-plain-obj": { @@ -6247,6 +6364,12 @@ "has-symbols": "^1.0.0" } }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -6311,6 +6434,16 @@ } } }, + "jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "requires": { + "@isaacs/cliui": "^8.0.2", + "@pkgjs/parseargs": "^0.11.0" + } + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -6435,12 +6568,13 @@ "dev": true }, "log-symbols": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", - "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "dev": true, "requires": { - "chalk": "^4.0.0" + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" }, "dependencies": { "ansi-styles": { @@ -6453,9 +6587,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -6551,6 +6685,12 @@ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, + "minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true + }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", @@ -6573,45 +6713,56 @@ "requires": {} }, "mocha": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.2.1.tgz", - "integrity": "sha512-cuLBVfyFfFqbNR0uUKbDGXKGk+UDFe6aR4os78XIrMQpZl/nv7JYHcvP5MFIAb374b2zFXsdgEGwmzMtP0Xg8w==", - "dev": true, - "requires": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.4.3", - "debug": "4.2.0", - "diff": "4.0.2", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.1.6", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "3.14.0", - "log-symbols": "4.0.0", - "minimatch": "3.0.4", - "ms": "2.1.2", - "nanoid": "3.1.12", - "serialize-javascript": "5.0.1", - "strip-json-comments": "3.1.1", - "supports-color": "7.2.0", - "which": "2.0.2", - "wide-align": "1.1.3", - "workerpool": "6.0.2", - "yargs": "13.3.2", - "yargs-parser": "13.1.2", - "yargs-unparser": "2.0.0" - }, - "dependencies": { + "version": "11.7.5", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.5.tgz", + "integrity": "sha512-mTT6RgopEYABzXWFx+GcJ+ZQ32kp4fMf0xvpZIIfSq9Z8lC/++MtcCnQ9t5FP2veYEP95FIYSvW+U9fV4xrlig==", + "dev": true, + "requires": { + "browser-stdout": "^1.3.1", + "chokidar": "^4.0.1", + "debug": "^4.3.5", + "diff": "^7.0.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^10.4.5", + "he": "^1.2.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^9.0.5", + "ms": "^2.1.3", + "picocolors": "^1.1.1", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^9.2.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1", + "yargs-unparser": "^2.0.0" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, "debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, "requires": { - "ms": "2.1.2" + "ms": "^2.1.3" } }, "escape-string-regexp": { @@ -6620,12 +6771,6 @@ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, "find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -6637,17 +6782,17 @@ } }, "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" } }, "has-flag": { @@ -6657,13 +6802,12 @@ "dev": true }, "js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", - "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" } }, "locate-path": { @@ -6675,10 +6819,19 @@ "p-locate": "^5.0.0" } }, + "minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, "p-limit": { @@ -6712,22 +6865,13 @@ "dev": true }, "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "requires": { "has-flag": "^4.0.0" } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } } } }, @@ -6736,12 +6880,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, - "nanoid": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.12.tgz", - "integrity": "sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A==", - "dev": true - }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -6793,12 +6931,6 @@ } } }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -6894,6 +7026,12 @@ "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", "dev": true }, + "package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -6936,6 +7074,24 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "requires": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + } + } + }, "path-type": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", @@ -6953,10 +7109,10 @@ "through": "~2.3" } }, - "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true }, "pify": { @@ -7163,13 +7319,10 @@ } }, "readdirp": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", - "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true }, "regexp.prototype.flags": { "version": "1.3.1", @@ -7193,12 +7346,6 @@ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, "resolve": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", @@ -7237,9 +7384,9 @@ } }, "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true }, "semver": { @@ -7269,20 +7416,14 @@ } }, "serialize-javascript": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", - "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, "requires": { "randombytes": "^2.1.0" } }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -7377,6 +7518,12 @@ "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", "dev": true }, + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true + }, "slice-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", @@ -7500,28 +7647,81 @@ } }, "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "dependencies": { "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^5.0.1" + } + } + } + }, + "string-width-cjs": { + "version": "npm:string-width@4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" } } } @@ -7549,6 +7749,23 @@ "ansi-regex": "^2.0.0" } }, + "strip-ansi-cjs": { + "version": "npm:strip-ansi@6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + } + } + }, "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -7617,15 +7834,6 @@ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, "tsconfig-paths": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", @@ -7706,21 +7914,6 @@ "isexe": "^2.0.0" } }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dev": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -7734,55 +7927,111 @@ "dev": true }, "workerpool": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.2.tgz", - "integrity": "sha512-DSNyvOpFKrNusaaUwk+ej6cBj1bmhLcBfj80elGk+ZIo5JSkq+unB1dLKEOcNfJDZgjGICfhQ0Q5TbP0PvF4+Q==", + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.4.tgz", + "integrity": "sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==", "dev": true }, "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "dependencies": { "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" } }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "color-name": "~1.1.4" } }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^4.1.0" + "ansi-regex": "^5.0.1" + } + } + } + }, + "wrap-ansi-cjs": { + "version": "npm:wrap-ansi@7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" } } } @@ -7815,9 +8064,9 @@ "dev": true }, "y18n": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", - "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true }, "yallist": { @@ -7827,103 +8076,25 @@ "dev": true }, "yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" } }, "yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true }, "yargs-unparser": { "version": "2.0.0", diff --git a/package.json b/package.json index b912597..0b4b693 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "echint": "^4.0.2", "glob": "^6.0.1", "istanbul": "^0.4.0", - "mocha": "^8.2.1", + "mocha": "^11.7.5", "require-directory": "^2.1.1", "should": "^13.2.3", "standard": "^16.0.3" From 4c98e9770124de5a1ad21f7402464f93524540a2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Nov 2025 17:34:26 +0000 Subject: [PATCH 31/36] chore(deps): bump js-yaml from 3.13.1 to 3.14.2 Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 3.13.1 to 3.14.2. - [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md) - [Commits](https://github.com/nodeca/js-yaml/compare/3.13.1...3.14.2) --- updated-dependencies: - dependency-name: js-yaml dependency-version: 3.14.2 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9a9cd1a..6341918 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2441,9 +2441,9 @@ "dev": true }, "node_modules/js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "dev": true, "dependencies": { "argparse": "^1.0.7", @@ -6451,9 +6451,9 @@ "dev": true }, "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "dev": true, "requires": { "argparse": "^1.0.7", From 732e0b05d4c4349d3beac3a97a107aa03477f716 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Fri, 19 Dec 2025 11:06:03 +0100 Subject: [PATCH 32/36] Improve handling of partially parseable query strings Previously we assumed that if qs.stringify didn't match the query string, then the queryString & queryObj properties would be empty, and so leaving the querystring in the URL (basically disabling structured generation of query = { a: b } style code and using raw URLs instead) would be safe. It turns out though that for partially parseable cases, we can get HARs with a URL containing a broken query string _and_ a valid queryString property with some values in it. We now actively ignore the latter, so the URL as always used as-is. --- src/index.js | 6 ++++-- test/fixtures/requests/unparseable-query.json | 9 +++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/index.js b/src/index.js index 2d093d4..4b03e29 100644 --- a/src/index.js +++ b/src/index.js @@ -242,9 +242,11 @@ HTTPSnippet.prototype.prepare = function (request) { request.uriObj.path = request.uriObj.pathname + '?' + request.uriObj.search } } else { - // We have no request.queryObj (so snippets won't send query params in a structured way) - // We keep the queryString in request.url (so it's sent raw everywhere) + // We keep the queryString in request.url (so it's sent raw everywhere) but disable it + // elsewhere, so it's omitted from automatic code generation cases. // request.fullUrl is recreated below (maybe mild fixed?) but preserves raw search etc + request.queryString = [] + request.queryObj = {} } // construct a full url diff --git a/test/fixtures/requests/unparseable-query.json b/test/fixtures/requests/unparseable-query.json index 2f2ae42..30875b6 100644 --- a/test/fixtures/requests/unparseable-query.json +++ b/test/fixtures/requests/unparseable-query.json @@ -1,6 +1,11 @@ { "method": "GET", "url": "http://mockbin.com/har?&&a=b&&", - "httpVersion": "HTTP/1.1", - "queryString": [] + "queryString": [ + { + "name": "a", + "value": "b" + } + ], + "httpVersion": "HTTP/1.1" } From e22c49da3ffed5284eb14b69c40d360f810da828 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Fri, 19 Dec 2025 11:14:15 +0100 Subject: [PATCH 33/36] 3.0.1 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6341918..b954569 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@httptoolkit/httpsnippet", - "version": "3.0.0", + "version": "3.0.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@httptoolkit/httpsnippet", - "version": "3.0.0", + "version": "3.0.1", "license": "MIT", "dependencies": { "chalk": "^1.1.1", diff --git a/package.json b/package.json index 0b4b693..7a9e5e6 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "3.0.0", + "version": "3.0.1", "name": "@httptoolkit/httpsnippet", "description": "HTTP request snippet generator for *most* languages", "author": "Tim Perry ", From 8018602f9e0589c8d5ef362fde3ec4d0b6972da9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 22 Jan 2026 02:47:01 +0000 Subject: [PATCH 34/36] chore(deps-dev): bump lodash from 4.17.21 to 4.17.23 Bumps [lodash](https://github.com/lodash/lodash) from 4.17.21 to 4.17.23. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.17.23) --- updated-dependencies: - dependency-name: lodash dependency-version: 4.17.23 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index b954569..1a54e9f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2582,9 +2582,9 @@ } }, "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", "dev": true }, "node_modules/log-symbols": { @@ -6562,9 +6562,9 @@ } }, "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", "dev": true }, "log-symbols": { From 97a59c1a5472140d62be383f832e3185d86158b2 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Thu, 5 Feb 2026 13:25:06 +0100 Subject: [PATCH 35/36] Tighten up raw header accuracy in HTTP/1.1 snippets --- src/index.js | 20 +++++++++++----- src/targets/http/http1.1.js | 24 ++++++++++++------- .../output/http/1.1/application-form-encoded | 2 +- .../fixtures/output/http/1.1/application-json | 2 +- test/fixtures/output/http/1.1/compression | 2 +- test/fixtures/output/http/1.1/full | 4 ++-- test/fixtures/output/http/1.1/headers | 6 ++--- .../output/http/1.1/jsonObj-multiline | 2 +- .../output/http/1.1/jsonObj-null-value | 2 +- test/fixtures/output/http/1.1/malicious | 22 ++++++++--------- test/fixtures/output/http/1.1/multipart-data | 2 +- test/fixtures/output/http/1.1/multipart-file | 2 +- test/fixtures/output/http/1.1/text-plain | 2 +- 13 files changed, 53 insertions(+), 39 deletions(-) diff --git a/src/index.js b/src/index.js index 4b03e29..0801c78 100644 --- a/src/index.js +++ b/src/index.js @@ -168,13 +168,21 @@ HTTPSnippet.prototype.prepare = function (request) { request.postData.boundary = boundary - // Since headers are case-sensitive we need to see if there's an existing `Content-Type` header that we can - // override. - const contentTypeHeader = helpers.hasHeader(request.headersObj, 'content-type') - ? helpers.getHeaderName(request.headersObj, 'content-type') - : 'content-type' + const multipartContentType = 'multipart/form-data; boundary=' + boundary - request.headersObj[contentTypeHeader] = 'multipart/form-data; boundary=' + boundary + // We need to update the various header states to match the CT to our boundary: + if (helpers.hasHeader(request.headersObj, 'content-type')) { + // Since headers are case-sensitive we need to see if there's an existing `Content-Type` + // header that we can override. + const contentTypeHeader = helpers.getHeaderName(request.headersObj, 'content-type') + request.headersObj[contentTypeHeader] = multipartContentType + + const headerEntry = request.headers.findLast(h => h.name.toLowerCase() === 'content-type') + headerEntry.value = multipartContentType + } else { + request.headersObj['Content-Type'] = multipartContentType + request.headers.push({ name: 'Content-Type', value: multipartContentType }) + } } break diff --git a/src/targets/http/http1.1.js b/src/targets/http/http1.1.js index 58b5918..4a391c2 100644 --- a/src/targets/http/http1.1.js +++ b/src/targets/http/http1.1.js @@ -43,21 +43,27 @@ module.exports = function (source, options) { code.push('%s %s %s', source.method, requestUrl, source.httpVersion) // RFC 7231 Section 5. Header Fields - Object.keys(source.allHeaders).forEach(function (key) { - // Capitalize header keys, even though it's not required by the spec. - const keyCapitalized = key.toLowerCase().replace(/(^|-)(\w)/g, function (x) { - return x.toUpperCase() - }) - + source.headers.forEach((header) => { code.push( '%s', - util.format('%s: %s', keyCapitalized, source.allHeaders[key]) + util.format('%s: %s', header.name, header.value) ) }) + // Unlike most other snippets, we use the fully raw input here (not headerObj/allHeaders) + // so we need to hook into the prepare() cookie injection logic: + if (source.allHeaders.cookie && !source.headers.find(h => h.name.toLowerCase() === 'cookie')) { + code.push( + '%s', + util.format('%s: %s', 'Cookie', source.allHeaders.cookie) + ) + } + + const headerKeys = Object.keys(source.allHeaders).map(k => k.toLowerCase()) + // RFC 7230 Section 5.4. Host // Automatically set Host header if option is on and on header already exists. - if (opts.autoHost && Object.keys(source.allHeaders).indexOf('host') === -1) { + if (opts.autoHost && headerKeys.indexOf('host') === -1) { code.push('Host: %s', source.uriObj.host) } @@ -66,7 +72,7 @@ module.exports = function (source, options) { if ( opts.autoContentLength && source.postData.text && - Object.keys(source.allHeaders).indexOf('content-length') === -1 + headerKeys.indexOf('conteTnt-length') === -1 ) { code.push( 'Content-Length: %d', diff --git a/test/fixtures/output/http/1.1/application-form-encoded b/test/fixtures/output/http/1.1/application-form-encoded index 723d94a..a979905 100644 --- a/test/fixtures/output/http/1.1/application-form-encoded +++ b/test/fixtures/output/http/1.1/application-form-encoded @@ -1,5 +1,5 @@ POST /har HTTP/1.1 -Content-Type: application/x-www-form-urlencoded +content-type: application/x-www-form-urlencoded Host: mockbin.com Content-Length: 19 diff --git a/test/fixtures/output/http/1.1/application-json b/test/fixtures/output/http/1.1/application-json index ee65b54..ac5f1b3 100644 --- a/test/fixtures/output/http/1.1/application-json +++ b/test/fixtures/output/http/1.1/application-json @@ -1,5 +1,5 @@ POST /har HTTP/1.1 -Content-Type: application/json +content-type: application/json Host: mockbin.com Content-Length: 118 diff --git a/test/fixtures/output/http/1.1/compression b/test/fixtures/output/http/1.1/compression index 8e2f8b1..9a99d1b 100644 --- a/test/fixtures/output/http/1.1/compression +++ b/test/fixtures/output/http/1.1/compression @@ -1,3 +1,3 @@ GET /har HTTP/1.1 -Accept-Encoding: deflate, gzip, br +accept-encoding: deflate, gzip, br Host: mockbin.com \ No newline at end of file diff --git a/test/fixtures/output/http/1.1/full b/test/fixtures/output/http/1.1/full index d4d41ec..530af73 100644 --- a/test/fixtures/output/http/1.1/full +++ b/test/fixtures/output/http/1.1/full @@ -1,7 +1,7 @@ POST /har?foo=bar&foo=baz&baz=abc&key=value HTTP/1.1 +accept: application/json +content-type: application/x-www-form-urlencoded Cookie: foo=bar; bar=baz -Accept: application/json -Content-Type: application/x-www-form-urlencoded Host: mockbin.com Content-Length: 7 diff --git a/test/fixtures/output/http/1.1/headers b/test/fixtures/output/http/1.1/headers index ad12eff..171dbda 100644 --- a/test/fixtures/output/http/1.1/headers +++ b/test/fixtures/output/http/1.1/headers @@ -1,7 +1,7 @@ GET /har HTTP/1.1 -Accept: application/json -X-Foo: Bar -Quoted-Value: "quoted" 'string' +accept: application/json +x-foo: Bar +quoted-value: "quoted" 'string' Host: mockbin.com diff --git a/test/fixtures/output/http/1.1/jsonObj-multiline b/test/fixtures/output/http/1.1/jsonObj-multiline index ebc26ad..9c19277 100644 --- a/test/fixtures/output/http/1.1/jsonObj-multiline +++ b/test/fixtures/output/http/1.1/jsonObj-multiline @@ -1,5 +1,5 @@ POST /har HTTP/1.1 -Content-Type: application/json +content-type: application/json Host: mockbin.com Content-Length: 18 diff --git a/test/fixtures/output/http/1.1/jsonObj-null-value b/test/fixtures/output/http/1.1/jsonObj-null-value index 240a57b..e4c7e14 100644 --- a/test/fixtures/output/http/1.1/jsonObj-null-value +++ b/test/fixtures/output/http/1.1/jsonObj-null-value @@ -1,5 +1,5 @@ POST /har HTTP/1.1 -Content-Type: application/json +content-type: application/json Host: mockbin.com Content-Length: 12 diff --git a/test/fixtures/output/http/1.1/malicious b/test/fixtures/output/http/1.1/malicious index 107f1af..8f7cbe3 100644 --- a/test/fixtures/output/http/1.1/malicious +++ b/test/fixtures/output/http/1.1/malicious @@ -1,20 +1,20 @@ POST /%27%22%60$(%(%%7B%7B%7B/0%s//?'=squote-key-test&squote-value-test='&%22=dquote-key-test&dquote-value-test=%22&%60=backtick-key-test&backtick-value-test=%60&%24(=dollar-parenthesis-key-test&dollar-parenthesis-value-test=%24(&%23%7B=hash-brace-key-test&hash-brace-value-test=%23%7B&%25(=percent-parenthesis-key-test&percent-parenthesis-value-test=%25(&%25%7B=percent-brace-key-test&percent-brace-value-test=%25%7B&%7B%7B=double-brace-key-test&double-brace-value-test=%7B%7B&%5C0=null-key-test&null-value-test=%5C0&%25s=string-fmt-key-test&string-fmt-value-test=%25s&%5C=slash-key-test&slash-value-test=%5C HTTP/1.1 ': squote-key-test -Squote-Value-Test: ' -Dquote-Value-Test: " +squote-value-test: ' +dquote-value-test: " `: backtick-key-test -Backtick-Value-Test: ` +backtick-value-test: ` $: dollar-key-test -Dollar-Parenthesis-Value-Test: $( +dollar-parenthesis-value-test: $( #: hash-key-test -Hash-Brace-Value-Test: #{ +hash-brace-value-test: #{ %: percent-key-test -Percent-Parenthesis-Value-Test: %( -Percent-Brace-Value-Test: %{ -Double-Brace-Value-Test: {{ -Null-Value-Test: \0 -String-Fmt-Value-Test: %s -Slash-Value-Test: \ +percent-parenthesis-value-test: %( +percent-brace-value-test: %{ +double-brace-value-test: {{ +null-value-test: \0 +string-fmt-value-test: %s +slash-value-test: \ Host: example.test Content-Length: 28 diff --git a/test/fixtures/output/http/1.1/multipart-data b/test/fixtures/output/http/1.1/multipart-data index cbe1c5f..d0306c7 100644 --- a/test/fixtures/output/http/1.1/multipart-data +++ b/test/fixtures/output/http/1.1/multipart-data @@ -1,5 +1,5 @@ POST /har HTTP/1.1 -Content-Type: multipart/form-data; boundary=---011000010111000001101001 +content-type: multipart/form-data; boundary=---011000010111000001101001 Host: mockbin.com Content-Length: 171 diff --git a/test/fixtures/output/http/1.1/multipart-file b/test/fixtures/output/http/1.1/multipart-file index be0776f..0f8d0e0 100644 --- a/test/fixtures/output/http/1.1/multipart-file +++ b/test/fixtures/output/http/1.1/multipart-file @@ -1,5 +1,5 @@ POST /har HTTP/1.1 -Content-Type: multipart/form-data; boundary=---011000010111000001101001 +content-type: multipart/form-data; boundary=---011000010111000001101001 Host: mockbin.com Content-Length: 160 diff --git a/test/fixtures/output/http/1.1/text-plain b/test/fixtures/output/http/1.1/text-plain index c341a43..6ba9edf 100644 --- a/test/fixtures/output/http/1.1/text-plain +++ b/test/fixtures/output/http/1.1/text-plain @@ -1,5 +1,5 @@ POST /har HTTP/1.1 -Content-Type: text/plain +content-type: text/plain Host: mockbin.com Content-Length: 11 From 1b174a8749f62599ad1deb0e472a138999570646 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Thu, 5 Feb 2026 13:26:56 +0100 Subject: [PATCH 36/36] 3.0.2 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1a54e9f..69e2307 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@httptoolkit/httpsnippet", - "version": "3.0.1", + "version": "3.0.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@httptoolkit/httpsnippet", - "version": "3.0.1", + "version": "3.0.2", "license": "MIT", "dependencies": { "chalk": "^1.1.1", diff --git a/package.json b/package.json index 7a9e5e6..a9a9247 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "3.0.1", + "version": "3.0.2", "name": "@httptoolkit/httpsnippet", "description": "HTTP request snippet generator for *most* languages", "author": "Tim Perry ",