From 7e746c4cd05fa5d117fd3cc4dcfaac16a07e8789 Mon Sep 17 00:00:00 2001 From: Nathan Bailey Date: Fri, 3 Sep 2021 13:21:31 -0700 Subject: [PATCH 01/83] fix(curl) remove boundary form content-type header (#227) --- src/targets/shell/curl.js | 17 +++++++++++++++++ .../output/shell/curl/multipart-data.sh | 2 +- .../output/shell/curl/multipart-file.sh | 2 +- .../output/shell/curl/multipart-form-data.sh | 2 +- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/targets/shell/curl.js b/src/targets/shell/curl.js index f097f5a..3cde6bb 100644 --- a/src/targets/shell/curl.js +++ b/src/targets/shell/curl.js @@ -12,6 +12,7 @@ const util = require('util') const helpers = require('../../helpers/shell') +const headerHelpers = require('../../helpers/headers') const CodeBuilder = require('../../helpers/code-builder') module.exports = function (source, options) { @@ -39,6 +40,22 @@ module.exports = function (source, options) { code.push(opts.short ? '-0' : '--http1.0') } + // if multipart form data, we want to remove the boundary + if (source.postData.mimeType === 'multipart/form-data') { + const contentTypeHeaderName = headerHelpers.getHeaderName(source.headersObj, 'content-type') + const contentTypeHeader = source.headersObj[contentTypeHeaderName] + + if (contentTypeHeaderName && contentTypeHeader) { + // remove the leading semi colon and boundary + // up to the next semi colon or the end of string + const noBoundary = contentTypeHeader.replace(/; boundary.+?(?=(;|$))/, '') + + // replace the content-type header with no boundary in both headersObj and allHeaders + source.headersObj[contentTypeHeaderName] = noBoundary + source.allHeaders[contentTypeHeaderName] = noBoundary + } + } + // construct headers Object.keys(source.headersObj).sort().forEach(function (key) { const header = util.format('%s: %s', key, source.headersObj[key]) diff --git a/test/fixtures/output/shell/curl/multipart-data.sh b/test/fixtures/output/shell/curl/multipart-data.sh index 40a0201..216ae23 100644 --- a/test/fixtures/output/shell/curl/multipart-data.sh +++ b/test/fixtures/output/shell/curl/multipart-data.sh @@ -1,4 +1,4 @@ curl --request POST \ --url http://mockbin.com/har \ - --header 'content-type: multipart/form-data; boundary=---011000010111000001101001' \ + --header 'content-type: multipart/form-data' \ --form foo=@hello.txt diff --git a/test/fixtures/output/shell/curl/multipart-file.sh b/test/fixtures/output/shell/curl/multipart-file.sh index e054807..9f18a58 100644 --- a/test/fixtures/output/shell/curl/multipart-file.sh +++ b/test/fixtures/output/shell/curl/multipart-file.sh @@ -1,4 +1,4 @@ curl --request POST \ --url http://mockbin.com/har \ - --header 'content-type: multipart/form-data; boundary=---011000010111000001101001' \ + --header 'content-type: multipart/form-data' \ --form foo=@test/fixtures/files/hello.txt diff --git a/test/fixtures/output/shell/curl/multipart-form-data.sh b/test/fixtures/output/shell/curl/multipart-form-data.sh index def1f43..fd5d2d1 100644 --- a/test/fixtures/output/shell/curl/multipart-form-data.sh +++ b/test/fixtures/output/shell/curl/multipart-form-data.sh @@ -1,4 +1,4 @@ curl --request POST \ --url http://mockbin.com/har \ - --header 'Content-Type: multipart/form-data; boundary=---011000010111000001101001' \ + --header 'Content-Type: multipart/form-data' \ --form foo=bar From 9071fb58faaacfc9d898a72ba471cbec6774906e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Sep 2021 13:23:48 -0700 Subject: [PATCH 02/83] chore(deps): bump path-parse from 1.0.6 to 1.0.7 (#225) Bumps [path-parse](https://github.com/jbgutierrez/path-parse) from 1.0.6 to 1.0.7. - [Release notes](https://github.com/jbgutierrez/path-parse/releases) - [Commits](https://github.com/jbgutierrez/path-parse/commits/v1.0.7) --- updated-dependencies: - dependency-name: path-parse dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 66cd5cc..14f9046 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2571,9 +2571,9 @@ "dev": true }, "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, "path-type": { From b80accf62fbc299331e74ce7a9f9edc5e3a958e6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Sep 2021 13:24:28 -0700 Subject: [PATCH 03/83] chore(deps): bump glob-parent from 5.1.1 to 5.1.2 (#223) Bumps [glob-parent](https://github.com/gulpjs/glob-parent) from 5.1.1 to 5.1.2. - [Release notes](https://github.com/gulpjs/glob-parent/releases) - [Changelog](https://github.com/gulpjs/glob-parent/blob/main/CHANGELOG.md) - [Commits](https://github.com/gulpjs/glob-parent/compare/v5.1.1...v5.1.2) --- updated-dependencies: - dependency-name: glob-parent dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Eric Reynolds --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 14f9046..5e88e12 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1532,9 +1532,9 @@ } }, "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "requires": { "is-glob": "^4.0.1" From 1a0c61f4c880f935e75d3b9c2e8ec36b7e574aee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Sep 2021 13:25:26 -0700 Subject: [PATCH 04/83] chore(deps): bump handlebars from 4.7.6 to 4.7.7 (#214) Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.7.6 to 4.7.7. - [Release notes](https://github.com/wycats/handlebars.js/releases) - [Changelog](https://github.com/handlebars-lang/handlebars.js/blob/master/release-notes.md) - [Commits](https://github.com/wycats/handlebars.js/compare/v4.7.6...v4.7.7) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5e88e12..7cbd26a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1567,9 +1567,9 @@ "dev": true }, "handlebars": { - "version": "4.7.6", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz", - "integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==", + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", "dev": true, "requires": { "minimist": "^1.2.5", From 02ce296f48f92f3450cc9bd1ba299169e132abab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Sep 2021 13:25:42 -0700 Subject: [PATCH 05/83] chore(deps): bump lodash from 4.17.19 to 4.17.21 (#215) Bumps [lodash](https://github.com/lodash/lodash) from 4.17.19 to 4.17.21. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.17.19...4.17.21) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Eric Reynolds --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7cbd26a..b6f76a3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2067,9 +2067,9 @@ } }, "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", - "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, "log-symbols": { From d9d305251d8a993c360cb8a2d6684c2527228f8e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Sep 2021 13:26:18 -0700 Subject: [PATCH 06/83] chore(deps): bump hosted-git-info from 2.8.8 to 2.8.9 (#217) Bumps [hosted-git-info](https://github.com/npm/hosted-git-info) from 2.8.8 to 2.8.9. - [Release notes](https://github.com/npm/hosted-git-info/releases) - [Changelog](https://github.com/npm/hosted-git-info/blob/v2.8.9/CHANGELOG.md) - [Commits](https://github.com/npm/hosted-git-info/compare/v2.8.8...v2.8.9) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Eric Reynolds --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index b6f76a3..c6b1cc0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1643,9 +1643,9 @@ "dev": true }, "hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, "http-signature": { From 9530d5b5e91c37e055aa98f6a1ad2a5223ab8401 Mon Sep 17 00:00:00 2001 From: Suren Khorenyan Date: Fri, 3 Sep 2021 23:30:01 +0300 Subject: [PATCH 07/83] pass extra options to httpsnippet (pass through to the target) (#222) Co-authored-by: Eric Reynolds --- README.md | 10 +++++++++- bin/httpsnippet | 13 ++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cb59c19..acb7dd9 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ npm install --save httpsnippet ``` - Usage: httpsnippet [options] + Usage: httpsnippet [options] Options: @@ -32,6 +32,7 @@ npm install --save httpsnippet -t, --target target output -c, --client [client] target client library -o, --output write output to directory + -x, --extra [{"optionKey": "optionValue"}] provide extra options for the target/client ``` @@ -63,6 +64,13 @@ snippets/ └── endpoint-3.js ``` +provide extra options: + +```shell +httpsnippet example.json --target http --output ./snippets -x '{"autoHost": false, "autoContentLength": false}' +``` + + ## API ### HTTPSnippet(source) diff --git a/bin/httpsnippet b/bin/httpsnippet index 3747f66..49410f8 100755 --- a/bin/httpsnippet +++ b/bin/httpsnippet @@ -17,12 +17,23 @@ cmd .option('-t, --target ', 'target output') .option('-c, --client [client]', 'target client library') .option('-o, --output ', 'write output to directory') + .option('-x, --extra [{"optionKey": "optionValue"}]', 'provide extra options for the target/client') .parse(process.argv) if (!cmd.args.length || !cmd.target) { cmd.help() } +let extraOptions +if (cmd.extra) { + try { + extraOptions = JSON.parse(cmd.extra) + } catch (e) { + console.error('%s failed to parse options %s (should be JSON)', chalk.red('✖'), chalk.cyan.bold(cmd.extra)) + process.exit() + } +} + let dir if (cmd.output) { dir = path.resolve(cmd.output) @@ -53,7 +64,7 @@ cmd.args.forEach(function (fileName) { }) .then(function (snippet) { - return snippet.convert(cmd.target, cmd.client) + return snippet.convert(cmd.target, cmd.client, extraOptions) }) .then(function (output) { From 6b85ba24b13241990fecae20eeae3c7d257cd415 Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Fri, 3 Sep 2021 13:31:01 -0700 Subject: [PATCH 08/83] fix: not sending form urlencoded properly in JS fetch snippets (#218) Co-authored-by: Eric Reynolds --- src/targets/javascript/fetch.js | 12 +++++++++++- .../javascript/fetch/application-form-encoded.js | 2 +- test/fixtures/output/javascript/fetch/full.js | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/targets/javascript/fetch.js b/src/targets/javascript/fetch.js index 2bf213f..f76e396 100644 --- a/src/targets/javascript/fetch.js +++ b/src/targets/javascript/fetch.js @@ -67,7 +67,17 @@ module.exports = function (source, options) { } } - code.push('const options = %s;', stringifyObject(options, { indent: opts.indent, inlineCharacterLimit: 80 })) + code.push('const options = %s;', stringifyObject(options, { + indent: opts.indent, + inlineCharacterLimit: 80, + transform: (object, property, originalResult) => { + if (property === 'body' && source.postData.mimeType === 'application/x-www-form-urlencoded') { + return `new URLSearchParams(${originalResult})` + } + + return originalResult + } + })) .blank() if (source.postData.mimeType === 'multipart/form-data') { diff --git a/test/fixtures/output/javascript/fetch/application-form-encoded.js b/test/fixtures/output/javascript/fetch/application-form-encoded.js index 186c1db..a710c45 100644 --- a/test/fixtures/output/javascript/fetch/application-form-encoded.js +++ b/test/fixtures/output/javascript/fetch/application-form-encoded.js @@ -1,7 +1,7 @@ const options = { method: 'POST', headers: {'content-type': 'application/x-www-form-urlencoded'}, - body: {foo: 'bar', hello: 'world'} + body: new URLSearchParams({foo: 'bar', hello: 'world'}) }; fetch('http://mockbin.com/har', options) diff --git a/test/fixtures/output/javascript/fetch/full.js b/test/fixtures/output/javascript/fetch/full.js index 4c7d08f..99298d4 100644 --- a/test/fixtures/output/javascript/fetch/full.js +++ b/test/fixtures/output/javascript/fetch/full.js @@ -5,7 +5,7 @@ const options = { accept: 'application/json', 'content-type': 'application/x-www-form-urlencoded' }, - body: {foo: 'bar'} + body: new URLSearchParams({foo: 'bar'}) }; fetch('http://mockbin.com/har?foo=bar&foo=baz&baz=abc&key=value', options) From 7fd160c016d7b00aca923673004dcdcf4b5a0068 Mon Sep 17 00:00:00 2001 From: Eric Reynolds Date: Fri, 3 Sep 2021 13:36:20 -0700 Subject: [PATCH 09/83] chore(release bump) - Bump package.json to version 2.0.0 BREAKING CHANGE: removed support for Node < 10 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index aa7fd35..0f9f6b0 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "1.25.0", + "version": "2.0.0", "name": "httpsnippet", "description": "HTTP Request snippet generator for *most* languages", "author": "Ahmad Nassri (https://www.mashape.com/)", From df6d3ce80afe182e5e44ed6f5737faa2b6cf748c Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Wed, 8 Dec 2021 18:43:11 +0100 Subject: [PATCH 10/83] Use curl's --compressed option for requests that accept it --- src/targets/shell/curl.js | 4 ++++ test/fixtures/curl/compression.json | 10 ++++++++++ test/targets/shell/curl.js | 9 +++++++++ 3 files changed, 23 insertions(+) create mode 100644 test/fixtures/curl/compression.json diff --git a/src/targets/shell/curl.js b/src/targets/shell/curl.js index 3cde6bb..3bdf6b6 100644 --- a/src/targets/shell/curl.js +++ b/src/targets/shell/curl.js @@ -40,6 +40,10 @@ module.exports = function (source, options) { code.push(opts.short ? '-0' : '--http1.0') } + if (headerHelpers.getHeader(source.allHeaders, 'accept-encoding')) { + code.push('--compressed') + } + // if multipart form data, we want to remove the boundary if (source.postData.mimeType === 'multipart/form-data') { const contentTypeHeaderName = headerHelpers.getHeaderName(source.headersObj, 'content-type') diff --git a/test/fixtures/curl/compression.json b/test/fixtures/curl/compression.json new file mode 100644 index 0000000..1bc9160 --- /dev/null +++ b/test/fixtures/curl/compression.json @@ -0,0 +1,10 @@ +{ + "method": "GET", + "url": "http://mockbin.com/har", + "headers": [ + { + "name": "accept-encoding", + "value": "deflate, gzip, br" + } + ] +} diff --git a/test/targets/shell/curl.js b/test/targets/shell/curl.js index 9435639..fbbff40 100644 --- a/test/targets/shell/curl.js +++ b/test/targets/shell/curl.js @@ -64,6 +64,15 @@ module.exports = function (HTTPSnippet, fixtures) { result.should.eql('curl --request GET --url http://mockbin.com/request --http1.0') }) + it('should use --compressed for requests that accept encodings', function () { + const result = new HTTPSnippet(fixtures.curl.compression).convert('shell', 'curl', { + indent: false + }) + + result.should.be.a.String() + result.should.eql("curl --request GET --url http://mockbin.com/har --compressed --header 'accept-encoding: deflate, gzip, br'") + }) + it('should use custom indentation', function () { const result = new HTTPSnippet(fixtures.requests.full).convert('shell', 'curl', { indent: '@' From 7320d041a7cd149789abe9fb627c1905110cc31f Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Wed, 8 Dec 2021 19:12:00 +0100 Subject: [PATCH 11/83] Add support for insecureSkipVerify with Node.js native modules --- src/targets/node/native.js | 4 ++++ test/targets/node/native.js | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/targets/node/native.js b/src/targets/node/native.js index a61e63c..63a27b4 100644 --- a/src/targets/node/native.js +++ b/src/targets/node/native.js @@ -28,6 +28,10 @@ module.exports = function (source, options) { headers: source.allHeaders } + if (options.insecureSkipVerify) { + reqOpts.rejectUnauthorized = false + } + code.push('const http = require("%s");', source.uriObj.protocol.replace(':', '')) code.blank() diff --git a/test/targets/node/native.js b/test/targets/node/native.js index b77cc77..133faf6 100644 --- a/test/targets/node/native.js +++ b/test/targets/node/native.js @@ -1,3 +1,36 @@ 'use strict' -module.exports = function (snippet, fixtures) {} +module.exports = function (HTTPSnippet, fixtures) { + it('should support the insecureSkipVerify option', function () { + const result = new HTTPSnippet(fixtures.requests.https).convert('node', 'native', { + insecureSkipVerify: true + }) + + result.should.be.a.String() + result.should.eql(`const http = require("https"); + +const options = { + "method": "GET", + "hostname": "mockbin.com", + "port": null, + "path": "/har", + "headers": {}, + "rejectUnauthorized": false +}; + +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();`) + }) +} From f7443942dac3b3c07d1b3f7fd5d553ef96394ba9 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Wed, 8 Dec 2021 19:15:29 +0100 Subject: [PATCH 12/83] Add support for insecureSkipVerify with curl --- src/targets/shell/curl.js | 4 ++++ test/targets/shell/curl.js | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/src/targets/shell/curl.js b/src/targets/shell/curl.js index 3cde6bb..1a0061a 100644 --- a/src/targets/shell/curl.js +++ b/src/targets/shell/curl.js @@ -36,6 +36,10 @@ module.exports = function (source, options) { } code.push(util.format('%s%s', opts.short ? '' : '--url ', formattedUrl)) + if (opts.insecureSkipVerify) { + code.push(opts.short ? '-k' : '--insecure') + } + if (source.httpVersion === 'HTTP/1.0') { code.push(opts.short ? '-0' : '--http1.0') } diff --git a/test/targets/shell/curl.js b/test/targets/shell/curl.js index 9435639..44323bb 100644 --- a/test/targets/shell/curl.js +++ b/test/targets/shell/curl.js @@ -55,6 +55,16 @@ module.exports = function (HTTPSnippet, fixtures) { result.should.eql("curl --request GET --url 'http://mockbin.com/har?foo%5Bbar%5D=baz%2Czap&fiz=buz&key=value'") }) + it('should support insecureSkipVerify', function () { + const result = new HTTPSnippet(fixtures.requests.https).convert('shell', 'curl', { + indent: false, + insecureSkipVerify: true + }) + + result.should.be.a.String() + result.should.eql('curl --request GET --url https://mockbin.com/har --insecure') + }) + it('should use --http1.0 for HTTP/1.0', function () { const result = new HTTPSnippet(fixtures.curl.http1).convert('shell', 'curl', { indent: false From ed6a9fcda0a8cd2f0a0da8b4f8c70a1dc405038f Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Wed, 8 Dec 2021 19:24:44 +0100 Subject: [PATCH 13/83] Add support for insecureSkipVerify with Go --- src/targets/go/native.js | 26 ++++++++++++++++++---- test/targets/go/native.js | 45 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 4 deletions(-) diff --git a/src/targets/go/native.js b/src/targets/go/native.js index fe36c93..93812bb 100644 --- a/src/targets/go/native.js +++ b/src/targets/go/native.js @@ -47,6 +47,10 @@ module.exports = function (source, options) { code.push(indent, '"time"') } + if (opts.insecureSkipVerify) { + code.push(indent, '"crypto/tls"') + } + if (source.postData.text) { code.push(indent, '"strings"') } @@ -63,14 +67,28 @@ module.exports = function (source, options) { .blank() } + // Create an insecure transport for the client + if (opts.insecureSkipVerify) { + code.push(indent, 'insecureTransport := http.DefaultTransport.(*http.Transport).Clone()') + code.push(indent, 'insecureTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}') + } + // Create client let client - if (opts.timeout > 0) { + if (opts.timeout > 0 || opts.insecureSkipVerify) { client = 'client' code.push(indent, 'client := http.Client{') - .push(indent + 1, 'Timeout: time.Duration(%s * time.Second),', opts.timeout) - .push(indent, '}') - .blank() + + if (opts.timeout > 0) { + code.push(indent + 1, 'Timeout: time.Duration(%s * time.Second),', opts.timeout) + } + + if (opts.insecureSkipVerify) { + code.push(indent + 1, 'Transport: insecureTransport,') + } + + code.push(indent, '}') + code.blank() } else { client = 'http.DefaultClient' } diff --git a/test/targets/go/native.js b/test/targets/go/native.js index 5137ecc..5288d45 100644 --- a/test/targets/go/native.js +++ b/test/targets/go/native.js @@ -132,6 +132,51 @@ func main() { \tfmt.Println(res) \tfmt.Println(string(body)) +}`) + }) + + it('should support insecureSkipVerify option', function () { + const result = new HTTPSnippet(fixtures.requests.full).convert('go', 'native', { + insecureSkipVerify: true + }) + + result.should.be.a.String() + result.should.eql(`package main + +import ( +\t"fmt" +\t"crypto/tls" +\t"strings" +\t"net/http" +\t"io/ioutil" +) + +func main() { + +\tinsecureTransport := http.DefaultTransport.(*http.Transport).Clone() +\tinsecureTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} +\tclient := http.Client{ +\t\tTransport: insecureTransport, +\t} + +\turl := "http://mockbin.com/har?foo=bar&foo=baz&baz=abc&key=value" + +\tpayload := strings.NewReader("foo=bar") + +\treq, _ := http.NewRequest("POST", url, payload) + +\treq.Header.Add("cookie", "foo=bar; bar=baz") +\treq.Header.Add("accept", "application/json") +\treq.Header.Add("content-type", "application/x-www-form-urlencoded") + +\tres, _ := client.Do(req) + +\tdefer res.Body.Close() +\tbody, _ := ioutil.ReadAll(res.Body) + +\tfmt.Println(res) +\tfmt.Println(string(body)) + }`) }) } From c003f65a5333a6827ca5bbb7308fcc7c5f913a90 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Wed, 8 Dec 2021 19:32:07 +0100 Subject: [PATCH 14/83] Add support for insecureSkipVerify with Python --- src/targets/python/python3.js | 18 +++++++++++++++--- test/targets/python/python3.js | 21 ++++++++++++++++++++- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/targets/python/python3.js b/src/targets/python/python3.js index a843b93..ab763d0 100644 --- a/src/targets/python/python3.js +++ b/src/targets/python/python3.js @@ -16,13 +16,25 @@ module.exports = function (source, options) { const code = new CodeBuilder() // Start Request code.push('import http.client') - .blank() + + if (options.insecureSkipVerify) { + code.push('import ssl') + } + + code.blank() // Check which protocol to be used for the client connection const protocol = source.uriObj.protocol if (protocol === 'https:') { - code.push('conn = http.client.HTTPSConnection("%s")', source.uriObj.host) - .blank() + if (options.insecureSkipVerify) { + code.push( + 'conn = http.client.HTTPSConnection("%s", context = ssl._create_unverified_context())', + source.uriObj.host + ).blank() + } else { + code.push('conn = http.client.HTTPSConnection("%s")', source.uriObj.host) + .blank() + } } else { code.push('conn = http.client.HTTPConnection("%s")', source.uriObj.host) .blank() diff --git a/test/targets/python/python3.js b/test/targets/python/python3.js index 9ad8c17..ad6bddc 100644 --- a/test/targets/python/python3.js +++ b/test/targets/python/python3.js @@ -2,4 +2,23 @@ require('should') -module.exports = function (snippet, fixtures) {} +module.exports = function (HTTPSnippet, fixtures) { + it('should support insecureSkipVerify', function () { + const result = new HTTPSnippet(fixtures.requests.https).convert('python', 'python3', { + insecureSkipVerify: true + }) + + result.should.be.a.String() + result.should.eql(`import http.client +import ssl + +conn = http.client.HTTPSConnection("mockbin.com", context = ssl._create_unverified_context()) + +conn.request("GET", "/har") + +res = conn.getresponse() +data = res.read() + +print(data.decode("utf-8"))`) + }) +} From b000a7a9e666670068bcd957e1cc4c4a4f39a0b8 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Wed, 8 Dec 2021 19:35:45 +0100 Subject: [PATCH 15/83] Disable cert verification in Ruby only if insecureSkipVerify is set --- src/targets/ruby/native.js | 5 ++++- test/fixtures/output/ruby/native/https.rb | 1 - test/targets/ruby/native.js | 24 ++++++++++++++++++++++- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/targets/ruby/native.js b/src/targets/ruby/native.js index df96b9e..e6d7fa7 100644 --- a/src/targets/ruby/native.js +++ b/src/targets/ruby/native.js @@ -34,7 +34,10 @@ module.exports = function (source, options) { if (source.uriObj.protocol === 'https:') { code.push('http.use_ssl = true') - .push('http.verify_mode = OpenSSL::SSL::VERIFY_NONE') + + if (options.insecureSkipVerify) { + code.push('http.verify_mode = OpenSSL::SSL::VERIFY_NONE') + } } code.blank() diff --git a/test/fixtures/output/ruby/native/https.rb b/test/fixtures/output/ruby/native/https.rb index 8d645dd..81eff1f 100644 --- a/test/fixtures/output/ruby/native/https.rb +++ b/test/fixtures/output/ruby/native/https.rb @@ -6,7 +6,6 @@ http = Net::HTTP.new(url.host, url.port) http.use_ssl = true -http.verify_mode = OpenSSL::SSL::VERIFY_NONE request = Net::HTTP::Get.new(url) diff --git a/test/targets/ruby/native.js b/test/targets/ruby/native.js index b77cc77..a92e36b 100644 --- a/test/targets/ruby/native.js +++ b/test/targets/ruby/native.js @@ -1,3 +1,25 @@ 'use strict' -module.exports = function (snippet, fixtures) {} +module.exports = function (HTTPSnippet, fixtures) { + it('should support insecureSkipVerify', function () { + const result = new HTTPSnippet(fixtures.requests.https).convert('ruby', 'native', { + insecureSkipVerify: true + }) + + result.should.be.a.String() + result.should.eql(`require 'uri' +require 'net/http' +require 'openssl' + +url = URI("https://mockbin.com/har") + +http = Net::HTTP.new(url.host, url.port) +http.use_ssl = true +http.verify_mode = OpenSSL::SSL::VERIFY_NONE + +request = Net::HTTP::Get.new(url) + +response = http.request(request) +puts response.read_body`) + }) +} From cda26a3a71a2705c33f5a76a6b3820d26a382c51 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Wed, 8 Dec 2021 19:48:24 +0100 Subject: [PATCH 16/83] Make it clear why subprocess tests fail given missing dependencies --- test/requests.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/requests.js b/test/requests.js index dd52ff9..63f3fec 100644 --- a/test/requests.js +++ b/test/requests.js @@ -8,7 +8,7 @@ const targets = require('../src/targets') const shell = require('child_process') const util = require('util') -require('should') +const should = require('should') const base = './test/fixtures/output/' const requests = [ @@ -40,6 +40,11 @@ fixtures.cli.forEach(function (cli) { }) ls.on('exit', function (code) { + if (code !== 0) { + console.error(stdout) + should.fail(0, code, `Process '${cli.run.split(' ')[0]}' exited unexpectedly with code ${code}`) + } + let har try { har = JSON.parse(stdout) From b6c56d62e7542526444e73e3ad91999db9aa5466 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Wed, 8 Dec 2021 20:23:41 +0100 Subject: [PATCH 17/83] Replace Travis (now unusable) with GitHub Actions --- .github/workflows/ci.yml | 25 +++++++++++++++++++++++++ .travis.yml | 12 ------------ 2 files changed, 25 insertions(+), 12 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..53c679d --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,25 @@ +name: CI +on: [push, pull_request] +jobs: + build: + name: Build & test + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [10.x, 12.x, 14.x, 16.x, '*'] + + steps: + - uses: actions/checkout@v2 + + - uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node-version }} + + - uses: shivammathur/setup-php@v2 + with: + php-version: '7.0' + + - run: npm ci + - run: npm test + - run: npm run codeclimate diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index c7e2c8e..0000000 --- a/.travis.yml +++ /dev/null @@ -1,12 +0,0 @@ -language: node_js - -node_js: - - node - - lts/* - -before_install: - - sudo apt-get update -qq - - sudo apt-get install -qq php7.0 php7.0-curl php7.0-cli - -after_script: - - npm run codeclimate From 2602e574d7b4fe3c6ddf01bcd3b472ed231cb75f Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Wed, 8 Dec 2021 20:31:06 +0100 Subject: [PATCH 18/83] Fix npm coverage scripts --- .github/workflows/ci.yml | 2 ++ package.json | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 53c679d..b34f6b4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,3 +23,5 @@ jobs: - run: npm ci - run: npm test - run: npm run codeclimate + env: + CODECLIMATE_REPO_TOKEN: ${{ secrets.CODECLIMATE_REPO_TOKEN }} diff --git a/package.json b/package.json index 0f9f6b0..1f6c0dc 100644 --- a/package.json +++ b/package.json @@ -52,9 +52,9 @@ "quick": "mocha --no-timeouts --fgrep 'Request Validation' --invert", "pretest": "standard && echint", "test": "mocha --no-timeouts", - "posttest": "exit 0 && npm run coverage", + "posttest": "npm run coverage", "coverage": "istanbul cover --dir coverage _mocha -- --fgrep 'Request Validation' --invert -R dot", - "codeclimate": "codeclimate < coverage/lcov.info" + "codeclimate": "codeclimate-test-reporter < coverage/lcov.info" }, "standard": { "env": "mocha", From c5026f6b685273e6fff4f7637d2ca55642c4e03f Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Thu, 3 Feb 2022 14:41:25 +0100 Subject: [PATCH 19/83] Disable (for now at least) codeclimate, so builds work on our fork This previously worked for one test run for a quick PR, but having recreated the repo it's now broken, and it's impossible to reset CodeClimate with the new repo for some reason. Not especially important, so lets drop it. --- .github/workflows/ci.yml | 3 --- package.json | 4 +--- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b34f6b4..fb074a8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,6 +22,3 @@ jobs: - run: npm ci - run: npm test - - run: npm run codeclimate - env: - CODECLIMATE_REPO_TOKEN: ${{ secrets.CODECLIMATE_REPO_TOKEN }} diff --git a/package.json b/package.json index 1f6c0dc..561e022 100644 --- a/package.json +++ b/package.json @@ -53,8 +53,7 @@ "pretest": "standard && echint", "test": "mocha --no-timeouts", "posttest": "npm run coverage", - "coverage": "istanbul cover --dir coverage _mocha -- --fgrep 'Request Validation' --invert -R dot", - "codeclimate": "codeclimate-test-reporter < coverage/lcov.info" + "coverage": "istanbul cover --dir coverage _mocha -- --fgrep 'Request Validation' --invert -R dot" }, "standard": { "env": "mocha", @@ -70,7 +69,6 @@ ] }, "devDependencies": { - "codeclimate-test-reporter": "^0.5.1", "echint": "^4.0.2", "glob": "^6.0.1", "istanbul": "^0.4.0", From 136abf01b3dbda7a1b95d1fcb080a3c99060432f Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Thu, 3 Feb 2022 15:18:56 +0100 Subject: [PATCH 20/83] Inline 'Creating Targets' wiki page into CONTRIBUTING This should let us remove wiki references and generally allow us to start versioning all the documentation alongside the source code. --- CONTRIBUTING.md | 291 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 289 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c4cae94..ddfed4d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,7 +11,7 @@ patches and features. ## Using the issue tracker The [issue tracker](/issues) is the preferred channel for [bug reports](#bug-reports), -[features requests](#feature-requests) and [submitting pull requests](#pull-requests), +[features requests](#feature-requests) and [submitting pull requests](#pull-requests), but please respect the following restrictions: * Please **do not** use the issue tracker for personal support requests (use @@ -136,4 +136,291 @@ license your work under the same license as that used by the project. ## Creating New Conversion Targets -For a info on creating new conversion targets, please review this [guideline](https://github.com/Mashape/httpsnippet/wiki/Creating-Targets) +A target is a simple module with a constructor that accepts two parameters: `source` and `options`, where `source` is the HAR Object to process, and `options` is an optional object with any target-specific flags *(used for customizing the output)*. + +###### Example + +```js +module.exports = function (source, opts) { + // optionally process `opts` object for target specific configuration + // + // process `source` object + // + // return processed output as string +}; + +module.exports.info = { + key: 'curl', + title: 'cURL', + link: 'http://curl.haxx.se/', + description: 'curl is a command line tool and library for transferring data with URL syntax', + extname: '.sh' +}; +``` + +### Conversion Rules + +1. Start by reading and understanding the [HAR](http://www.softwareishard.com/blog/har-12-spec/#request) format. +2. Utilize utility properties created for convenience (`source.headersObj`, `source.uriObj` etc ...) *see below for mode details* +3. Follow the guidelines below for best practices and consistency. + +### Guidelines + +Using the following example of a request object, HTTP Snippet will pre-process data and create some additional properties: + +| property | description | +| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | +| `source.fullUrl` | the full & final url, including all query string values | +| `source.uriObj` | the url parsed with `url.parse()`. compatible with `url.format` | +| `source.queryObj` | a key => value pair, "normalized" version of `source.queryString`, adds additional query string values from the `source.url` | +| `source.headersObj` | a key => value pair, "normalized" version of `source.headers`, header names are lowercased | +| `source.allHeaders` | same as `source.headersObj` but with `cookies` header and populated from `source.cookies` array | +| `source.postData.jsonObj` | the parsed value of `source.postData.text`, only for `source.postData.mimeType` = `application/json` *(or equivalent mimeTypes)* | +| `source.postData.paramsObj` | a key => value pair, "normalized" version of `source.postData.params`, only for `source.postData.mimeType` = `application/x-www-form-urlencoded` | + +###### Sample Incoming Request Object + +```js +{ + method: 'POST', + url: 'http://mockbin.com/har?key=value', + httpVersion: 'HTTP/1.1', + queryString: [ + { name: 'foo', value: 'bar' }, + { name: 'foo', value: 'baz' }, + { name: 'baz', value: 'abc' } + ], + headers: [ + { name: 'Accept', value: 'application/json' }, + { name: 'Content-Type', value: 'application/x-www-form-urlencoded' } + ], + + cookies: [ + { name: 'foo', value: 'bar' }, + { name: 'bar', value: 'baz' } + ], + + postData: { + mimeType: 'application/x-www-form-urlencoded', + params: [ + { name: 'foo', value: 'bar' }, + { name: 'foo', value: 'baz' }, + { name: 'baz', value: 'abc' } + ] + } +} +``` + +###### Processed Source Object + +```js +{ + method: 'POST', + + // the base url value stripped of any the query string + url: 'http://mockbin.com/har', + + // the full & final url, including all query string values + fullUrl: 'http://mockbin.com/har?foo=bar&foo=baz&baz=abc&key=value', + + // the url parsed with url.parse() + // compatible with url.format + uriObj: { + protocol: 'http:', + slashes: true, + auth: null, + host: 'mockbin.com', + port: null, + hostname: 'mockbin.com', + hash: null, + search: 'key=value&baz=abc&foo=bar&foo=baz', + query: { key: 'value', baz: 'abc', foo: [Object] }, + pathname: '/har', + path: '/har?key=value&baz=abc&foo=bar&foo=baz', + href: 'http://mockbin.com/har' + }, + + httpVersion: 'HTTP/1.1', + + // added to pass har-validator + bodySize: 0, + + // added to pass har-validator + headersSize: 0, + + queryString: [ + { name: 'foo', value: 'bar' }, + { name: 'foo', value: 'baz' }, + { name: 'baz', value: 'abc' } + ], + + // "normalized" version of `queryString` + // adds any additional query string values from the url + // compatible with "querystring" node module + queryObj: { + key: 'value', + baz: 'abc', + foo: [ 'bar', 'baz' ] + }, + + headers: [ + { name: 'Accept', value: 'application/json' }, + { name: 'Content-Type', value: 'application/x-www-form-urlencoded' } + ], + + // normalized headers array into a key => value object pair + // header names are lowercased + headersObj: { + 'accept': 'application/json', + 'content-type': 'application/x-www-form-urlencoded' + }, + + // same as headersObj but with Cookies added (if any exist in cookies array) + allHeaders: { + 'accept': 'application/json', + 'content-type': 'application/x-www-form-urlencoded', + 'cookie': 'foo=bar; bar=baz' + }, + + cookies: [ + { name: 'foo', value: 'bar' }, + { name: 'bar', value: 'baz' } + ], + + // see below for different scenarios + postData: [Object] +} +``` + +###### application/x-www-form-urlencoded + +```js +postData: { + // added to pass har-validator + size: 0, + + // original value + mimeType: 'application/x-www-form-urlencoded', + + // original value + params: [ + { name: 'foo', value: 'bar' }, + { name: 'foo', value: 'baz' }, + { name: 'baz', value: 'abc' } + ], + + // "normalized" version of `params` + // compatible with "querystring" node module + paramsObj: { + key: 'value', + baz: 'abc', + foo: [ 'bar', 'baz' ] + } + + // the raw body in plain text + // this value will be always overwritten in this scenario + text: 'baz=abc&foo=bar&foo=baz' + + // see below + jsonObj: false +} +``` + +###### application/json + +- Will match when `postData.mimeType` is one of: `application/json`, `text/json`, `text/x-json`, `application/x-json` +- In case of failure to parse `postData.text` as a JSON object, `postData.mimeType` is set to `text/plain`, `postData.jsonObj` remains as `false`. this is done so that the implementing target, would still attempt to post the raw body as is. +- This also emphasizes not to rely on `postData.mimeType` for the `Content-Type` header! + +```js +postData: { + // added to pass har-validator + size: 0, + + // original value + mimeType: 'application/json', + + // ignored + params: [], + + // default value + paramsObj: false + + // the raw body in plain text + text: '"{\"foo\": \"bar\"}"' + + // the parsed value of postData.text + jsonObj: { + foo: 'bar' + } +} +``` + +###### multipart/form-data + +- Will match when `postData.mimeType` is one of: `multipart/mixed` `multipart/related`, `multipart/form-data`, `multipart/alternative` +- Will force `postData.mimeType` to `multipart/form-data` +- Will create/overwrite the `Content-Type` header if it does not exist, with the appropriate boundary flag. +- When no `params[].value` is present, will default to empty content + +```js +postData: { + // added to pass har-validator + size: 0, + + // original value + mimeType: 'multipart/form-data', + + // parsed into text values + params: [ + { + name: 'foo', + value: 'bar' + } + ] + + // ignored + paramsObj: false + + // the raw body in plain text + // generated based on appropriately parsing the `params` into a multi-boundary content string + // this value will be always overwritten in this scenario + text: '----------------------------591447866569479977899212\r\nContent-Disposition: form-data; name=\"foo\"\r\n\r\nbar\r\n----------------------------591447866569479977899212--' + + // ignored + jsonObj: false +} +``` + +###### multipart/form-data (File Uploads) + +```js +postData: { + // added to pass har-validator + size: 0, + + // original value + mimeType: 'multipart/form-data', + + // parsed into text values + params: [ + { + name: 'foo', + value: 'Hello World', + fileName: 'test/fixtures/files/hello.txt', + contentType: 'text/plain' + } + ] + + // ignored + paramsObj: false + + // the raw body in plain text + // generated based on appropriately parsing the `params` into a multi-boundary content string + // this value will be always overwritten in this scenario + text: '----------------------------771333709043252625002993\r\nContent-Disposition: form-data; name=\"foo\"; filename=\"hello.txt\"\r\nContent-Type: text/plain\r\n\r\nHello World\r\n----------------------------771333709043252625002993--' + + // ignored + jsonObj: false +} +``` From 31a2211210ce047d65d13c417679739e4a8fe9ea Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Thu, 3 Feb 2022 15:23:04 +0100 Subject: [PATCH 21/83] Move target docs inline & update internal wiki links --- README.md | 22 ++--- TARGETS.md | 267 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 278 insertions(+), 11 deletions(-) create mode 100644 TARGETS.md diff --git a/README.md b/README.md index acb7dd9..1a38293 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ httpsnippet example.json --target http --output ./snippets -x '{"autoHost": fals *Required* Type: `object` -Name of [conversion target](https://github.com/Mashape/httpsnippet/wiki/Targets) +Name of [conversion target](TARGETS.md) ```js var HTTPSnippet = require('httpsnippet'); @@ -98,13 +98,13 @@ var snippet = new HTTPSnippet({ *Required* Type: `string` -Name of [conversion target](https://github.com/Mashape/httpsnippet/wiki/Targets) +Name of [conversion target](TARGETS.md) #### options Type: `object` -Target options, *see [wiki](https://github.com/Mashape/httpsnippet/wiki/Targets) for details* +Target options, *see [target docs](https://github.com/httptoolkit/httpsnippet/blob/main/TARGETS.md) for details* ```js var HTTPSnippet = require('httpsnippet'); @@ -130,19 +130,19 @@ console.log(snippet.convert('node', { *Required* Type: `string` -Name of [conversion target](https://github.com/Mashape/httpsnippet/wiki/Targets) +Name of [conversion target](TARGETS.md) #### client Type: `string` -Name of conversion target [client library](https://github.com/Mashape/httpsnippet/wiki/Targets) +Name of conversion target [client library](TARGETS.md) #### options Type: `object` -Target options, *see [wiki](https://github.com/Mashape/httpsnippet/wiki/Targets) for details* +Target options, *see [target docs](https://github.com/httptoolkit/httpsnippet/blob/main/TARGETS.md) for details* ```js var HTTPSnippet = require('httpsnippet'); @@ -167,7 +167,7 @@ console.log(snippet.convert('node', 'unirest')); *Required* Type: `object` -Representation of a [conversion target](https://github.com/Kong/httpsnippet/wiki/Creating-Targets). Can use this to use targets that are not officially supported. +Representation of a [conversion target](https://github.com/httptoolkit/httpsnippet/blob/main/CONTRIBUTING.md#creating-new-conversion-targets). Can use this to use targets that are not officially supported. ```js const customLanguageTarget = require('httpsnippet-for-my-lang'); @@ -180,14 +180,14 @@ HTTPSnippet.addTarget(customLanguageTarget); *Required* Type: `string` -Name of [conversion target](https://github.com/Mashape/httpsnippet/wiki/Targets) +Name of [conversion target](TARGETS.md) ### client *Required* Type: `object` -Representation of a [conversion target client](https://github.com/Kong/httpsnippet/wiki/Creating-Targets). Can use this to use target clients that are not officially supported. +Representation of a [conversion target client](https://github.com/httptoolkit/httpsnippet/blob/main/CONTRIBUTING.md#creating-new-conversion-targets). Can use this to use target clients that are not officially supported. ```js const customClient = require('httpsnippet-for-my-node-http-client'); @@ -198,7 +198,7 @@ HTTPSnippet.addTargetClient('node', customClient); At the heart of this module is the [HAR Format](http://www.softwareishard.com/blog/har-12-spec/#request) as the HTTP request description format, please review some of the sample JSON HAR Request objects in [test fixtures](/test/fixtures/requests), or read the [HAR Docs](http://www.softwareishard.com/blog/har-12-spec/#request) for more details. -For detailed information on each target, please review the [wiki](https://github.com/Mashape/httpsnippet/wiki). +For detailed information on each target, please review the [target docs](./TARGETS.md). ## Bugs and feature requests @@ -208,7 +208,7 @@ Have a bug or a feature request? Please first read the [issue guidelines](CONTRI Please read through our [contributing guidelines](CONTRIBUTING.md). Included are directions for opening issues, coding standards, and notes on development. -For info on creating new conversion targets, please review this [guideline](https://github.com/Mashape/httpsnippet/wiki/Creating-Targets) +For info on creating new conversion targets, please review this [guideline](https://github.com/httptoolkit/httpsnippet/blob/main/CONTRIBUTING.md#creating-new-conversion-targets) Moreover, if your pull request contains JavaScript patches or features, you must include relevant unit tests. diff --git a/TARGETS.md b/TARGETS.md new file mode 100644 index 0000000..08d9986 --- /dev/null +++ b/TARGETS.md @@ -0,0 +1,267 @@ +# Targets + +Currently the following output targets are supported: + +## Go + +### [Native](http://golang.org/pkg/net/http/#NewRequest) + +> Golang HTTP client request + +###### Options + +| Option | Default | Description | +| --------------- | ------- | ----------------------------------------------------- | +| `checkErrors` | `false` | add error checking for request, response and body | +| `printBody` | `true` | include code to print the body as a string | +| `timeout` | `-1` | sets a request timeout in seconds (requires go 1.3+) | + +---- + +## Java + +### [Unirest](http://unirest.io/java.html) + +> Lightweight HTTP Request Client Library + +###### Options + +| Option | Default | Description | +| --------- | ------- | -------------------------------- | +| `indent` | ` ` | line break & indent output value | + +### [OkHttp](http://square.github.io/okhttp/) + +> An HTTP Request Client Library + +###### Options + +| Option | Default | Description | +| --------- | ------- | -------------------------------- | +| `indent` | ` ` | line break & indent output value | + +---- + +## JavaScript + +### [jQuery.ajax](http://api.jquery.com/jquery.ajax/) + +> Perform an asynchronous HTTP (Ajax) requests with jQuery + +###### Options + +| Option | Default | Description | +| --------- | ------- | -------------------------------- | +| `indent` | ` ` | line break & indent output value | + +### [XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) + +> W3C Standard API that provides scripted client functionality + +###### Options + +| Option | Default | Description | +| --------- | ------- | -------------------------------- | +| `cors` | `true` | use `xhr.withCredentials = true` | +| `indent` | ` ` | line break & indent output value | + +###### Options + +---- + +## Node.js + +### [Native](http://nodejs.org/api/http.html#http_http_request_options_callback) + +> Node.js native HTTP interface + +###### Options + +| Option | Default | Description | +| --------- | ------- | -------------------------------- | +| `indent` | ` ` | line break & indent output value | + +### [Request](https://github.com/request/request) + +> Simplified HTTP request client + +###### Options + +| Option | Default | Description | +| --------- | ------- | -------------------------------- | +| `indent` | ` ` | line break & indent output value | + +### [Unirest](http://unirest.io/nodejs.html) + +> Lightweight HTTP Request Client Library + +###### Options + +| Option | Default | Description | +| --------- | ------- | -------------------------------- | +| `indent` | ` ` | line break & indent output value | + +---- + +## Objective-C + +### [NSURLSession](https://developer.apple.com/library/mac/documentation/Foundation/Reference/NSURLSession_class/index.html) + +> Foundation's NSURLSession request + +###### Options + +| Option | Default | Description | +| --------- | ------- | --------------------------------------------------------------- | +| `indent` | ` ` | line break & indent output value | +| `pretty` | `true` | indent extracted headers/parameters in `NSDictionary` literals | +| `timeout` | `10` | NSURLRequest timeout | + +---- + +## OCaml + +### [CoHTTP](https://github.com/mirage/ocaml-cohttp) + +> CoHTTP is a very lightweight HTTP server using Lwt or Async for OCaml + +###### Options + +| Option | Default | Description | +| --------- | ------- | -------------------------------- | +| `indent` | ` ` | line break & indent output value | + +---- + +## PHP + +### [ext-curl](http://php.net/manual/en/book.curl.php) + +> PHP with ext-curl + +###### Options + +| Option | Default | Description | +| --------------- | ------- | ----------------------------------------------- | +| `closingTag` | `false` | add a closing tag `?>` | +| `indent` | ` ` | line break & indent output value | +| `maxRedirects` | `10` | value for `CURLOPT_MAXREDIRS` | +| `namedErrors` | `false` | attempt to display curl error name instead of # | +| `noTags` | `false` | do NOT output start and end tags: `` | +| `shortTags` | `false` | use short opening tag: ` PHP with pecl/http v1 + +###### Options + +| Option | Default | Description | +| --------------- | ------- | ----------------------------------------------- | +| `closingTag` | `false` | add a closing tag `?>` | +| `indent` | ` ` | line break & indent output value | +| `noTags` | `false` | do NOT output start and end tags: `` | +| `shortTags` | `false` | use short opening tag: ` PHP with pecl/http v2 + +###### Options + +| Option | Default | Description | +| --------------- | ------- | ----------------------------------------------- | +| `closingTag` | `false` | add a closing tag `?>` | +| `indent` | ` ` | line break & indent output value | +| `noTags` | `false` | do NOT output start and end tags: `` | +| `shortTags` | `false` | use short opening tag: ` Python3 HTTP Client + +### [Requests](http://docs.python-requests.org/en/latest/api/#requests.request) + +Requests HTTP library + +---- + +## Ruby + +### [Native](http://ruby-doc.org/stdlib-2.2.1/libdoc/net/http/rdoc/Net/HTTP.html) + +> Ruby HTTP client + +---- + +## Shell + +### [cURL](http://curl.haxx.se/) + +> cURL is a command line tool and library for transferring data with URL syntax + +| Option | Default | Description | +| -------- | ------- | ------------------------------------------------------------------------ | +| `indent` | ` ` | line break & indent output value, set to `false` to disable line breaks | +| `short` | `false` | use short form of cURL CLI options | + +### [HTTPie](http://httpie.org) + +> a CLI, cURL-like tool for humans + +| Option | Default | Description | +| ------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------- | +| `body` | `false` | only the response body is printed | +| `cert` | `false` | use a client side certificate *(see [httpie docs](https://github.com/jakubroztocil/httpie#client-side-ssl-certificate))* | +| `headers` | `false` | only the response headers are printed | +| `indent` | ` ` | line break & indent output value, set to `false` to disable line breaks | +| `pretty` | `false` | syntax highlighting *(see [httpie docs](https://github.com/jakubroztocil/httpie#colors-and-formatting))* | +| `print` | `false` | selects parts of the HTTP exchange, e.g. `--print=Hh` *(see [httpie docs](https://github.com/jakubroztocil/httpie#output-options))* | +| `queryParams` | `false` | use query params as CLI parameters *otherwise, query string is added to URL* | +| `short` | `false` | use short form of cURL CLI options | +| `style` | `false` | syntax highlighting *(see [httpie docs](https://github.com/jakubroztocil/httpie#colors-and-formatting))* | +| `timeout` | `false` | overwrite the default *30s* timeout | +| `verbose` | `false` | print the whole HTTP exchange (request and response) | +| `verify` | `false` | server SSL certificate verification *(see [httpie docs](https://github.com/jakubroztocil/httpie#server-ssl-certificate-verification))* | + +### [Wget](https://www.gnu.org/software/wget/) + +> a free software package for retrieving files using HTTP, HTTPS + +| Option | Default | Description | +| --------- | ------- | ------------------------------------------------------------------------ | +| `indent` | ` ` | line break & indent output value, set to `false` to disable line breaks | +| `short` | `false` | use short form of cURL CLI options | +| `verbose` | `false` | by default, `--quiet` is always used, unless `verbose` is set to `true` | + +---- + +## Swift + +### [NSURLSession](https://developer.apple.com/library/mac/documentation/Foundation/Reference/NSURLSession_class/index.html) + +> Foundation's NSURLSession request + +| Option | Default | Description | +| --------- | ------- | --------------------------------------------------------------- | +| `indent` | ` ` | line break & indent output value | +| `pretty` | `true` | indent extracted headers/parameters in `NSDictionary` literals | +| `timeout` | `10` | NSURLRequest timeout | + + +## C# + +### [RestSharp](http://restsharp.org/) + +> Simple REST and HTTP API Client for .NET + +## C + +### [LibCurl](http://curl.haxx.se/libcurl/) + +> A easy-to-use client-side URL transfer library From 1d6d7be06000eb1fbff025bc515a62abf54939a4 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Thu, 3 Feb 2022 15:23:27 +0100 Subject: [PATCH 22/83] Update docs & package name to complete fork --- CONTRIBUTING.md | 2 +- README.md | 29 +++++++---------------------- package.json | 12 ++++++------ 3 files changed, 14 insertions(+), 29 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ddfed4d..ba2b0ba 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -93,7 +93,7 @@ project: # Navigate to the newly cloned directory cd # Assign the original repo to a remote called "upstream" - git remote add upstream https://github.com/Mashape/httpsnippet.git + git remote add upstream https://github.com/httptoolkit/httpsnippet.git ``` 2. If you cloned a while ago, get the latest changes from upstream: diff --git a/README.md b/README.md index 1a38293..9884759 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,21 @@ -# HTTP Snippet [![version][npm-version]][npm-url] [![License][npm-license]][license-url] +# @httptoolkit/HTTPSnippet [![Build Status](https://github.com/httptoolkit/httpsnippet/workflows/CI/badge.svg)](https://github.com/httptoolkit/httpsnippet/actions) [![Available on NPM](https://img.shields.io/npm/v/@httptoolkit/httpsnippet.svg)](https://npmjs.com/package/@httptoolkit/httpsnippet) -> HTTP Request snippet generator for *many* languages & tools including: `cURL`, `HTTPie`, `Javascript`, `Node`, `C`, `Java`, `PHP`, `Objective-C`, `Swift`, `Python`, `Ruby`, `C#`, `Go`, `OCaml` and [more](https://github.com/Mashape/httpsnippet/wiki/Targets)! +> _Part of [HTTP Toolkit](https://httptoolkit.tech): powerful tools for building, testing & debugging HTTP(S)_ -Relies on the popular [HAR](http://www.softwareishard.com/blog/har-12-spec/#request) format to import data and describe HTTP calls. +Httpsnippet is an HTTP request snippet generator for *many* languages & tools including: `cURL`, `HTTPie`, `Javascript`, `Node`, `C`, `Java`, `PHP`, `Objective-C`, `Swift`, `Python`, `Ruby`, `C#`, `Go`, `OCaml` and [more](https://github.com/httptoolkit/httpsnippet/tree/main/src/targets)! -See it in action on companion service: [APIembed](https://apiembed.com/) +This library relies on the popular [HAR](http://www.softwareishard.com/blog/har-12-spec/#request) format to import data and describe HTTP calls. -[![Build Status][travis-image]][travis-url] -[![Downloads][npm-downloads]][npm-url] +_This is a fork of Kong's (previous Mashape's) [httpsnippet](https://github.com/Kong/httpsnippet/) library, which appears to no longer be maintained. This version is in active production use in [HTTP Toolkit](https://httptoolkit.tech)._ ## Install ```shell # to use in cli -npm install --global httpsnippet +npm install --global @httptoolkit/httpsnippet # to use as a module -npm install --save httpsnippet +npm install --save @httptoolkit/httpsnippet ``` ## Usage @@ -229,17 +228,3 @@ And constructed with the following guidelines: - Bug fixes and misc changes **bumps only the patch** For more information on SemVer, please visit . - -## License - -[MIT](LICENSE) © [Kong](https://konghq.com) - -[license-url]: https://github.com/Kong/httpsnippet/blob/master/LICENSE - -[travis-url]: https://travis-ci.org/Kong/httpsnippet -[travis-image]: https://api.travis-ci.org/Kong/httpsnippet.svg?branch=master - -[npm-url]: https://www.npmjs.com/package/httpsnippet -[npm-license]: https://img.shields.io/npm/l/httpsnippet.svg?style=flat-square -[npm-version]: https://img.shields.io/npm/v/httpsnippet.svg?style=flat-square -[npm-downloads]: https://img.shields.io/npm/dm/httpsnippet.svg?style=flat-square diff --git a/package.json b/package.json index 561e022..00f8823 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { "version": "2.0.0", - "name": "httpsnippet", - "description": "HTTP Request snippet generator for *most* languages", - "author": "Ahmad Nassri (https://www.mashape.com/)", - "homepage": "https://github.com/Mashape/httpsnippet", + "name": "@httptoolkit/httpsnippet", + "description": "HTTP request snippet generator for *most* languages", + "author": "Tim Perry ", + "homepage": "https://github.com/httptoolkit/httpsnippet", "license": "MIT", "main": "src/index.js", "bin": "bin/httpsnippet", @@ -44,9 +44,9 @@ "bin", "src" ], - "repository": "Mashape/httpsnippet", + "repository": "httptoolkit/httpsnippet", "bugs": { - "url": "https://github.com/Mashape/httpsnippet/issues" + "url": "https://github.com/httptoolkit/httpsnippet/issues" }, "scripts": { "quick": "mocha --no-timeouts --fgrep 'Request Validation' --invert", From e23d6623187d935b1f3f162fe25531719b00490f Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Thu, 3 Feb 2022 15:30:05 +0100 Subject: [PATCH 23/83] Update package-lock to new format Also updates the package name after the fork, completes the removal of codeclimate libs, and includes the update of the version number (seems like that never happened in the source repo?) --- package-lock.json | 4923 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 4578 insertions(+), 345 deletions(-) diff --git a/package-lock.json b/package-lock.json index c6b1cc0..03abc83 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,8 +1,4574 @@ { - "name": "httpsnippet", - "version": "1.25.0", - "lockfileVersion": 1, + "name": "@httptoolkit/httpsnippet", + "version": "2.0.0", + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "@httptoolkit/httpsnippet", + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "chalk": "^1.1.1", + "commander": "^2.9.0", + "debug": "^2.2.0", + "event-stream": "3.3.4", + "form-data": "3.0.0", + "fs-readfile-promise": "^2.0.1", + "fs-writefile-promise": "^1.0.3", + "har-validator": "^5.0.0", + "stringify-object": "^3.3.0" + }, + "bin": { + "httpsnippet": "bin/httpsnippet" + }, + "devDependencies": { + "echint": "^4.0.2", + "glob": "^6.0.1", + "istanbul": "^0.4.0", + "mocha": "^8.2.1", + "require-directory": "^2.1.1", + "should": "^13.2.3", + "standard": "^16.0.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", + "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", + "dev": true + }, + "node_modules/@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "node_modules/@babel/highlight/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==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.2.tgz", + "integrity": "sha512-EfB5OHNYp1F4px/LI/FEnGylop7nOqkQ1LRzCM0KccA2U8tvV8w01KBv37LbO7nW4H+YhKyo2LcJhRwjjV17QQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "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", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "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", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@eslint/eslintrc/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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", + "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", + "dev": true + }, + "node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", + "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", + "dependencies": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "node_modules/amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.4.2" + } + }, + "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/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "engines": { + "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", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-includes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.2.tgz", + "integrity": "sha512-w2GspexNQpx+PutG3QpT437/BenZBj0M/MZGn5mzv/MofYqo0xmRHzn4lFsoDlWJ+THYsGJmFlW68WlDFx7VRw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "get-intrinsic": "^1.0.1", + "is-string": "^1.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", + "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz", + "integrity": "sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "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", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.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", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "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", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/chokidar": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", + "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", + "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" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.1.2" + } + }, + "node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "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, + "engines": { + "node": ">=6" + } + }, + "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==", + "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/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==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/commander": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/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" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/debug-log": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.1.tgz", + "integrity": "sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8=", + "dev": true, + "engines": { + "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", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "node_modules/define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "dependencies": { + "object-keys": "^1.0.12" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dotenv": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-7.0.0.tgz", + "integrity": "sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/duplexer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=" + }, + "node_modules/echint": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/echint/-/echint-4.0.2.tgz", + "integrity": "sha512-iUEHrTxUqpZ0V6ayTmjyf9/f3Iz/Pp3EGKhmfFpnZQ4tjTk3ZyO9bO2qGwgr3coSknzXdieYrcCe3JDsiI/Uvw==", + "deprecated": "no longer maintained", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "commander": "^2.19.0", + "dotenv": "^7.0.0", + "glob": "^7.1.3", + "lintspaces": "0.6.3", + "minimatch": "^3.0.4", + "pkg-config": "^1.1.1" + }, + "bin": { + "echint": "lib/bin.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/echint/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==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/echint/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/echint/node_modules/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha1-OWCDLT8VdBCDQtr9OmezMsCWnfE=", + "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" + }, + "engines": { + "node": "*" + } + }, + "node_modules/echint/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/echint/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/editorconfig": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", + "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", + "dev": true, + "dependencies": { + "commander": "^2.19.0", + "lru-cache": "^4.1.5", + "semver": "^5.6.0", + "sigmund": "^1.0.1" + }, + "bin": { + "editorconfig": "bin/editorconfig" + } + }, + "node_modules/editorconfig/node_modules/semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "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", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.18.0-next.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.2.tgz", + "integrity": "sha512-Ih4ZMFHEtZupnUh6497zEL4y2+w8+1ljnCyaTa+adcoafI1GOvMwFlDjBLfWR7y9VLfrjRJe9ocuHY1PSR9jjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.1", + "object-inspect": "^1.9.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.3", + "string.prototype.trimstart": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "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", + "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-abstract/node_modules/object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-abstract/node_modules/string.prototype.trimend": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz", + "integrity": "sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-abstract/node_modules/string.prototype.trimstart": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz", + "integrity": "sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", + "dev": true, + "dependencies": { + "esprima": "^2.7.1", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=0.12.0" + }, + "optionalDependencies": { + "source-map": "~0.2.0" + } + }, + "node_modules/eslint": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.13.0.tgz", + "integrity": "sha512-uCORMuOO8tUzJmsdRtrvcGq5qposf7Rw0LwkTJkoDbOycVQtQjmnhZSuLQnozLE4TmAzlMVV45eCHmQ1OpDKUQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "@eslint/eslintrc": "^0.2.1", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.0", + "esquery": "^1.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-standard": { + "version": "16.0.2", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-16.0.2.tgz", + "integrity": "sha512-fx3f1rJDsl9bY7qzyX8SAtP8GBSk6MfXFaTfaGgk12aAYW4gJSyRm7dM790L6cbXv63fvjY4XeSzXnb4WM+SKw==", + "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" + } + ], + "peerDependencies": { + "eslint": "^7.12.1", + "eslint-plugin-import": "^2.22.1", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-promise": "^4.2.1" + } + }, + "node_modules/eslint-config-standard-jsx": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-10.0.0.tgz", + "integrity": "sha512-hLeA2f5e06W1xyr/93/QJulN/rLbUVUmqTlexv9PRKHFwEC9ffJcH2LvJhMoEqYQBEYafedgGZXH2W8NUpt5lA==", + "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" + } + ], + "peerDependencies": { + "eslint": "^7.12.1", + "eslint-plugin-react": "^7.21.5" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", + "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "dev": true, + "dependencies": { + "debug": "^2.6.9", + "resolve": "^1.13.1" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "dev": true, + "dependencies": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", + "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", + "dev": true, + "dependencies": { + "debug": "^2.6.9", + "pkg-dir": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-es": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", + "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", + "dev": true, + "dependencies": { + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=4.19.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.22.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz", + "integrity": "sha512-8K7JjINHOpH64ozkAhpT3sd+FswIZTfMZTjdx052pnWrgRCVfp8op9tbjpAk3DdUeI/Ba4C8OjdC0r90erHEOw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.1", + "array.prototype.flat": "^1.2.3", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.4", + "eslint-module-utils": "^2.6.0", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.1", + "read-pkg-up": "^2.0.0", + "resolve": "^1.17.0", + "tsconfig-paths": "^3.9.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "dependencies": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "dev": true, + "dependencies": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-node": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", + "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", + "dev": true, + "dependencies": { + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" + }, + "engines": { + "node": ">=8.10.0" + }, + "peerDependencies": { + "eslint": ">=5.16.0" + } + }, + "node_modules/eslint-plugin-node/node_modules/ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/eslint-plugin-node/node_modules/resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "dev": true, + "dependencies": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-node/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-promise": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz", + "integrity": "sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.21.5.tgz", + "integrity": "sha512-8MaEggC2et0wSF6bUeywF7qQ46ER81irOdWS4QWxnnlAEsnzeBevk1sWh7fhpCghPpXb+8Ks7hvaft6L/xsR6g==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.1", + "array.prototype.flatmap": "^1.2.3", + "doctrine": "^2.1.0", + "has": "^1.0.3", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "object.entries": "^1.1.2", + "object.fromentries": "^2.0.2", + "object.values": "^1.1.1", + "prop-types": "^15.7.2", + "resolve": "^1.18.1", + "string.prototype.matchall": "^4.0.2" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "dev": true, + "dependencies": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", + "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/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": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/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/eslint/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/eslint/node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/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==", + "dev": true + }, + "node_modules/eslint/node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/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==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/esquery": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", + "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/event-stream": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", + "dependencies": { + "duplexer": "~0.1.1", + "from": "~0", + "map-stream": "~0.1.0", + "pause-stream": "0.0.11", + "split": "0.3", + "stream-combiner": "~0.0.4", + "through": "~2.3.1" + } + }, + "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=" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "dependencies": { + "flat-cache": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "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==", + "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", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "dev": true + }, + "node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "dependencies": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "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==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data/node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/from": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=" + }, + "node_modules/fs-readfile-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fs-readfile-promise/-/fs-readfile-promise-2.0.1.tgz", + "integrity": "sha1-gAI4I5gfn//+AWCei+Zo9prknnA=", + "dependencies": { + "graceful-fs": "^4.1.2" + } + }, + "node_modules/fs-writefile-promise": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fs-writefile-promise/-/fs-writefile-promise-1.0.3.tgz", + "integrity": "sha1-4C+bWP/CVe2CKtx6ARFPRF1I0GM=", + "dependencies": { + "mkdirp-promise": "^1.0.0", + "pinkie-promise": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/fs-writefile-promise/node_modules/pinkie-promise": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz", + "integrity": "sha1-0dpn9UglY7t89X8oauKCLs+/NnA=", + "dependencies": { + "pinkie": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "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.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "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, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic/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/get-own-enumerable-property-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.0.tgz", + "integrity": "sha512-CIJYJC4GGF06TakLg8z4GQKvDsx9EMspVxOYih7LerEL/WosUnFIww45CGfxfeKHqlg3twgUrYRT1O3WQqjGCg==" + }, + "node_modules/get-stdin": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", + "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "dev": true, + "dependencies": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "dependencies": { + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.1.15", + "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", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/handlebars/node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "node_modules/handlebars/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha1-HvievT5JllV2de7ZiTEQ3DUPoIA=", + "deprecated": "this library is no longer supported", + "dependencies": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "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", + "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", + "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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/is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "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==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "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-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/istanbul": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", + "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", + "deprecated": "This module is no longer maintained, try this instead:\n npm i nyc\nVisit https://istanbul.js.org/integrations for other alternatives.", + "dev": true, + "dependencies": { + "abbrev": "1.0.x", + "async": "1.x", + "escodegen": "1.8.x", + "esprima": "2.7.x", + "glob": "^5.0.15", + "handlebars": "^4.0.1", + "js-yaml": "3.x", + "mkdirp": "0.5.x", + "nopt": "3.x", + "once": "1.x", + "resolve": "1.1.x", + "supports-color": "^3.1.0", + "which": "^1.1.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "istanbul": "lib/cli.js" + } + }, + "node_modules/istanbul/node_modules/async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "node_modules/istanbul/node_modules/glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "dev": true, + "dependencies": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/istanbul/node_modules/supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "dependencies": { + "has-flag": "^1.0.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "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==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/js-yaml/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/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "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==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz", + "integrity": "sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.2", + "object.assign": "^4.1.2" + }, + "engines": { + "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", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lintspaces": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/lintspaces/-/lintspaces-0.6.3.tgz", + "integrity": "sha512-nUwq/jK+gUhpILtV9Ms2cuF16LB9a8nnecowSQD5LRNX3+h1Bl1zIvPZNQgJYeK9xxuoR+HuWnjagQsvyJbS4w==", + "dev": true, + "dependencies": { + "deep-extend": "^0.6.0", + "editorconfig": "^0.15.0", + "rc": "^1.2.8" + }, + "engines": { + "node": ">=5" + } + }, + "node_modules/load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "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==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/log-symbols/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": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "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==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/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/log-symbols/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/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/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==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/map-stream": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", + "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=" + }, + "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==", + "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==", + "dependencies": { + "mime-db": "1.40.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "node_modules/mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "dependencies": { + "minimist": "0.0.8" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mkdirp-promise": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mkdirp-promise/-/mkdirp-promise-1.1.0.tgz", + "integrity": "sha1-LISJPtZ24NmPsY+5piEv0bK5qBk=", + "deprecated": "This package is broken and no longer maintained. 'mkdirp' itself supports promises now, please switch to that.", + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "mkdirp": ">=0.5.0" + } + }, + "node_modules/mkdirp/node_modules/minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "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" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 10.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "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)", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/mocha/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "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", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "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" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/mocha/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true + }, + "node_modules/mocha/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "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" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "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", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/neo-async": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz", + "integrity": "sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==", + "dev": true + }, + "node_modules/nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "dev": true, + "dependencies": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "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", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.entries": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.3.tgz", + "integrity": "sha512-ym7h7OZebNS96hn5IJeyUmaWhaSM4SVtAPPfNLQEI2MYWCO2egsITb9nab2+i/Pwibx+R0mtn+ltKJXRSeTMGg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "has": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.3.tgz", + "integrity": "sha512-IDUSMXs6LOSJBWE++L0lzIbSqHl9KDCfff2x/JSEIDtEUavUnyMYC2ZGay/04Zq4UT8lvd4xNhU4/YHKibAOlw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "has": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.2.tgz", + "integrity": "sha512-MYC0jvJopr8EK6dPBiO8Nb9mvjdypOachO5REGk6MXzujbBrAisKo3HmdEI6kZDL6fC31Mwee/5YbtMebixeag==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "has": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "dependencies": { + "pify": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", + "dependencies": { + "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/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz", + "integrity": "sha1-Wkfyi6EBXQIBvae/DzWOR77Ix+Q=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pkg-conf": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-3.1.0.tgz", + "integrity": "sha512-m0OTbR/5VPNPqO1ph6Fqbj7Hv6QU7gR/tQW40ZqrL1rjgCU85W6C1bJn0BItuJqnR98PWzw7Z8hHeChD1WrgdQ==", + "dev": true, + "dependencies": { + "find-up": "^3.0.0", + "load-json-file": "^5.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-conf/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/pkg-conf/node_modules/load-json-file": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-5.3.0.tgz", + "integrity": "sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.15", + "parse-json": "^4.0.0", + "pify": "^4.0.1", + "strip-bom": "^3.0.0", + "type-fest": "^0.3.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-conf/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/pkg-conf/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/pkg-conf/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/pkg-conf/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/pkg-conf/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-conf/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-conf/node_modules/type-fest": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", + "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-config": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pkg-config/-/pkg-config-1.1.1.tgz", + "integrity": "sha1-VX7yLXPaPIg3EHdmxS6tq94pj+Q=", + "dev": true, + "dependencies": { + "debug-log": "^1.0.0", + "find-root": "^1.0.0", + "xtend": "^4.0.1" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "dependencies": { + "find-up": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "dev": true, + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, + "node_modules/read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "dependencies": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "dependencies": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "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==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", + "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true, + "engines": { + "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", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "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" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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 + }, + "node_modules/semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "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==", + "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", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/should": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz", + "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==", + "dev": true, + "dependencies": { + "should-equal": "^2.0.0", + "should-format": "^3.0.3", + "should-type": "^1.4.0", + "should-type-adaptors": "^1.0.1", + "should-util": "^1.0.0" + } + }, + "node_modules/should-equal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", + "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", + "dev": true, + "dependencies": { + "should-type": "^1.4.0" + } + }, + "node_modules/should-format": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", + "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", + "dev": true, + "dependencies": { + "should-type": "^1.3.0", + "should-type-adaptors": "^1.0.1" + } + }, + "node_modules/should-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", + "integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=", + "dev": true + }, + "node_modules/should-type-adaptors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz", + "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==", + "dev": true, + "dependencies": { + "should-type": "^1.3.0", + "should-util": "^1.0.0" + } + }, + "node_modules/should-util": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.0.tgz", + "integrity": "sha1-yYzaN0qmsZDfi6h8mInCtNtiAGM=", + "dev": true + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel/node_modules/object-inspect": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", + "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", + "dev": true + }, + "node_modules/slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/slice-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==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "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", + "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", + "dev": true, + "optional": true, + "dependencies": { + "amdefine": ">=0.0.4" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", + "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", + "dev": true + }, + "node_modules/split": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", + "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", + "dependencies": { + "through": "2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/standard": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/standard/-/standard-16.0.3.tgz", + "integrity": "sha512-70F7NH0hSkNXosXRltjSv6KpTAOkUkSfyu3ynyM5dtRUiLtR+yX9EGZ7RKwuGUqCJiX/cnkceVM6HTZ4JpaqDg==", + "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" + } + ], + "dependencies": { + "eslint": "~7.13.0", + "eslint-config-standard": "16.0.2", + "eslint-config-standard-jsx": "10.0.0", + "eslint-plugin-import": "~2.22.1", + "eslint-plugin-node": "~11.1.0", + "eslint-plugin-promise": "~4.2.1", + "eslint-plugin-react": "~7.21.5", + "standard-engine": "^14.0.1" + }, + "bin": { + "standard": "bin/cmd.js" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/standard-engine": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-14.0.1.tgz", + "integrity": "sha512-7FEzDwmHDOGva7r9ifOzD3BGdTbA7ujJ50afLVdW/tK14zQEptJjbFuUfn50irqdHDcTbNh0DTIoMPynMCXb0Q==", + "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" + } + ], + "dependencies": { + "get-stdin": "^8.0.0", + "minimist": "^1.2.5", + "pkg-conf": "^3.1.0", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8.10" + } + }, + "node_modules/standard-engine/node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "node_modules/stream-combiner": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", + "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", + "dependencies": { + "duplexer": "~0.1.1" + } + }, + "node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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=", + "dev": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.3.tgz", + "integrity": "sha512-OBxYDA2ifZQ2e13cP82dWFMaCV9CGF8GzmN4fljBVw5O5wep0lu4gacm1OL6MjROoUnB8VbkWRThqkV2YFLNxw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "has-symbols": "^1.0.1", + "internal-slot": "^1.0.2", + "regexp.prototype.flags": "^1.3.0", + "side-channel": "^1.0.3" + }, + "funding": { + "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/stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dependencies": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "dependencies": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "engines": { + "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", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true, + "engines": { + "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", + "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/table/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/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "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", + "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + } + }, + "node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/uglify-js": { + "version": "3.5.8", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.5.8.tgz", + "integrity": "sha512-GFSjB1nZIzoIq70qvDRtWRORHX3vFkAnyK/rDExc0BN7r9+/S+Voz3t/fwJuVfjppAMz+ceR2poE7tkhvnVwQQ==", + "dev": true, + "optional": true, + "dependencies": { + "commander": "~2.20.0", + "source-map": "~0.6.1" + }, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/uglify-js/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", + "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", + "dev": true + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "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", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "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==", + "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==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "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==", + "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/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==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "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": "4.0.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", + "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "dev": true + }, + "node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "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==", + "dev": true, + "dependencies": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "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" + } + }, + "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==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser/node_modules/camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs-unparser/node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "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", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, "dependencies": { "@babel/code-frame": { "version": "7.12.11", @@ -154,7 +4720,8 @@ "version": "5.3.1", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", - "dev": true + "dev": true, + "requires": {} }, "ajv": { "version": "6.10.0", @@ -245,21 +4812,6 @@ "function-bind": "^1.1.1" } }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "dev": true, - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - }, "astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", @@ -271,33 +4823,12 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true - }, - "aws4": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", - "dev": true - }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -351,12 +4882,6 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", @@ -424,35 +4949,6 @@ } } }, - "codeclimate-test-reporter": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/codeclimate-test-reporter/-/codeclimate-test-reporter-0.5.1.tgz", - "integrity": "sha512-XCzmc8dH+R4orK11BCg5pBbXc35abxq9sept4YvUFRkFl9zb9MIVRrCKENe6U1TKAMTgvGJmrYyHn0y2lerpmg==", - "dev": true, - "requires": { - "async": "~1.5.2", - "commander": "2.9.0", - "lcov-parse": "0.0.10", - "request": "~2.88.0" - }, - "dependencies": { - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "dev": true - }, - "commander": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", - "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", - "dev": true, - "requires": { - "graceful-readlink": ">= 1.0.0" - } - } - } - }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -468,15 +4964,6 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, - "combined-stream": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", - "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, "commander": { "version": "2.20.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", @@ -494,12 +4981,6 @@ "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", "dev": true }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -522,15 +5003,6 @@ } } }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -603,16 +5075,6 @@ "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=" }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, "echint": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/echint/-/echint-4.0.2.tgz", @@ -1003,13 +5465,15 @@ "version": "16.0.2", "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-16.0.2.tgz", "integrity": "sha512-fx3f1rJDsl9bY7qzyX8SAtP8GBSk6MfXFaTfaGgk12aAYW4gJSyRm7dM790L6cbXv63fvjY4XeSzXnb4WM+SKw==", - "dev": true + "dev": true, + "requires": {} }, "eslint-config-standard-jsx": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-10.0.0.tgz", "integrity": "sha512-hLeA2f5e06W1xyr/93/QJulN/rLbUVUmqTlexv9PRKHFwEC9ffJcH2LvJhMoEqYQBEYafedgGZXH2W8NUpt5lA==", - "dev": true + "dev": true, + "requires": {} }, "eslint-import-resolver-node": { "version": "0.3.4", @@ -1306,18 +5770,6 @@ "through": "~2.3.1" } }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true - }, "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", @@ -1390,12 +5842,6 @@ "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", "dev": true }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, "form-data": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", @@ -1509,15 +5955,6 @@ "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", "dev": true }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, "glob": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", @@ -1554,12 +5991,6 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" }, - "graceful-readlink": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", - "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", - "dev": true - }, "growl": { "version": "1.10.5", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", @@ -1648,17 +6079,6 @@ "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", @@ -1831,12 +6251,6 @@ "has-symbols": "^1.0.0" } }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -1849,12 +6263,6 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, "istanbul": { "version": "0.4.5", "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", @@ -1931,24 +6339,12 @@ } } }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true - }, "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true - }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -1960,12 +6356,6 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, "json5": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", @@ -1975,18 +6365,6 @@ "minimist": "^1.2.0" } }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, "jsx-ast-utils": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz", @@ -2017,12 +6395,6 @@ } } }, - "lcov-parse": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.10.tgz", - "integrity": "sha1-GwuP+ayceIklBYK3C3ExXZ2m2aM=", - "dev": true - }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -2188,7 +6560,6 @@ "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, "requires": { "minimist": "0.0.8" }, @@ -2196,15 +6567,15 @@ "minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" } } }, "mkdirp-promise": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/mkdirp-promise/-/mkdirp-promise-1.1.0.tgz", - "integrity": "sha1-LISJPtZ24NmPsY+5piEv0bK5qBk=" + "integrity": "sha1-LISJPtZ24NmPsY+5piEv0bK5qBk=", + "requires": {} }, "mocha": { "version": "8.2.1", @@ -2433,12 +6804,6 @@ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true - }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -2593,12 +6958,6 @@ "through": "~2.3" } }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, "picomatch": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", @@ -2755,23 +7114,11 @@ "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", "dev": true }, - "psl": { - "version": "1.1.31", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", - "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==", - "dev": true - }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "dev": true - }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -2845,47 +7192,6 @@ "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", "dev": true }, - "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - } - } - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -2941,12 +7247,6 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, "semver": { "version": "7.3.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", @@ -3166,23 +7466,6 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "dev": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, "standard": { "version": "16.0.3", "resolved": "https://registry.npmjs.org/standard/-/standard-16.0.3.tgz", @@ -3396,24 +7679,6 @@ "is-number": "^7.0.0" } }, - "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", - "dev": true, - "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - } - } - }, "tsconfig-paths": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", @@ -3426,21 +7691,6 @@ "strip-bom": "^3.0.0" } }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true - }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -3484,12 +7734,6 @@ "punycode": "^2.1.0" } }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", - "dev": true - }, "v8-compile-cache": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", @@ -3506,17 +7750,6 @@ "spdx-expression-parse": "^3.0.0" } }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", From 8a82fcbd873085fb417c2c1f99cdc1c5a596f41a Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Thu, 3 Feb 2022 15:32:18 +0100 Subject: [PATCH 24/83] 2.1.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 03abc83..9e36ade 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@httptoolkit/httpsnippet", - "version": "2.0.0", + "version": "2.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@httptoolkit/httpsnippet", - "version": "2.0.0", + "version": "2.1.0", "license": "MIT", "dependencies": { "chalk": "^1.1.1", diff --git a/package.json b/package.json index 00f8823..9a49e44 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "2.0.0", + "version": "2.1.0", "name": "@httptoolkit/httpsnippet", "description": "HTTP request snippet generator for *most* languages", "author": "Tim Perry ", From 2401900ba1fb04526d2e110cfaf15a119a024083 Mon Sep 17 00:00:00 2001 From: eeWynell Date: Thu, 17 Feb 2022 22:18:19 +0300 Subject: [PATCH 25/83] Add %v and %q options to format in CodeBuilder.buildLine and some handy indentation methods --- src/helpers/code-builder.js | 34 +++++++++++++++++++++--- src/helpers/format.js | 53 +++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 src/helpers/format.js diff --git a/src/helpers/code-builder.js b/src/helpers/code-builder.js index c1a75e8..ff7afdc 100644 --- a/src/helpers/code-builder.js +++ b/src/helpers/code-builder.js @@ -1,6 +1,6 @@ 'use strict' -const util = require('util') +const formatString = require('./format') /** * Helper object to format and aggragate lines of code. @@ -13,6 +13,7 @@ const util = require('util') */ const CodeBuilder = function (indentation, join) { this.code = [] + this.indentLevel = 0 this.indentation = indentation this.lineJoin = join || '\n' } @@ -42,7 +43,7 @@ CodeBuilder.prototype.buildLine = function (indentationLevel, line) { if (Object.prototype.toString.call(indentationLevel) === '[object String]') { slice = 1 line = indentationLevel - indentationLevel = 0 + indentationLevel = this.indentLevel } else if (indentationLevel === null) { return null } @@ -55,7 +56,7 @@ CodeBuilder.prototype.buildLine = function (indentationLevel, line) { const format = Array.prototype.slice.call(arguments, slice, arguments.length) format.unshift(lineIndentation + line) - return util.format.apply(this, format) + return formatString.apply(this, format) } /** @@ -100,4 +101,31 @@ CodeBuilder.prototype.join = function () { return this.code.join(this.lineJoin) } +/** + * Increase indentation level + * @returns {this} + */ +CodeBuilder.prototype.indent = function () { + this.indentLevel++ + return this +} + +/** + * Decrease indentation level + * @returns {this} + */ +CodeBuilder.prototype.unindent = function () { + this.indentLevel-- + return this +} + +/** + * Reset indentation level + * @returns {this} + */ +CodeBuilder.prototype.reindent = function () { + this.indentLevel = 0 + return this +} + module.exports = CodeBuilder diff --git a/src/helpers/format.js b/src/helpers/format.js new file mode 100644 index 0000000..551f26b --- /dev/null +++ b/src/helpers/format.js @@ -0,0 +1,53 @@ +const util = require('util') + +function quote (value) { + if (typeof value !== 'string') value = JSON.stringify(value) + return JSON.stringify(value) +} + +function escape (value) { + const q = quote(value) + return q && q.slice(1, -1) +} + +/** + * Wraps the `util.format` function and adds the %q and %v format options, + * where `%q` - escape tricky characters, like newline or quotes + * and `%v` - JSON-stringify-if-necessary + * + * @param {string} value + * @param {...string} format + * + * @example + * format('foo("%q")', { bar: 'baz' }) + * // output: foo("{\"bar\":\"baz\"}") + * + * format('foo(%v)', { bar: 'baz' }) + * // output: foo({"bar":"baz"}) + * + * @returns {string} Formatted string + */ +function format (value, ...format) { + if (typeof value !== 'string') return '' + + let i = 0 + value = value.replace(/(? { + // JSON-stringify + if (m === '%v') { + const [elem] = format.splice(i, 1) + return JSON.stringify(elem) + } + // JSON-stringify, remove quotes (means, escape) + if (m === '%q') { + const [elem] = format.splice(i, 1) + return escape(elem) + } + i += 1 + return m + }) + + const ret = util.format(value, ...format) + return ret +} + +module.exports = format From a10703297c8b03cbf62b8c5d282cbdf36596fa04 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Fri, 1 Jul 2022 14:41:13 +0200 Subject: [PATCH 26/83] Correctly escape single & double quotes within header values --- src/helpers/code-builder.js | 2 +- src/helpers/format.js | 85 ++++++++++++++----- src/targets/c/libcurl.js | 2 +- src/targets/csharp/httpclient.js | 2 +- src/targets/csharp/restsharp.js | 2 +- src/targets/go/native.js | 2 +- src/targets/java/asynchttp.js | 2 +- src/targets/java/nethttp.js | 2 +- src/targets/java/okhttp.js | 2 +- src/targets/java/unirest.js | 2 +- src/targets/kotlin/okhttp.js | 2 +- src/targets/ocaml/cohttp.js | 4 +- src/targets/php/curl.js | 8 +- src/targets/php/helpers.js | 4 +- src/targets/powershell/common.js | 3 +- src/targets/python/python3.js | 8 +- src/targets/python/requests.js | 6 +- src/targets/r/httr.js | 56 ++++++------ src/targets/ruby/native.js | 2 +- test/fixtures/output/c/libcurl/headers.c | 1 + .../output/clojure/clj_http/headers.clj | 3 +- .../output/csharp/httpclient/headers.cs | 1 + .../output/csharp/restsharp/headers.cs | 1 + test/fixtures/output/go/native/headers.go | 1 + test/fixtures/output/http/1.1/headers | 1 + .../output/java/asynchttp/headers.java | 1 + .../fixtures/output/java/nethttp/headers.java | 1 + test/fixtures/output/java/okhttp/headers.java | 1 + .../fixtures/output/java/unirest/headers.java | 1 + .../output/javascript/axios/headers.js | 6 +- .../output/javascript/fetch/headers.js | 9 +- .../output/javascript/jquery/headers.js | 3 +- .../fixtures/output/javascript/xhr/headers.js | 1 + test/fixtures/output/kotlin/okhttp/headers.kt | 1 + test/fixtures/output/node/axios/headers.js | 6 +- test/fixtures/output/node/fetch/headers.js | 9 +- test/fixtures/output/node/native/headers.js | 3 +- test/fixtures/output/node/request/headers.js | 6 +- test/fixtures/output/node/unirest/headers.js | 3 +- .../output/objc/nsurlsession/headers.m | 3 +- test/fixtures/output/ocaml/cohttp/headers.ml | 1 + test/fixtures/output/php/curl/headers.php | 1 + test/fixtures/output/php/http1/headers.php | 3 +- test/fixtures/output/php/http2/headers.php | 3 +- .../output/powershell/restmethod/headers.ps1 | 1 + .../output/powershell/webrequest/headers.ps1 | 1 + test/fixtures/output/python/python3/full.py | 2 +- .../fixtures/output/python/python3/headers.py | 5 +- .../output/python/requests/headers.py | 3 +- test/fixtures/output/r/httr/headers.r | 2 +- test/fixtures/output/ruby/native/headers.rb | 1 + test/fixtures/output/shell/curl/headers.sh | 1 + test/fixtures/output/shell/httpie/headers.sh | 1 + test/fixtures/output/shell/wget/headers.sh | 1 + .../output/swift/nsurlsession/headers.swift | 3 +- test/fixtures/requests/headers.json | 4 + test/index.js | 9 +- 57 files changed, 201 insertions(+), 99 deletions(-) diff --git a/src/helpers/code-builder.js b/src/helpers/code-builder.js index ff7afdc..62a8f21 100644 --- a/src/helpers/code-builder.js +++ b/src/helpers/code-builder.js @@ -1,6 +1,6 @@ 'use strict' -const formatString = require('./format') +const { format: formatString } = require('./format') /** * Helper object to format and aggragate lines of code. diff --git a/src/helpers/format.js b/src/helpers/format.js index 551f26b..4eecbf0 100644 --- a/src/helpers/format.js +++ b/src/helpers/format.js @@ -1,46 +1,87 @@ const util = require('util') -function quote (value) { - if (typeof value !== 'string') value = JSON.stringify(value) - return JSON.stringify(value) +exports.escape = function escape (value, options) { + // The JSON-stringify string serialization algorithm, but generalized for string delimiters + // (e.g. " or ') and different escape characters (e.g. Powershell uses `) + // https://tc39.es/ecma262/multipage/structured-data.html#sec-quotejsonstring + const { + delimiter = '"', + escapeChar = '\\', + escapeNewlines = true + } = options || {} + + return [...value].map((c) => { + if (c === '\b') { + return escapeChar + 'b' + } else if (c === '\t') { + return escapeChar + 't' + } else if (c === '\n') { + if (escapeNewlines) { + return escapeChar + 'n' + } else { + return c // Don't just continue, or this is caught by < \u0020 + } + } else if (c === '\f') { + return escapeChar + 'f' + } else if (c === '\r') { + if (escapeNewlines) { + return escapeChar + 'r' + } else { + return c // Don't just continue, or this is caught by < \u0020 + } + } else if (c === escapeChar) { + return escapeChar + escapeChar + } else if (c === delimiter) { + return escapeChar + delimiter + } else if (c < '\u0020' || c > '\u007E') { + // Delegate the trickier non-ASCII cases to the normal algorithm. Some of these are escaped as + // \uXXXX, whilst others are represented literally. Since we're using this primarily for header + // values that are generally (though not strictly?) ASCII-only, this should almost never happen. + return JSON.stringify(c).slice(1, -1) + } else { + return c + } + }).join('') } -function escape (value) { - const q = quote(value) - return q && q.slice(1, -1) +function doubleQuoteEscape (value) { + return exports.escape(value, { delimiter: '"' }) +} + +function singleQuoteEscape (value) { + return exports.escape(value, { delimiter: "'" }) } /** - * Wraps the `util.format` function and adds the %q and %v format options, - * where `%q` - escape tricky characters, like newline or quotes - * and `%v` - JSON-stringify-if-necessary + * Wraps the `util.format` function and adds the %qd, %qs and %v format options, + * where `%qd` escapes characters for a single-line double-quoted string, `%qs` + * escapes characters for a single-line single-quoted string, and `%v` + * JSON-stringifies the value. * * @param {string} value * @param {...string} format * - * @example - * format('foo("%q")', { bar: 'baz' }) - * // output: foo("{\"bar\":\"baz\"}") - * - * format('foo(%v)', { bar: 'baz' }) - * // output: foo({"bar":"baz"}) - * * @returns {string} Formatted string */ -function format (value, ...format) { +exports.format = function format (value, ...format) { if (typeof value !== 'string') return '' let i = 0 - value = value.replace(/(? { + value = value.replace(/(? { // JSON-stringify if (m === '%v') { const [elem] = format.splice(i, 1) return JSON.stringify(elem) } - // JSON-stringify, remove quotes (means, escape) - if (m === '%q') { + // Escape for double-quoted string + if (m === '%qd') { + const [elem] = format.splice(i, 1) + return doubleQuoteEscape(elem) + } + // Escape for single-quoted string + if (m === '%qs') { const [elem] = format.splice(i, 1) - return escape(elem) + return singleQuoteEscape(elem) } i += 1 return m @@ -49,5 +90,3 @@ function format (value, ...format) { const ret = util.format(value, ...format) return ret } - -module.exports = format diff --git a/src/targets/c/libcurl.js b/src/targets/c/libcurl.js index 1609074..be3a218 100644 --- a/src/targets/c/libcurl.js +++ b/src/targets/c/libcurl.js @@ -19,7 +19,7 @@ module.exports = function (source, options) { .push('struct curl_slist *headers = NULL;') headers.forEach(function (key) { - code.push('headers = curl_slist_append(headers, "%s: %s");', key, source.headersObj[key]) + code.push('headers = curl_slist_append(headers, "%s: %qd");', key, source.headersObj[key]) }) code.push('curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers);') diff --git a/src/targets/csharp/httpclient.js b/src/targets/csharp/httpclient.js index 8523a00..1df3e0b 100644 --- a/src/targets/csharp/httpclient.js +++ b/src/targets/csharp/httpclient.js @@ -85,7 +85,7 @@ module.exports = function (source, options) { code.push(1, 'Headers =') code.push(1, '{') headers.forEach(function (key) { - code.push(2, '{ "%s", "%s" },', key, source.allHeaders[key]) + code.push(2, '{ "%s", "%qd" },', key, source.allHeaders[key]) }) code.push(1, '},') } diff --git a/src/targets/csharp/restsharp.js b/src/targets/csharp/restsharp.js index d724c36..373f996 100644 --- a/src/targets/csharp/restsharp.js +++ b/src/targets/csharp/restsharp.js @@ -20,7 +20,7 @@ module.exports = function (source, options) { // construct headers if (headers.length) { headers.forEach(function (key) { - code.push('request.AddHeader("%s", "%s");', key, source.headersObj[key]) + code.push('request.AddHeader("%s", "%qd");', key, source.headersObj[key]) }) } diff --git a/src/targets/go/native.js b/src/targets/go/native.js index 93812bb..4f43d0f 100644 --- a/src/targets/go/native.js +++ b/src/targets/go/native.js @@ -112,7 +112,7 @@ module.exports = function (source, options) { // Add headers if (Object.keys(source.allHeaders).length) { Object.keys(source.allHeaders).forEach(function (key) { - code.push(indent, 'req.Header.Add("%s", "%s")', key, source.allHeaders[key]) + code.push(indent, 'req.Header.Add("%s", "%qd")', key, source.allHeaders[key]) }) code.blank() diff --git a/src/targets/java/asynchttp.js b/src/targets/java/asynchttp.js index ce3db5d..fd0957b 100644 --- a/src/targets/java/asynchttp.js +++ b/src/targets/java/asynchttp.js @@ -29,7 +29,7 @@ module.exports = function (source, options) { // construct headers if (headers.length) { headers.forEach(function (key) { - code.push(1, '.setHeader("%s", "%s")', key, source.allHeaders[key]) + code.push(1, '.setHeader("%s", "%qd")', key, source.allHeaders[key]) }) } diff --git a/src/targets/java/nethttp.js b/src/targets/java/nethttp.js index 328eeaa..5a81181 100644 --- a/src/targets/java/nethttp.js +++ b/src/targets/java/nethttp.js @@ -30,7 +30,7 @@ module.exports = function (source, options) { // construct headers if (headers.length) { headers.forEach(function (key) { - code.push(2, '.header("%s", "%s")', key, source.allHeaders[key]) + code.push(2, '.header("%s", "%qd")', key, source.allHeaders[key]) }) } diff --git a/src/targets/java/okhttp.js b/src/targets/java/okhttp.js index 3dc7564..b5c8d62 100644 --- a/src/targets/java/okhttp.js +++ b/src/targets/java/okhttp.js @@ -59,7 +59,7 @@ module.exports = function (source, options) { // construct headers if (headers.length) { headers.forEach(function (key) { - code.push(1, '.addHeader("%s", "%s")', key, source.allHeaders[key]) + code.push(1, '.addHeader("%s", "%qd")', key, source.allHeaders[key]) }) } diff --git a/src/targets/java/unirest.js b/src/targets/java/unirest.js index 7def78e..e449b52 100644 --- a/src/targets/java/unirest.js +++ b/src/targets/java/unirest.js @@ -33,7 +33,7 @@ module.exports = function (source, options) { // construct headers if (headers.length) { headers.forEach(function (key) { - code.push(1, '.header("%s", "%s")', key, source.allHeaders[key]) + code.push(1, '.header("%s", "%qd")', key, source.allHeaders[key]) }) } diff --git a/src/targets/kotlin/okhttp.js b/src/targets/kotlin/okhttp.js index 8c13905..8be95db 100644 --- a/src/targets/kotlin/okhttp.js +++ b/src/targets/kotlin/okhttp.js @@ -59,7 +59,7 @@ module.exports = function (source, options) { // construct headers if (headers.length) { headers.forEach(function (key) { - code.push(1, '.addHeader("%s", "%s")', key, source.allHeaders[key]) + code.push(1, '.addHeader("%s", "%qd")', key, source.allHeaders[key]) }) } diff --git a/src/targets/ocaml/cohttp.js b/src/targets/ocaml/cohttp.js index 76e2335..6abbcb0 100644 --- a/src/targets/ocaml/cohttp.js +++ b/src/targets/ocaml/cohttp.js @@ -30,12 +30,12 @@ module.exports = function (source, options) { const headers = Object.keys(source.allHeaders) if (headers.length === 1) { - code.push('let headers = Header.add (Header.init ()) "%s" "%s" in', headers[0], source.allHeaders[headers[0]]) + code.push('let headers = Header.add (Header.init ()) "%s" "%qd" in', headers[0], source.allHeaders[headers[0]]) } else if (headers.length > 1) { code.push('let headers = Header.add_list (Header.init ()) [') headers.forEach(function (key) { - code.push(1, '("%s", "%s");', key, source.allHeaders[key]) + code.push(1, '("%s", "%qd");', key, source.allHeaders[key]) }) code.push('] in') diff --git a/src/targets/php/curl.js b/src/targets/php/curl.js index 1a7b6a8..50a2e0f 100644 --- a/src/targets/php/curl.js +++ b/src/targets/php/curl.js @@ -10,7 +10,7 @@ 'use strict' -const util = require('util') +const { format } = require('../../helpers/format') const CodeBuilder = require('../../helpers/code-builder') module.exports = function (source, options) { @@ -78,7 +78,7 @@ module.exports = function (source, options) { curlOptions.forEach(function (option) { if (!~[null, undefined].indexOf(option.value)) { - curlopts.push(util.format('%s => %s,', option.name, option.escape ? JSON.stringify(option.value) : option.value)) + curlopts.push(format('%s => %s,', option.name, option.escape ? JSON.stringify(option.value) : option.value)) } }) @@ -88,12 +88,12 @@ module.exports = function (source, options) { }) if (cookies.length) { - curlopts.push(util.format('CURLOPT_COOKIE => "%s",', cookies.join('; '))) + curlopts.push(format('CURLOPT_COOKIE => "%s",', cookies.join('; '))) } // construct cookies const headers = Object.keys(source.headersObj).sort().map(function (key) { - return util.format('"%s: %s"', key, source.headersObj[key]) + return format('"%s: %qd"', key, source.headersObj[key]) }) if (headers.length) { diff --git a/src/targets/php/helpers.js b/src/targets/php/helpers.js index 266d72b..0e833fa 100644 --- a/src/targets/php/helpers.js +++ b/src/targets/php/helpers.js @@ -1,5 +1,7 @@ 'use strict' +const { escape } = require('../../helpers/format') + const convert = function (obj, indent, lastIndent) { let i, result @@ -17,7 +19,7 @@ const convert = function (obj, indent, lastIndent) { break case '[object String]': - result = "'" + obj.replace(/\\/g, '\\\\').replace(/'/g, "'") + "'" + result = "'" + escape(obj, { delimiter: "'", escapeNewlines: false }) + "'" break case '[object Number]': diff --git a/src/targets/powershell/common.js b/src/targets/powershell/common.js index e6c53a5..fd32b85 100644 --- a/src/targets/powershell/common.js +++ b/src/targets/powershell/common.js @@ -1,6 +1,7 @@ 'use strict' const CodeBuilder = require('../../helpers/code-builder') +const { escape } = require('../../helpers/format') const helpers = require('../../helpers/headers') module.exports = function (command) { @@ -22,7 +23,7 @@ module.exports = function (command) { code.push('$headers=@{}') headers.forEach(function (key) { if (key !== 'connection') { // Not allowed - code.push('$headers.Add("%s", "%s")', key, source.headersObj[key]) + code.push('$headers.Add("%s", "%s")', key, escape(source.headersObj[key], { escapeChar: '`' })) } }) commandOptions.push('-Headers $headers') diff --git a/src/targets/python/python3.js b/src/targets/python/python3.js index 550b650..35ac961 100644 --- a/src/targets/python/python3.js +++ b/src/targets/python/python3.js @@ -52,7 +52,7 @@ module.exports = function (source, options) { const headerCount = Object.keys(headers).length if (headerCount === 1) { for (const header in headers) { - code.push('headers = { "%s": "%s" }', header, headers[header]) + code.push('headers = { "%s": "%qd" }', header, headers[header]) .blank() } } else if (headerCount > 1) { @@ -62,13 +62,13 @@ module.exports = function (source, options) { for (const header in headers) { if (count++ !== headerCount) { - code.push(' "%s": "%s",', header, headers[header]) + code.push(' "%s": "%qd",', header, headers[header]) } else { - code.push(' "%s": "%s"', header, headers[header]) + code.push(' "%s": "%qd"', header, headers[header]) } } - code.push(' }') + code.push('}') .blank() } diff --git a/src/targets/python/requests.js b/src/targets/python/requests.js index 394656f..1938f97 100644 --- a/src/targets/python/requests.js +++ b/src/targets/python/requests.js @@ -85,7 +85,7 @@ module.exports = function (source, options) { if (headerCount === 1) { for (const header in headers) { - code.push('headers = { "%s": "%s" }', header, headers[header]) + code.push('headers = { "%s": "%qd" }', header, headers[header]) .blank() } } else if (headerCount > 1) { @@ -95,9 +95,9 @@ module.exports = function (source, options) { for (const header in headers) { if (count++ !== headerCount) { - code.push(1, '"%s": "%s",', header, headers[header]) + code.push(1, '"%s": "%qd",', header, headers[header]) } else { - code.push(1, '"%s": "%s"', header, headers[header]) + code.push(1, '"%s": "%qd"', header, headers[header]) } } diff --git a/src/targets/r/httr.js b/src/targets/r/httr.js index db68df2..5a7f557 100644 --- a/src/targets/r/httr.js +++ b/src/targets/r/httr.js @@ -11,6 +11,8 @@ 'use strict' const util = require('util') +const { escape } = require('../../helpers/format') +const { getHeader } = require('../../helpers/headers') const CodeBuilder = require('../../helpers/code-builder') module.exports = function (source, options) { @@ -84,24 +86,28 @@ module.exports = function (source, options) { } // Construct headers - const headers = source.allHeaders - let headerCount = Object.keys(headers).length - let header = '' - let cookies - let accept - - for (const head in headers) { - if (head.toLowerCase() === 'accept') { - accept = ', accept("' + headers[head] + '")' - headerCount = headerCount - 1 - } else if (head.toLowerCase() === 'cookie') { - cookies = ', set_cookies(`' + headers[head].replace(/;/g, '", `').replace(/` /g, '`').replace(/=/g, '` = "') + '")' - headerCount = headerCount - 1 - } else if (head.toLowerCase() !== 'content-type') { - header = header + head.replace('-', '_') + " = '" + headers[head] - if (headerCount > 1) { header = header + "', " } - } - } + const cookieHeader = getHeader(source.allHeaders, 'cookie') + const acceptHeader = getHeader(source.allHeaders, 'accept') + + const setCookies = cookieHeader + ? 'set_cookies(`' + cookieHeader.replace(/;/g, '", `').replace(/` /g, '`').replace(/=/g, '` = "') + '")' + : undefined + + const setAccept = acceptHeader + ? `accept("${escape(acceptHeader)}")` + : undefined + + const setContentType = 'content_type("' + source.postData.mimeType + '")' + + 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: "'" })}'`) + .join(', ') + + const setHeaders = otherHeaders + ? `add_headers(${otherHeaders})` + : undefined // Construct request const method = source.method @@ -111,22 +117,14 @@ module.exports = function (source, options) { request += ', body = payload' } - if (header !== '') { - request += ', add_headers(' + header + "')" - } - if (source.queryString.length) { request += ', query = queryString' } - request += ', content_type("' + source.postData.mimeType + '")' - - if (typeof accept !== 'undefined') { - request += accept - } + const headerAdditions = [setHeaders, setContentType, setAccept, setCookies].filter(x => !!x).join(', ') - if (typeof cookies !== 'undefined') { - request += cookies + if (headerAdditions) { + request += ', ' + headerAdditions } if (source.postData.text || source.postData.jsonObj || source.postData.params) { diff --git a/src/targets/ruby/native.js b/src/targets/ruby/native.js index e6d7fa7..7316135 100644 --- a/src/targets/ruby/native.js +++ b/src/targets/ruby/native.js @@ -46,7 +46,7 @@ module.exports = function (source, options) { const headers = Object.keys(source.allHeaders) if (headers.length) { headers.forEach(function (key) { - code.push('request["%s"] = \'%s\'', key, source.allHeaders[key]) + code.push('request["%s"] = \'%qs\'', key, source.allHeaders[key]) }) } diff --git a/test/fixtures/output/c/libcurl/headers.c b/test/fixtures/output/c/libcurl/headers.c index 54ed7a8..d4cb770 100644 --- a/test/fixtures/output/c/libcurl/headers.c +++ b/test/fixtures/output/c/libcurl/headers.c @@ -6,6 +6,7 @@ curl_easy_setopt(hnd, CURLOPT_URL, "http://mockbin.com/har"); struct curl_slist *headers = NULL; headers = curl_slist_append(headers, "accept: application/json"); headers = curl_slist_append(headers, "x-foo: Bar"); +headers = curl_slist_append(headers, "quoted-value: \"quoted\" 'string'"); curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers); CURLcode ret = curl_easy_perform(hnd); diff --git a/test/fixtures/output/clojure/clj_http/headers.clj b/test/fixtures/output/clojure/clj_http/headers.clj index d2816fb..ebe5d7f 100644 --- a/test/fixtures/output/clojure/clj_http/headers.clj +++ b/test/fixtures/output/clojure/clj_http/headers.clj @@ -1,4 +1,5 @@ (require '[clj-http.client :as client]) -(client/get "http://mockbin.com/har" {:headers {:x-foo "Bar"} +(client/get "http://mockbin.com/har" {:headers {:x-foo "Bar" + :quoted-value "\"quoted\" 'string'"} :accept :json}) diff --git a/test/fixtures/output/csharp/httpclient/headers.cs b/test/fixtures/output/csharp/httpclient/headers.cs index ad317d7..e63b8de 100644 --- a/test/fixtures/output/csharp/httpclient/headers.cs +++ b/test/fixtures/output/csharp/httpclient/headers.cs @@ -7,6 +7,7 @@ { { "accept", "application/json" }, { "x-foo", "Bar" }, + { "quoted-value", "\"quoted\" 'string'" }, }, }; using (var response = await client.SendAsync(request)) diff --git a/test/fixtures/output/csharp/restsharp/headers.cs b/test/fixtures/output/csharp/restsharp/headers.cs index e338bb1..febda66 100644 --- a/test/fixtures/output/csharp/restsharp/headers.cs +++ b/test/fixtures/output/csharp/restsharp/headers.cs @@ -2,4 +2,5 @@ var request = new RestRequest(Method.GET); request.AddHeader("accept", "application/json"); request.AddHeader("x-foo", "Bar"); +request.AddHeader("quoted-value", "\"quoted\" 'string'"); IRestResponse response = client.Execute(request); diff --git a/test/fixtures/output/go/native/headers.go b/test/fixtures/output/go/native/headers.go index 0d09039..00af29b 100644 --- a/test/fixtures/output/go/native/headers.go +++ b/test/fixtures/output/go/native/headers.go @@ -14,6 +14,7 @@ func main() { req.Header.Add("accept", "application/json") req.Header.Add("x-foo", "Bar") + req.Header.Add("quoted-value", "\"quoted\" 'string'") res, _ := http.DefaultClient.Do(req) diff --git a/test/fixtures/output/http/1.1/headers b/test/fixtures/output/http/1.1/headers index 7bde2bc..ad12eff 100644 --- a/test/fixtures/output/http/1.1/headers +++ b/test/fixtures/output/http/1.1/headers @@ -1,6 +1,7 @@ GET /har HTTP/1.1 Accept: application/json X-Foo: Bar +Quoted-Value: "quoted" 'string' Host: mockbin.com diff --git a/test/fixtures/output/java/asynchttp/headers.java b/test/fixtures/output/java/asynchttp/headers.java index 472fe09..69a96ed 100644 --- a/test/fixtures/output/java/asynchttp/headers.java +++ b/test/fixtures/output/java/asynchttp/headers.java @@ -2,6 +2,7 @@ client.prepare("GET", "http://mockbin.com/har") .setHeader("accept", "application/json") .setHeader("x-foo", "Bar") + .setHeader("quoted-value", "\"quoted\" 'string'") .execute() .toCompletableFuture() .thenAccept(System.out::println) diff --git a/test/fixtures/output/java/nethttp/headers.java b/test/fixtures/output/java/nethttp/headers.java index 2e8a09f..db666ed 100644 --- a/test/fixtures/output/java/nethttp/headers.java +++ b/test/fixtures/output/java/nethttp/headers.java @@ -2,6 +2,7 @@ .uri(URI.create("http://mockbin.com/har")) .header("accept", "application/json") .header("x-foo", "Bar") + .header("quoted-value", "\"quoted\" 'string'") .method("GET", HttpRequest.BodyPublishers.noBody()) .build(); HttpResponse response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()); diff --git a/test/fixtures/output/java/okhttp/headers.java b/test/fixtures/output/java/okhttp/headers.java index 081a33a..c2182bd 100644 --- a/test/fixtures/output/java/okhttp/headers.java +++ b/test/fixtures/output/java/okhttp/headers.java @@ -5,6 +5,7 @@ .get() .addHeader("accept", "application/json") .addHeader("x-foo", "Bar") + .addHeader("quoted-value", "\"quoted\" 'string'") .build(); Response response = client.newCall(request).execute(); diff --git a/test/fixtures/output/java/unirest/headers.java b/test/fixtures/output/java/unirest/headers.java index 142cf4e..6ab80f8 100644 --- a/test/fixtures/output/java/unirest/headers.java +++ b/test/fixtures/output/java/unirest/headers.java @@ -1,4 +1,5 @@ HttpResponse response = Unirest.get("http://mockbin.com/har") .header("accept", "application/json") .header("x-foo", "Bar") + .header("quoted-value", "\"quoted\" 'string'") .asString(); diff --git a/test/fixtures/output/javascript/axios/headers.js b/test/fixtures/output/javascript/axios/headers.js index 1db8b5b..3270a35 100644 --- a/test/fixtures/output/javascript/axios/headers.js +++ b/test/fixtures/output/javascript/axios/headers.js @@ -3,7 +3,11 @@ import axios from "axios"; const options = { method: 'GET', url: 'http://mockbin.com/har', - headers: {accept: 'application/json', 'x-foo': 'Bar'} + headers: { + accept: 'application/json', + 'x-foo': 'Bar', + 'quoted-value': '"quoted" \'string\'' + } }; axios.request(options).then(function (response) { diff --git a/test/fixtures/output/javascript/fetch/headers.js b/test/fixtures/output/javascript/fetch/headers.js index 583e54c..7948289 100644 --- a/test/fixtures/output/javascript/fetch/headers.js +++ b/test/fixtures/output/javascript/fetch/headers.js @@ -1,4 +1,11 @@ -const options = {method: 'GET', headers: {accept: 'application/json', 'x-foo': 'Bar'}}; +const options = { + method: 'GET', + headers: { + accept: 'application/json', + 'x-foo': 'Bar', + 'quoted-value': '"quoted" \'string\'' + } +}; fetch('http://mockbin.com/har', options) .then(response => response.json()) diff --git a/test/fixtures/output/javascript/jquery/headers.js b/test/fixtures/output/javascript/jquery/headers.js index 17652fa..fd6840a 100644 --- a/test/fixtures/output/javascript/jquery/headers.js +++ b/test/fixtures/output/javascript/jquery/headers.js @@ -5,7 +5,8 @@ const settings = { "method": "GET", "headers": { "accept": "application/json", - "x-foo": "Bar" + "x-foo": "Bar", + "quoted-value": "\"quoted\" 'string'" } }; diff --git a/test/fixtures/output/javascript/xhr/headers.js b/test/fixtures/output/javascript/xhr/headers.js index 511c4ab..2ceeb6d 100644 --- a/test/fixtures/output/javascript/xhr/headers.js +++ b/test/fixtures/output/javascript/xhr/headers.js @@ -12,5 +12,6 @@ xhr.addEventListener("readystatechange", function () { xhr.open("GET", "http://mockbin.com/har"); xhr.setRequestHeader("accept", "application/json"); xhr.setRequestHeader("x-foo", "Bar"); +xhr.setRequestHeader("quoted-value", "\"quoted\" 'string'"); xhr.send(data); diff --git a/test/fixtures/output/kotlin/okhttp/headers.kt b/test/fixtures/output/kotlin/okhttp/headers.kt index 780e580..e404958 100644 --- a/test/fixtures/output/kotlin/okhttp/headers.kt +++ b/test/fixtures/output/kotlin/okhttp/headers.kt @@ -5,6 +5,7 @@ val request = Request.Builder() .get() .addHeader("accept", "application/json") .addHeader("x-foo", "Bar") + .addHeader("quoted-value", "\"quoted\" 'string'") .build() val response = client.newCall(request).execute() diff --git a/test/fixtures/output/node/axios/headers.js b/test/fixtures/output/node/axios/headers.js index 2dbe470..0955cbd 100644 --- a/test/fixtures/output/node/axios/headers.js +++ b/test/fixtures/output/node/axios/headers.js @@ -3,7 +3,11 @@ var axios = require("axios").default; var options = { method: 'GET', url: 'http://mockbin.com/har', - headers: {accept: 'application/json', 'x-foo': 'Bar'} + headers: { + accept: 'application/json', + 'x-foo': 'Bar', + 'quoted-value': '"quoted" \'string\'' + } }; axios.request(options).then(function (response) { diff --git a/test/fixtures/output/node/fetch/headers.js b/test/fixtures/output/node/fetch/headers.js index 7fa2948..09f7fd2 100644 --- a/test/fixtures/output/node/fetch/headers.js +++ b/test/fixtures/output/node/fetch/headers.js @@ -2,7 +2,14 @@ const fetch = require('node-fetch'); let url = 'http://mockbin.com/har'; -let options = {method: 'GET', headers: {accept: 'application/json', 'x-foo': 'Bar'}}; +let options = { + method: 'GET', + headers: { + accept: 'application/json', + 'x-foo': 'Bar', + 'quoted-value': '"quoted" \'string\'' + } +}; fetch(url, options) .then(res => res.json()) diff --git a/test/fixtures/output/node/native/headers.js b/test/fixtures/output/node/native/headers.js index a36dfc9..940deb5 100644 --- a/test/fixtures/output/node/native/headers.js +++ b/test/fixtures/output/node/native/headers.js @@ -7,7 +7,8 @@ const options = { "path": "/har", "headers": { "accept": "application/json", - "x-foo": "Bar" + "x-foo": "Bar", + "quoted-value": "\"quoted\" 'string'" } }; diff --git a/test/fixtures/output/node/request/headers.js b/test/fixtures/output/node/request/headers.js index a30e3fb..b33229b 100644 --- a/test/fixtures/output/node/request/headers.js +++ b/test/fixtures/output/node/request/headers.js @@ -3,7 +3,11 @@ const request = require('request'); const options = { method: 'GET', url: 'http://mockbin.com/har', - headers: {accept: 'application/json', 'x-foo': 'Bar'} + headers: { + accept: 'application/json', + 'x-foo': 'Bar', + 'quoted-value': '"quoted" \'string\'' + } }; request(options, function (error, response, body) { diff --git a/test/fixtures/output/node/unirest/headers.js b/test/fixtures/output/node/unirest/headers.js index a9e1939..0808629 100644 --- a/test/fixtures/output/node/unirest/headers.js +++ b/test/fixtures/output/node/unirest/headers.js @@ -4,7 +4,8 @@ const req = unirest("GET", "http://mockbin.com/har"); req.headers({ "accept": "application/json", - "x-foo": "Bar" + "x-foo": "Bar", + "quoted-value": "\"quoted\" 'string'" }); req.end(function (res) { diff --git a/test/fixtures/output/objc/nsurlsession/headers.m b/test/fixtures/output/objc/nsurlsession/headers.m index 1d226ff..aec7198 100644 --- a/test/fixtures/output/objc/nsurlsession/headers.m +++ b/test/fixtures/output/objc/nsurlsession/headers.m @@ -1,7 +1,8 @@ #import NSDictionary *headers = @{ @"accept": @"application/json", - @"x-foo": @"Bar" }; + @"x-foo": @"Bar", + @"quoted-value": @"\"quoted\" 'string'" }; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://mockbin.com/har"] cachePolicy:NSURLRequestUseProtocolCachePolicy diff --git a/test/fixtures/output/ocaml/cohttp/headers.ml b/test/fixtures/output/ocaml/cohttp/headers.ml index 6755d5a..05f86ee 100644 --- a/test/fixtures/output/ocaml/cohttp/headers.ml +++ b/test/fixtures/output/ocaml/cohttp/headers.ml @@ -6,6 +6,7 @@ let uri = Uri.of_string "http://mockbin.com/har" in let headers = Header.add_list (Header.init ()) [ ("accept", "application/json"); ("x-foo", "Bar"); + ("quoted-value", "\"quoted\" 'string'"); ] in Client.call ~headers `GET uri diff --git a/test/fixtures/output/php/curl/headers.php b/test/fixtures/output/php/curl/headers.php index 4e8be5a..d0d4bb7 100644 --- a/test/fixtures/output/php/curl/headers.php +++ b/test/fixtures/output/php/curl/headers.php @@ -12,6 +12,7 @@ CURLOPT_CUSTOMREQUEST => "GET", CURLOPT_HTTPHEADER => [ "accept: application/json", + "quoted-value: \"quoted\" 'string'", "x-foo: Bar" ], ]); diff --git a/test/fixtures/output/php/http1/headers.php b/test/fixtures/output/php/http1/headers.php index 8f819c7..7c2fa3b 100644 --- a/test/fixtures/output/php/http1/headers.php +++ b/test/fixtures/output/php/http1/headers.php @@ -6,7 +6,8 @@ $request->setHeaders([ 'accept' => 'application/json', - 'x-foo' => 'Bar' + 'x-foo' => 'Bar', + 'quoted-value' => '"quoted" \'string\'' ]); try { diff --git a/test/fixtures/output/php/http2/headers.php b/test/fixtures/output/php/http2/headers.php index 712a027..cfa3688 100644 --- a/test/fixtures/output/php/http2/headers.php +++ b/test/fixtures/output/php/http2/headers.php @@ -7,7 +7,8 @@ $request->setRequestMethod('GET'); $request->setHeaders([ 'accept' => 'application/json', - 'x-foo' => 'Bar' + 'x-foo' => 'Bar', + 'quoted-value' => '"quoted" \'string\'' ]); $client->enqueue($request)->send(); diff --git a/test/fixtures/output/powershell/restmethod/headers.ps1 b/test/fixtures/output/powershell/restmethod/headers.ps1 index 7b2d929..5f81709 100644 --- a/test/fixtures/output/powershell/restmethod/headers.ps1 +++ b/test/fixtures/output/powershell/restmethod/headers.ps1 @@ -1,4 +1,5 @@ $headers=@{} $headers.Add("accept", "application/json") $headers.Add("x-foo", "Bar") +$headers.Add("quoted-value", "`"quoted`" 'string'") $response = Invoke-RestMethod -Uri 'http://mockbin.com/har' -Method GET -Headers $headers diff --git a/test/fixtures/output/powershell/webrequest/headers.ps1 b/test/fixtures/output/powershell/webrequest/headers.ps1 index a6a817e..03d1296 100644 --- a/test/fixtures/output/powershell/webrequest/headers.ps1 +++ b/test/fixtures/output/powershell/webrequest/headers.ps1 @@ -1,4 +1,5 @@ $headers=@{} $headers.Add("accept", "application/json") $headers.Add("x-foo", "Bar") +$headers.Add("quoted-value", "`"quoted`" 'string'") $response = Invoke-WebRequest -Uri 'http://mockbin.com/har' -Method GET -Headers $headers diff --git a/test/fixtures/output/python/python3/full.py b/test/fixtures/output/python/python3/full.py index 75131d7..38c2dbb 100644 --- a/test/fixtures/output/python/python3/full.py +++ b/test/fixtures/output/python/python3/full.py @@ -8,7 +8,7 @@ "cookie": "foo=bar; bar=baz", "accept": "application/json", "content-type": "application/x-www-form-urlencoded" - } +} conn.request("POST", "/har?foo=bar&foo=baz&baz=abc&key=value", payload, headers) diff --git a/test/fixtures/output/python/python3/headers.py b/test/fixtures/output/python/python3/headers.py index 6de1d8a..60182d7 100644 --- a/test/fixtures/output/python/python3/headers.py +++ b/test/fixtures/output/python/python3/headers.py @@ -4,8 +4,9 @@ headers = { "accept": "application/json", - "x-foo": "Bar" - } + "x-foo": "Bar", + "quoted-value": "\"quoted\" 'string'" +} conn.request("GET", "/har", headers=headers) diff --git a/test/fixtures/output/python/requests/headers.py b/test/fixtures/output/python/requests/headers.py index 8da4089..d2e3b3f 100644 --- a/test/fixtures/output/python/requests/headers.py +++ b/test/fixtures/output/python/requests/headers.py @@ -4,7 +4,8 @@ headers = { "accept": "application/json", - "x-foo": "Bar" + "x-foo": "Bar", + "quoted-value": "\"quoted\" 'string'" } response = requests.get(url, headers=headers) diff --git a/test/fixtures/output/r/httr/headers.r b/test/fixtures/output/r/httr/headers.r index 26a20cb..2694465 100644 --- a/test/fixtures/output/r/httr/headers.r +++ b/test/fixtures/output/r/httr/headers.r @@ -2,6 +2,6 @@ library(httr) url <- "http://mockbin.com/har" -response <- VERB("GET", url, add_headers(x_foo = 'Bar'), content_type("application/octet-stream"), accept("application/json")) +response <- VERB("GET", url, add_headers(x_foo = 'Bar', quoted_value = '"quoted" \'string\''), content_type("application/octet-stream"), accept("application/json")) content(response, "text") diff --git a/test/fixtures/output/ruby/native/headers.rb b/test/fixtures/output/ruby/native/headers.rb index f2a4dba..82219f4 100644 --- a/test/fixtures/output/ruby/native/headers.rb +++ b/test/fixtures/output/ruby/native/headers.rb @@ -8,6 +8,7 @@ request = Net::HTTP::Get.new(url) request["accept"] = 'application/json' request["x-foo"] = 'Bar' +request["quoted-value"] = '"quoted" \'string\'' response = http.request(request) puts response.read_body diff --git a/test/fixtures/output/shell/curl/headers.sh b/test/fixtures/output/shell/curl/headers.sh index c415136..7a4ea84 100644 --- a/test/fixtures/output/shell/curl/headers.sh +++ b/test/fixtures/output/shell/curl/headers.sh @@ -1,4 +1,5 @@ curl --request GET \ --url http://mockbin.com/har \ --header 'accept: application/json' \ + --header 'quoted-value: "quoted" '\''string'\''' \ --header 'x-foo: Bar' diff --git a/test/fixtures/output/shell/httpie/headers.sh b/test/fixtures/output/shell/httpie/headers.sh index 427ae78..1659df8 100644 --- a/test/fixtures/output/shell/httpie/headers.sh +++ b/test/fixtures/output/shell/httpie/headers.sh @@ -1,3 +1,4 @@ http GET http://mockbin.com/har \ accept:application/json \ + quoted-value:'"quoted" '\''string'\''' \ x-foo:Bar diff --git a/test/fixtures/output/shell/wget/headers.sh b/test/fixtures/output/shell/wget/headers.sh index e39f090..2389d65 100644 --- a/test/fixtures/output/shell/wget/headers.sh +++ b/test/fixtures/output/shell/wget/headers.sh @@ -2,5 +2,6 @@ wget --quiet \ --method GET \ --header 'accept: application/json' \ --header 'x-foo: Bar' \ + --header 'quoted-value: "quoted" '\''string'\''' \ --output-document \ - http://mockbin.com/har diff --git a/test/fixtures/output/swift/nsurlsession/headers.swift b/test/fixtures/output/swift/nsurlsession/headers.swift index 8902e1a..5b4ed4d 100644 --- a/test/fixtures/output/swift/nsurlsession/headers.swift +++ b/test/fixtures/output/swift/nsurlsession/headers.swift @@ -2,7 +2,8 @@ import Foundation let headers = [ "accept": "application/json", - "x-foo": "Bar" + "x-foo": "Bar", + "quoted-value": "\"quoted\" 'string'" ] let request = NSMutableURLRequest(url: NSURL(string: "http://mockbin.com/har")! as URL, diff --git a/test/fixtures/requests/headers.json b/test/fixtures/requests/headers.json index 6f41b38..bdca607 100644 --- a/test/fixtures/requests/headers.json +++ b/test/fixtures/requests/headers.json @@ -9,6 +9,10 @@ { "name": "x-foo", "value": "Bar" + }, + { + "name": "quoted-value", + "value": "\"quoted\" 'string'" } ] } diff --git a/test/index.js b/test/index.js index d35bda6..1b748da 100644 --- a/test/index.js +++ b/test/index.js @@ -158,7 +158,8 @@ describe('HTTPSnippet', function () { req.headersObj.should.be.an.Object() req.headersObj.should.eql({ accept: 'application/json', - 'x-foo': 'Bar' + 'x-foo': 'Bar', + 'quoted-value': "\"quoted\" 'string'" }) done() @@ -177,7 +178,8 @@ describe('HTTPSnippet', function () { req.headersObj.should.eql({ 'Kong-Admin-Token': 'Hunter1', accept: 'application/json', - 'x-foo': 'Bar' + 'x-foo': 'Bar', + 'quoted-value': "\"quoted\" 'string'" }) done() @@ -196,7 +198,8 @@ describe('HTTPSnippet', function () { req.headersObj.should.eql({ 'kong-admin-token': 'Hunter1', accept: 'application/json', - 'x-foo': 'Bar' + 'x-foo': 'Bar', + 'quoted-value': "\"quoted\" 'string'" }) done() From 95aea46551d8b1196f7b9510e6e98df626a51166 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Fri, 1 Jul 2022 15:00:29 +0200 Subject: [PATCH 27/83] 2.1.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 9e36ade..b46aef3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@httptoolkit/httpsnippet", - "version": "2.1.0", + "version": "2.1.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@httptoolkit/httpsnippet", - "version": "2.1.0", + "version": "2.1.1", "license": "MIT", "dependencies": { "chalk": "^1.1.1", diff --git a/package.json b/package.json index 9a49e44..02ff98d 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "2.1.0", + "version": "2.1.1", "name": "@httptoolkit/httpsnippet", "description": "HTTP request snippet generator for *most* languages", "author": "Tim Perry ", From a1011babc8342fa8aa63e103c6d2a461788837af Mon Sep 17 00:00:00 2001 From: JonLuca DeCaro Date: Wed, 6 Jul 2022 16:52:58 -0400 Subject: [PATCH 28/83] change variable name --- src/helpers/format.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/helpers/format.js b/src/helpers/format.js index 4eecbf0..fad620c 100644 --- a/src/helpers/format.js +++ b/src/helpers/format.js @@ -63,30 +63,30 @@ function singleQuoteEscape (value) { * * @returns {string} Formatted string */ -exports.format = function format (value, ...format) { +exports.format = function format (value, ...formatVariables) { if (typeof value !== 'string') return '' let i = 0 value = value.replace(/(? { // JSON-stringify if (m === '%v') { - const [elem] = format.splice(i, 1) + const [elem] = formatVariables.splice(i, 1) return JSON.stringify(elem) } // Escape for double-quoted string if (m === '%qd') { - const [elem] = format.splice(i, 1) + const [elem] = formatVariables.splice(i, 1) return doubleQuoteEscape(elem) } // Escape for single-quoted string if (m === '%qs') { - const [elem] = format.splice(i, 1) + const [elem] = formatVariables.splice(i, 1) return singleQuoteEscape(elem) } i += 1 return m }) - const ret = util.format(value, ...format) + const ret = util.format(value, ...formatVariables) return ret } From b3174ae377a4699cc83fee48e2df766c273c86fd Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Fri, 8 Jul 2022 11:01:39 +0200 Subject: [PATCH 29/83] 2.1.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 b46aef3..a759b2a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@httptoolkit/httpsnippet", - "version": "2.1.1", + "version": "2.1.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@httptoolkit/httpsnippet", - "version": "2.1.1", + "version": "2.1.2", "license": "MIT", "dependencies": { "chalk": "^1.1.1", diff --git a/package.json b/package.json index 02ff98d..b2b6533 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "2.1.1", + "version": "2.1.2", "name": "@httptoolkit/httpsnippet", "description": "HTTP request snippet generator for *most* languages", "author": "Tim Perry ", From 3c5fe71c4c3b5ae0e702e06518ac24270d1c761c Mon Sep 17 00:00:00 2001 From: Alexander Weber Date: Wed, 2 Nov 2022 09:35:59 +0100 Subject: [PATCH 30/83] ioutil -> io (deprecated) (Cherry-picked from upstream) --- src/targets/go/native.js | 4 ++-- .../output/go/native/application-form-encoded.go | 4 ++-- test/fixtures/output/go/native/application-json.go | 4 ++-- test/fixtures/output/go/native/cookies.go | 4 ++-- test/fixtures/output/go/native/custom-method.go | 4 ++-- test/fixtures/output/go/native/full.go | 4 ++-- test/fixtures/output/go/native/headers.go | 4 ++-- test/fixtures/output/go/native/https.go | 4 ++-- .../fixtures/output/go/native/jsonObj-multiline.go | 4 ++-- .../output/go/native/jsonObj-null-value.go | 4 ++-- test/fixtures/output/go/native/multipart-data.go | 4 ++-- test/fixtures/output/go/native/multipart-file.go | 4 ++-- .../output/go/native/multipart-form-data.go | 4 ++-- test/fixtures/output/go/native/nested.go | 4 ++-- test/fixtures/output/go/native/query.go | 4 ++-- test/fixtures/output/go/native/short.go | 4 ++-- test/fixtures/output/go/native/text-plain.go | 4 ++-- test/targets/go/native.js | 14 +++++++------- 18 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/targets/go/native.js b/src/targets/go/native.js index 4f43d0f..9a6feee 100644 --- a/src/targets/go/native.js +++ b/src/targets/go/native.js @@ -58,7 +58,7 @@ module.exports = function (source, options) { code.push(indent, '"net/http"') if (opts.printBody) { - code.push(indent, '"io/ioutil"') + code.push(indent, '"io"') } code.push(')') @@ -126,7 +126,7 @@ module.exports = function (source, options) { if (opts.printBody) { code.blank() .push(indent, 'defer res.Body.Close()') - .push(indent, 'body, %s := ioutil.ReadAll(res.Body)', errorPlaceholder) + .push(indent, 'body, %s := io.ReadAll(res.Body)', errorPlaceholder) errorCheck() } diff --git a/test/fixtures/output/go/native/application-form-encoded.go b/test/fixtures/output/go/native/application-form-encoded.go index 5344b4e..18b5cda 100644 --- a/test/fixtures/output/go/native/application-form-encoded.go +++ b/test/fixtures/output/go/native/application-form-encoded.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" "net/http" - "io/ioutil" + "io" ) func main() { @@ -20,7 +20,7 @@ func main() { res, _ := http.DefaultClient.Do(req) defer res.Body.Close() - body, _ := ioutil.ReadAll(res.Body) + body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) diff --git a/test/fixtures/output/go/native/application-json.go b/test/fixtures/output/go/native/application-json.go index c9dba6a..e2cdb35 100644 --- a/test/fixtures/output/go/native/application-json.go +++ b/test/fixtures/output/go/native/application-json.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" "net/http" - "io/ioutil" + "io" ) func main() { @@ -20,7 +20,7 @@ func main() { res, _ := http.DefaultClient.Do(req) defer res.Body.Close() - body, _ := ioutil.ReadAll(res.Body) + body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) diff --git a/test/fixtures/output/go/native/cookies.go b/test/fixtures/output/go/native/cookies.go index cd70638..ff804f8 100644 --- a/test/fixtures/output/go/native/cookies.go +++ b/test/fixtures/output/go/native/cookies.go @@ -3,7 +3,7 @@ package main import ( "fmt" "net/http" - "io/ioutil" + "io" ) func main() { @@ -17,7 +17,7 @@ func main() { res, _ := http.DefaultClient.Do(req) defer res.Body.Close() - body, _ := ioutil.ReadAll(res.Body) + body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) diff --git a/test/fixtures/output/go/native/custom-method.go b/test/fixtures/output/go/native/custom-method.go index 00c86ae..a94b6c2 100644 --- a/test/fixtures/output/go/native/custom-method.go +++ b/test/fixtures/output/go/native/custom-method.go @@ -3,7 +3,7 @@ package main import ( "fmt" "net/http" - "io/ioutil" + "io" ) func main() { @@ -15,7 +15,7 @@ func main() { res, _ := http.DefaultClient.Do(req) defer res.Body.Close() - body, _ := ioutil.ReadAll(res.Body) + body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) diff --git a/test/fixtures/output/go/native/full.go b/test/fixtures/output/go/native/full.go index 7166a6a..7992b37 100644 --- a/test/fixtures/output/go/native/full.go +++ b/test/fixtures/output/go/native/full.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" "net/http" - "io/ioutil" + "io" ) func main() { @@ -22,7 +22,7 @@ func main() { res, _ := http.DefaultClient.Do(req) defer res.Body.Close() - body, _ := ioutil.ReadAll(res.Body) + body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) diff --git a/test/fixtures/output/go/native/headers.go b/test/fixtures/output/go/native/headers.go index 00af29b..57bbca5 100644 --- a/test/fixtures/output/go/native/headers.go +++ b/test/fixtures/output/go/native/headers.go @@ -3,7 +3,7 @@ package main import ( "fmt" "net/http" - "io/ioutil" + "io" ) func main() { @@ -19,7 +19,7 @@ func main() { res, _ := http.DefaultClient.Do(req) defer res.Body.Close() - body, _ := ioutil.ReadAll(res.Body) + body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) diff --git a/test/fixtures/output/go/native/https.go b/test/fixtures/output/go/native/https.go index 40e7723..3737fc1 100644 --- a/test/fixtures/output/go/native/https.go +++ b/test/fixtures/output/go/native/https.go @@ -3,7 +3,7 @@ package main import ( "fmt" "net/http" - "io/ioutil" + "io" ) func main() { @@ -15,7 +15,7 @@ func main() { res, _ := http.DefaultClient.Do(req) defer res.Body.Close() - body, _ := ioutil.ReadAll(res.Body) + body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) diff --git a/test/fixtures/output/go/native/jsonObj-multiline.go b/test/fixtures/output/go/native/jsonObj-multiline.go index 9f80486..8d1ee53 100644 --- a/test/fixtures/output/go/native/jsonObj-multiline.go +++ b/test/fixtures/output/go/native/jsonObj-multiline.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" "net/http" - "io/ioutil" + "io" ) func main() { @@ -20,7 +20,7 @@ func main() { res, _ := http.DefaultClient.Do(req) defer res.Body.Close() - body, _ := ioutil.ReadAll(res.Body) + body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) diff --git a/test/fixtures/output/go/native/jsonObj-null-value.go b/test/fixtures/output/go/native/jsonObj-null-value.go index 8d920d7..15a9bb2 100644 --- a/test/fixtures/output/go/native/jsonObj-null-value.go +++ b/test/fixtures/output/go/native/jsonObj-null-value.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" "net/http" - "io/ioutil" + "io" ) func main() { @@ -20,7 +20,7 @@ func main() { res, _ := http.DefaultClient.Do(req) defer res.Body.Close() - body, _ := ioutil.ReadAll(res.Body) + body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) diff --git a/test/fixtures/output/go/native/multipart-data.go b/test/fixtures/output/go/native/multipart-data.go index 3bc875a..f607877 100644 --- a/test/fixtures/output/go/native/multipart-data.go +++ b/test/fixtures/output/go/native/multipart-data.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" "net/http" - "io/ioutil" + "io" ) func main() { @@ -20,7 +20,7 @@ func main() { res, _ := http.DefaultClient.Do(req) defer res.Body.Close() - body, _ := ioutil.ReadAll(res.Body) + body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) diff --git a/test/fixtures/output/go/native/multipart-file.go b/test/fixtures/output/go/native/multipart-file.go index 931cd28..0355970 100644 --- a/test/fixtures/output/go/native/multipart-file.go +++ b/test/fixtures/output/go/native/multipart-file.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" "net/http" - "io/ioutil" + "io" ) func main() { @@ -20,7 +20,7 @@ func main() { res, _ := http.DefaultClient.Do(req) defer res.Body.Close() - body, _ := ioutil.ReadAll(res.Body) + body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) diff --git a/test/fixtures/output/go/native/multipart-form-data.go b/test/fixtures/output/go/native/multipart-form-data.go index cf31548..2d46d6a 100644 --- a/test/fixtures/output/go/native/multipart-form-data.go +++ b/test/fixtures/output/go/native/multipart-form-data.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" "net/http" - "io/ioutil" + "io" ) func main() { @@ -20,7 +20,7 @@ func main() { res, _ := http.DefaultClient.Do(req) defer res.Body.Close() - body, _ := ioutil.ReadAll(res.Body) + body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) diff --git a/test/fixtures/output/go/native/nested.go b/test/fixtures/output/go/native/nested.go index f392179..2089b7d 100644 --- a/test/fixtures/output/go/native/nested.go +++ b/test/fixtures/output/go/native/nested.go @@ -3,7 +3,7 @@ package main import ( "fmt" "net/http" - "io/ioutil" + "io" ) func main() { @@ -15,7 +15,7 @@ func main() { res, _ := http.DefaultClient.Do(req) defer res.Body.Close() - body, _ := ioutil.ReadAll(res.Body) + body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) diff --git a/test/fixtures/output/go/native/query.go b/test/fixtures/output/go/native/query.go index e2e47ac..6f2ab48 100644 --- a/test/fixtures/output/go/native/query.go +++ b/test/fixtures/output/go/native/query.go @@ -3,7 +3,7 @@ package main import ( "fmt" "net/http" - "io/ioutil" + "io" ) func main() { @@ -15,7 +15,7 @@ func main() { res, _ := http.DefaultClient.Do(req) defer res.Body.Close() - body, _ := ioutil.ReadAll(res.Body) + body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) diff --git a/test/fixtures/output/go/native/short.go b/test/fixtures/output/go/native/short.go index 441f2a0..7384b12 100644 --- a/test/fixtures/output/go/native/short.go +++ b/test/fixtures/output/go/native/short.go @@ -3,7 +3,7 @@ package main import ( "fmt" "net/http" - "io/ioutil" + "io" ) func main() { @@ -15,7 +15,7 @@ func main() { res, _ := http.DefaultClient.Do(req) defer res.Body.Close() - body, _ := ioutil.ReadAll(res.Body) + body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) diff --git a/test/fixtures/output/go/native/text-plain.go b/test/fixtures/output/go/native/text-plain.go index ccf1c7a..6f72891 100644 --- a/test/fixtures/output/go/native/text-plain.go +++ b/test/fixtures/output/go/native/text-plain.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" "net/http" - "io/ioutil" + "io" ) func main() { @@ -20,7 +20,7 @@ func main() { res, _ := http.DefaultClient.Do(req) defer res.Body.Close() - body, _ := ioutil.ReadAll(res.Body) + body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) diff --git a/test/targets/go/native.js b/test/targets/go/native.js index 5288d45..db5315b 100644 --- a/test/targets/go/native.js +++ b/test/targets/go/native.js @@ -9,7 +9,7 @@ module.exports = function (HTTPSnippet, fixtures) { }) result.should.be.a.String() - result.should.eql('url := "http://mockbin.com/har?foo=bar&foo=baz&baz=abc&key=value"\n\npayload := strings.NewReader("foo=bar")\n\nreq, _ := http.NewRequest("POST", url, payload)\n\nreq.Header.Add("cookie", "foo=bar; bar=baz")\nreq.Header.Add("accept", "application/json")\nreq.Header.Add("content-type", "application/x-www-form-urlencoded")\n\nres, _ := http.DefaultClient.Do(req)\n\ndefer res.Body.Close()\nbody, _ := ioutil.ReadAll(res.Body)\n\nfmt.Println(res)\nfmt.Println(string(body))') + result.should.eql('url := "http://mockbin.com/har?foo=bar&foo=baz&baz=abc&key=value"\n\npayload := strings.NewReader("foo=bar")\n\nreq, _ := http.NewRequest("POST", url, payload)\n\nreq.Header.Add("cookie", "foo=bar; bar=baz")\nreq.Header.Add("accept", "application/json")\nreq.Header.Add("content-type", "application/x-www-form-urlencoded")\n\nres, _ := http.DefaultClient.Do(req)\n\ndefer res.Body.Close()\nbody, _ := io.ReadAll(res.Body)\n\nfmt.Println(res)\nfmt.Println(string(body))') }) it('should support checkErrors option', function () { @@ -24,7 +24,7 @@ import ( \t"fmt" \t"strings" \t"net/http" -\t"io/ioutil" +\t"io" ) func main() { @@ -48,7 +48,7 @@ func main() { \t} \tdefer res.Body.Close() -\tbody, err := ioutil.ReadAll(res.Body) +\tbody, err := io.ReadAll(res.Body) \tif err != nil { \t\tpanic(err) \t} @@ -105,7 +105,7 @@ import ( \t"time" \t"strings" \t"net/http" -\t"io/ioutil" +\t"io" ) func main() { @@ -127,7 +127,7 @@ func main() { \tres, _ := client.Do(req) \tdefer res.Body.Close() -\tbody, _ := ioutil.ReadAll(res.Body) +\tbody, _ := io.ReadAll(res.Body) \tfmt.Println(res) \tfmt.Println(string(body)) @@ -148,7 +148,7 @@ import ( \t"crypto/tls" \t"strings" \t"net/http" -\t"io/ioutil" +\t"io" ) func main() { @@ -172,7 +172,7 @@ func main() { \tres, _ := client.Do(req) \tdefer res.Body.Close() -\tbody, _ := ioutil.ReadAll(res.Body) +\tbody, _ := io.ReadAll(res.Body) \tfmt.Println(res) \tfmt.Println(string(body)) From 3038a77c24660d8145bd85d12b81abe226d4b841 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Mon, 5 Jun 2023 16:58:41 +0200 Subject: [PATCH 31/83] Remove require 'openssl' from ruby target (no longer needed) (Cherry-picked from upstream) --- src/targets/ruby/native.js | 5 ----- test/fixtures/output/ruby/native/https.rb | 1 - test/targets/ruby/native.js | 1 - 3 files changed, 7 deletions(-) diff --git a/src/targets/ruby/native.js b/src/targets/ruby/native.js index 7316135..ba9cebc 100644 --- a/src/targets/ruby/native.js +++ b/src/targets/ruby/native.js @@ -7,11 +7,6 @@ module.exports = function (source, options) { code.push('require \'uri\'') .push('require \'net/http\'') - - if (source.uriObj.protocol === 'https:') { - code.push('require \'openssl\'') - } - code.blank() // To support custom methods we check for the supported methods diff --git a/test/fixtures/output/ruby/native/https.rb b/test/fixtures/output/ruby/native/https.rb index 81eff1f..94d60f5 100644 --- a/test/fixtures/output/ruby/native/https.rb +++ b/test/fixtures/output/ruby/native/https.rb @@ -1,6 +1,5 @@ require 'uri' require 'net/http' -require 'openssl' url = URI("https://mockbin.com/har") diff --git a/test/targets/ruby/native.js b/test/targets/ruby/native.js index a92e36b..c376cd9 100644 --- a/test/targets/ruby/native.js +++ b/test/targets/ruby/native.js @@ -9,7 +9,6 @@ module.exports = function (HTTPSnippet, fixtures) { result.should.be.a.String() result.should.eql(`require 'uri' require 'net/http' -require 'openssl' url = URI("https://mockbin.com/har") From 20992dbe732ed541a990cdfb480aa93d7689df5e Mon Sep 17 00:00:00 2001 From: taqin Date: Thu, 22 Jun 2023 23:17:20 +0700 Subject: [PATCH 32/83] Check if options is defined before accessing insecureSkipVerify The `insecureSkipVerify` property was being accessed on the `options` object without checking if `options` was defined, leading to a TypeError when `options` was undefined. ````bash Error stack trace: TypeError: Cannot read properties of undefined (reading 'insecureSkipVerify') ... --- src/targets/node/native.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/targets/node/native.js b/src/targets/node/native.js index 63a27b4..a6d8332 100644 --- a/src/targets/node/native.js +++ b/src/targets/node/native.js @@ -28,7 +28,7 @@ module.exports = function (source, options) { headers: source.allHeaders } - if (options.insecureSkipVerify) { + if (options && options.insecureSkipVerify) { reqOpts.rejectUnauthorized = false } From 4fd58d76f8fecd6694d66de92c4bdad58c6307c3 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Thu, 22 Jun 2023 19:00:23 +0200 Subject: [PATCH 33/83] 2.1.3 --- 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 a759b2a..18b8f06 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@httptoolkit/httpsnippet", - "version": "2.1.2", + "version": "2.1.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@httptoolkit/httpsnippet", - "version": "2.1.2", + "version": "2.1.3", "license": "MIT", "dependencies": { "chalk": "^1.1.1", diff --git a/package.json b/package.json index b2b6533..a661db3 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "2.1.2", + "version": "2.1.3", "name": "@httptoolkit/httpsnippet", "description": "HTTP request snippet generator for *most* languages", "author": "Tim Perry ", From 13fe580c26be74e82b7822e73c0a96f1437c587c Mon Sep 17 00:00:00 2001 From: Fr0stM0urne Date: Thu, 28 Mar 2024 16:01:41 +0500 Subject: [PATCH 34/83] Fix JSON parsing for python requests --- src/targets/python/requests.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/targets/python/requests.js b/src/targets/python/requests.js index 1938f97..1ae79f9 100644 --- a/src/targets/python/requests.js +++ b/src/targets/python/requests.js @@ -56,7 +56,7 @@ module.exports = function (source, options) { switch (source.postData.mimeType) { case 'application/json': if (source.postData.jsonObj) { - code.push('payload = %s', helpers.literalRepresentation(source.postData.jsonObj, opts)) + code.push('payload = %s', JSON.stringify(source.postData.jsonObj)) jsonPayload = true hasPayload = true } From f87737e0ebf24d3198908ecf211cdd71a5ff8de9 Mon Sep 17 00:00:00 2001 From: Fr0stM0urne Date: Thu, 28 Mar 2024 21:38:03 +0500 Subject: [PATCH 35/83] move JSON.stringify to python helper --- src/targets/python/helpers.js | 2 +- src/targets/python/requests.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/targets/python/helpers.js b/src/targets/python/helpers.js index 46f72d8..a3c5ee7 100644 --- a/src/targets/python/helpers.js +++ b/src/targets/python/helpers.js @@ -77,7 +77,7 @@ module.exports = { if (value === null || value === undefined) { return '' } - return '"' + value.toString().replace(/"/g, '\\"') + '"' + return JSON.stringify(value) } } } diff --git a/src/targets/python/requests.js b/src/targets/python/requests.js index 1ae79f9..1938f97 100644 --- a/src/targets/python/requests.js +++ b/src/targets/python/requests.js @@ -56,7 +56,7 @@ module.exports = function (source, options) { switch (source.postData.mimeType) { case 'application/json': if (source.postData.jsonObj) { - code.push('payload = %s', JSON.stringify(source.postData.jsonObj)) + code.push('payload = %s', helpers.literalRepresentation(source.postData.jsonObj, opts)) jsonPayload = true hasPayload = true } From 7231dc898d8739ed0940bc6acceb1f6f6e65d2c5 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Fri, 5 Apr 2024 19:30:43 +0200 Subject: [PATCH 36/83] Skip request validation for now due to mockbin.com/har shutdown This used to return some kind of test HAR file (presumably of the incoming request) but it now returns a cloudflare block page, seemingly due to changes at Insomnia to remove this. We can't do much about that in the very short term, so I've disabled those tests. We should update the test output to use a different testserver some time soon. --- test/requests.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/requests.js b/test/requests.js index 63f3fec..de765c0 100644 --- a/test/requests.js +++ b/test/requests.js @@ -25,7 +25,7 @@ const requests = [ // test all the things! fixtures.cli.forEach(function (cli) { - describe(targets[cli.target].info.title + ' Request Validation', function () { + describe.skip(targets[cli.target].info.title + ' Request Validation', function () { cli.clients.forEach(function (client) { requests.forEach(function (request) { it(client + ' request should match mock for ' + request, function (done) { From d63c0c17c70b04894fb80322ea333375e646718b Mon Sep 17 00:00:00 2001 From: Fr0stM0urne Date: Wed, 27 Mar 2024 13:40:32 +0500 Subject: [PATCH 37/83] Added handling of gzip encoding for python3 http client. --- .gitignore | 1 + src/targets/python/python3.js | 20 +++++++++++++- test/fixtures/output/c/libcurl/compression.c | 10 +++++++ .../output/clojure/clj_http/compression.clj | 3 +++ .../output/csharp/httpclient/compression.cs | 16 +++++++++++ .../output/csharp/restsharp/compression.cs | 4 +++ test/fixtures/output/go/native/compression.go | 25 +++++++++++++++++ test/fixtures/output/http/1.1/compression | 3 +++ .../output/java/asynchttp/compression.java | 9 +++++++ .../output/java/nethttp/compression.java | 7 +++++ .../output/java/okhttp/compression.java | 9 +++++++ .../output/java/unirest/compression.java | 3 +++ .../output/javascript/axios/compression.js | 13 +++++++++ .../output/javascript/fetch/compression.js | 6 +++++ .../output/javascript/jquery/compression.js | 13 +++++++++ .../output/javascript/xhr/compression.js | 15 +++++++++++ .../output/kotlin/okhttp/compression.kt | 9 +++++++ .../fixtures/output/node/axios/compression.js | 13 +++++++++ .../fixtures/output/node/fetch/compression.js | 10 +++++++ .../output/node/native/compression.js | 26 ++++++++++++++++++ .../output/node/request/compression.js | 13 +++++++++ .../output/node/unirest/compression.js | 13 +++++++++ .../output/objc/nsurlsession/compression.m | 21 +++++++++++++++ .../output/ocaml/cohttp/compression.ml | 10 +++++++ test/fixtures/output/php/curl/compression.php | 27 +++++++++++++++++++ .../fixtures/output/php/http1/compression.php | 17 ++++++++++++ .../fixtures/output/php/http2/compression.php | 15 +++++++++++ .../powershell/restmethod/compression.ps1 | 3 +++ .../powershell/webrequest/compression.ps1 | 3 +++ .../output/python/python3/compression.py | 16 +++++++++++ .../python/python3/content-encoding-gzip.py | 16 +++++++++++ .../output/python/requests/compression.py | 9 +++++++ test/fixtures/output/r/httr/compression.r | 7 +++++ .../output/ruby/native/compression.rb | 12 +++++++++ .../fixtures/output/shell/curl/compression.sh | 4 +++ .../output/shell/httpie/compression.sh | 2 ++ .../fixtures/output/shell/wget/compression.sh | 5 ++++ .../swift/nsurlsession/compression.swift | 21 +++++++++++++++ .../{curl => requests}/compression.json | 0 test/targets/shell/curl.js | 9 ------- 40 files changed, 428 insertions(+), 10 deletions(-) create mode 100644 test/fixtures/output/c/libcurl/compression.c create mode 100644 test/fixtures/output/clojure/clj_http/compression.clj create mode 100644 test/fixtures/output/csharp/httpclient/compression.cs create mode 100644 test/fixtures/output/csharp/restsharp/compression.cs create mode 100644 test/fixtures/output/go/native/compression.go create mode 100644 test/fixtures/output/http/1.1/compression create mode 100644 test/fixtures/output/java/asynchttp/compression.java create mode 100644 test/fixtures/output/java/nethttp/compression.java create mode 100644 test/fixtures/output/java/okhttp/compression.java create mode 100644 test/fixtures/output/java/unirest/compression.java create mode 100644 test/fixtures/output/javascript/axios/compression.js create mode 100644 test/fixtures/output/javascript/fetch/compression.js create mode 100644 test/fixtures/output/javascript/jquery/compression.js create mode 100644 test/fixtures/output/javascript/xhr/compression.js create mode 100644 test/fixtures/output/kotlin/okhttp/compression.kt create mode 100644 test/fixtures/output/node/axios/compression.js create mode 100644 test/fixtures/output/node/fetch/compression.js create mode 100644 test/fixtures/output/node/native/compression.js create mode 100644 test/fixtures/output/node/request/compression.js create mode 100644 test/fixtures/output/node/unirest/compression.js create mode 100644 test/fixtures/output/objc/nsurlsession/compression.m create mode 100644 test/fixtures/output/ocaml/cohttp/compression.ml create mode 100644 test/fixtures/output/php/curl/compression.php create mode 100644 test/fixtures/output/php/http1/compression.php create mode 100644 test/fixtures/output/php/http2/compression.php create mode 100644 test/fixtures/output/powershell/restmethod/compression.ps1 create mode 100644 test/fixtures/output/powershell/webrequest/compression.ps1 create mode 100644 test/fixtures/output/python/python3/compression.py create mode 100644 test/fixtures/output/python/python3/content-encoding-gzip.py create mode 100644 test/fixtures/output/python/requests/compression.py create mode 100644 test/fixtures/output/r/httr/compression.r create mode 100644 test/fixtures/output/ruby/native/compression.rb create mode 100644 test/fixtures/output/shell/curl/compression.sh create mode 100644 test/fixtures/output/shell/httpie/compression.sh create mode 100644 test/fixtures/output/shell/wget/compression.sh create mode 100644 test/fixtures/output/swift/nsurlsession/compression.swift rename test/fixtures/{curl => requests}/compression.json (100%) diff --git a/.gitignore b/.gitignore index dddca89..a41ca4a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.log node_modules coverage* +.vscode \ No newline at end of file diff --git a/src/targets/python/python3.js b/src/targets/python/python3.js index 35ac961..fd0d121 100644 --- a/src/targets/python/python3.js +++ b/src/targets/python/python3.js @@ -11,9 +11,11 @@ 'use strict' const CodeBuilder = require('../../helpers/code-builder') +const helpers = require('../../helpers/headers') module.exports = function (source, options) { const code = new CodeBuilder() + // Start Request code.push('import http.client') @@ -21,6 +23,13 @@ module.exports = function (source, options) { code.push('import ssl') } + const mayBeGzipped = helpers.hasHeader(source.allHeaders, 'accept-encoding') && + helpers.getHeader(source.allHeaders, 'accept-encoding').includes('gzip') + + if (mayBeGzipped) { + code.push('import gzip') + } + code.blank() // Check which protocol to be used for the client connection @@ -90,7 +99,16 @@ module.exports = function (source, options) { .push('res = conn.getresponse()') .push('data = res.read()') .blank() - .push('print(data.decode("utf-8"))') + + // Decode response + if (mayBeGzipped) { + code.push("if res.headers['content-encoding'] == 'gzip':") + code.push(' print(gzip.decompress(data).decode("utf-8"))') + code.push('else:') + code.push(' print(data.decode("utf-8"))') + } else { + code.push('print(data.decode("utf-8"))') + } return code.join() } diff --git a/test/fixtures/output/c/libcurl/compression.c b/test/fixtures/output/c/libcurl/compression.c new file mode 100644 index 0000000..dd0bff6 --- /dev/null +++ b/test/fixtures/output/c/libcurl/compression.c @@ -0,0 +1,10 @@ +CURL *hnd = curl_easy_init(); + +curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "GET"); +curl_easy_setopt(hnd, CURLOPT_URL, "http://mockbin.com/har"); + +struct curl_slist *headers = NULL; +headers = curl_slist_append(headers, "accept-encoding: deflate, gzip, br"); +curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers); + +CURLcode ret = curl_easy_perform(hnd); \ No newline at end of file diff --git a/test/fixtures/output/clojure/clj_http/compression.clj b/test/fixtures/output/clojure/clj_http/compression.clj new file mode 100644 index 0000000..e81ae9d --- /dev/null +++ b/test/fixtures/output/clojure/clj_http/compression.clj @@ -0,0 +1,3 @@ +(require '[clj-http.client :as client]) + +(client/get "http://mockbin.com/har" {:headers {:accept-encoding "deflate, gzip, br"}}) \ No newline at end of file diff --git a/test/fixtures/output/csharp/httpclient/compression.cs b/test/fixtures/output/csharp/httpclient/compression.cs new file mode 100644 index 0000000..52fba9a --- /dev/null +++ b/test/fixtures/output/csharp/httpclient/compression.cs @@ -0,0 +1,16 @@ +var clientHandler = new HttpClientHandler +{ + AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip, +}; +var client = new HttpClient(clientHandler); +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/compression.cs b/test/fixtures/output/csharp/restsharp/compression.cs new file mode 100644 index 0000000..c3f7c28 --- /dev/null +++ b/test/fixtures/output/csharp/restsharp/compression.cs @@ -0,0 +1,4 @@ +var client = new RestClient("http://mockbin.com/har"); +var request = new RestRequest(Method.GET); +request.AddHeader("accept-encoding", "deflate, gzip, br"); +IRestResponse response = client.Execute(request); \ No newline at end of file diff --git a/test/fixtures/output/go/native/compression.go b/test/fixtures/output/go/native/compression.go new file mode 100644 index 0000000..11a1717 --- /dev/null +++ b/test/fixtures/output/go/native/compression.go @@ -0,0 +1,25 @@ +package main + +import ( + "fmt" + "net/http" + "io" +) + +func main() { + + url := "http://mockbin.com/har" + + req, _ := http.NewRequest("GET", url, nil) + + req.Header.Add("accept-encoding", "deflate, gzip, br") + + 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/compression b/test/fixtures/output/http/1.1/compression new file mode 100644 index 0000000..8e2f8b1 --- /dev/null +++ b/test/fixtures/output/http/1.1/compression @@ -0,0 +1,3 @@ +GET /har HTTP/1.1 +Accept-Encoding: deflate, gzip, br +Host: mockbin.com \ No newline at end of file diff --git a/test/fixtures/output/java/asynchttp/compression.java b/test/fixtures/output/java/asynchttp/compression.java new file mode 100644 index 0000000..ecadc31 --- /dev/null +++ b/test/fixtures/output/java/asynchttp/compression.java @@ -0,0 +1,9 @@ +AsyncHttpClient client = new DefaultAsyncHttpClient(); +client.prepare("GET", "http://mockbin.com/har") + .setHeader("accept-encoding", "deflate, gzip, br") + .execute() + .toCompletableFuture() + .thenAccept(System.out::println) + .join(); + +client.close(); \ No newline at end of file diff --git a/test/fixtures/output/java/nethttp/compression.java b/test/fixtures/output/java/nethttp/compression.java new file mode 100644 index 0000000..569ab05 --- /dev/null +++ b/test/fixtures/output/java/nethttp/compression.java @@ -0,0 +1,7 @@ +HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("http://mockbin.com/har")) + .header("accept-encoding", "deflate, gzip, br") + .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/compression.java b/test/fixtures/output/java/okhttp/compression.java new file mode 100644 index 0000000..2503e18 --- /dev/null +++ b/test/fixtures/output/java/okhttp/compression.java @@ -0,0 +1,9 @@ +OkHttpClient client = new OkHttpClient(); + +Request request = new Request.Builder() + .url("http://mockbin.com/har") + .get() + .addHeader("accept-encoding", "deflate, gzip, br") + .build(); + +Response response = client.newCall(request).execute(); \ No newline at end of file diff --git a/test/fixtures/output/java/unirest/compression.java b/test/fixtures/output/java/unirest/compression.java new file mode 100644 index 0000000..d006f9e --- /dev/null +++ b/test/fixtures/output/java/unirest/compression.java @@ -0,0 +1,3 @@ +HttpResponse response = Unirest.get("http://mockbin.com/har") + .header("accept-encoding", "deflate, gzip, br") + .asString(); \ No newline at end of file diff --git a/test/fixtures/output/javascript/axios/compression.js b/test/fixtures/output/javascript/axios/compression.js new file mode 100644 index 0000000..02f2a93 --- /dev/null +++ b/test/fixtures/output/javascript/axios/compression.js @@ -0,0 +1,13 @@ +import axios from "axios"; + +const options = { + method: 'GET', + url: 'http://mockbin.com/har', + headers: {'accept-encoding': 'deflate, gzip, br'} +}; + +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/compression.js b/test/fixtures/output/javascript/fetch/compression.js new file mode 100644 index 0000000..4215429 --- /dev/null +++ b/test/fixtures/output/javascript/fetch/compression.js @@ -0,0 +1,6 @@ +const options = {method: 'GET', headers: {'accept-encoding': 'deflate, gzip, br'}}; + +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/compression.js b/test/fixtures/output/javascript/jquery/compression.js new file mode 100644 index 0000000..6d60dd9 --- /dev/null +++ b/test/fixtures/output/javascript/jquery/compression.js @@ -0,0 +1,13 @@ +const settings = { + "async": true, + "crossDomain": true, + "url": "http://mockbin.com/har", + "method": "GET", + "headers": { + "accept-encoding": "deflate, gzip, br" + } +}; + +$.ajax(settings).done(function (response) { + console.log(response); +}); \ No newline at end of file diff --git a/test/fixtures/output/javascript/xhr/compression.js b/test/fixtures/output/javascript/xhr/compression.js new file mode 100644 index 0000000..eca54e4 --- /dev/null +++ b/test/fixtures/output/javascript/xhr/compression.js @@ -0,0 +1,15 @@ +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.setRequestHeader("accept-encoding", "deflate, gzip, br"); + +xhr.send(data); \ No newline at end of file diff --git a/test/fixtures/output/kotlin/okhttp/compression.kt b/test/fixtures/output/kotlin/okhttp/compression.kt new file mode 100644 index 0000000..7b1ab0c --- /dev/null +++ b/test/fixtures/output/kotlin/okhttp/compression.kt @@ -0,0 +1,9 @@ +val client = OkHttpClient() + +val request = Request.Builder() + .url("http://mockbin.com/har") + .get() + .addHeader("accept-encoding", "deflate, gzip, br") + .build() + +val response = client.newCall(request).execute() \ No newline at end of file diff --git a/test/fixtures/output/node/axios/compression.js b/test/fixtures/output/node/axios/compression.js new file mode 100644 index 0000000..6d4ba84 --- /dev/null +++ b/test/fixtures/output/node/axios/compression.js @@ -0,0 +1,13 @@ +var axios = require("axios").default; + +var options = { + method: 'GET', + url: 'http://mockbin.com/har', + headers: {'accept-encoding': 'deflate, gzip, br'} +}; + +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/compression.js b/test/fixtures/output/node/fetch/compression.js new file mode 100644 index 0000000..2eee5e8 --- /dev/null +++ b/test/fixtures/output/node/fetch/compression.js @@ -0,0 +1,10 @@ +const fetch = require('node-fetch'); + +let url = 'http://mockbin.com/har'; + +let options = {method: 'GET', headers: {'accept-encoding': 'deflate, gzip, br'}}; + +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/compression.js b/test/fixtures/output/node/native/compression.js new file mode 100644 index 0000000..1433ebc --- /dev/null +++ b/test/fixtures/output/node/native/compression.js @@ -0,0 +1,26 @@ +const http = require("http"); + +const options = { + "method": "GET", + "hostname": "mockbin.com", + "port": null, + "path": "/har", + "headers": { + "accept-encoding": "deflate, gzip, br" + } +}; + +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/compression.js b/test/fixtures/output/node/request/compression.js new file mode 100644 index 0000000..b034830 --- /dev/null +++ b/test/fixtures/output/node/request/compression.js @@ -0,0 +1,13 @@ +const request = require('request'); + +const options = { + method: 'GET', + url: 'http://mockbin.com/har', + headers: {'accept-encoding': 'deflate, gzip, br'} +}; + +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/compression.js b/test/fixtures/output/node/unirest/compression.js new file mode 100644 index 0000000..da60aa6 --- /dev/null +++ b/test/fixtures/output/node/unirest/compression.js @@ -0,0 +1,13 @@ +const unirest = require("unirest"); + +const req = unirest("GET", "http://mockbin.com/har"); + +req.headers({ + "accept-encoding": "deflate, gzip, br" +}); + +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/compression.m b/test/fixtures/output/objc/nsurlsession/compression.m new file mode 100644 index 0000000..533bd79 --- /dev/null +++ b/test/fixtures/output/objc/nsurlsession/compression.m @@ -0,0 +1,21 @@ +#import + +NSDictionary *headers = @{ @"accept-encoding": @"deflate, gzip, br" }; + +NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://mockbin.com/har"] + cachePolicy:NSURLRequestUseProtocolCachePolicy + timeoutInterval:10.0]; +[request setHTTPMethod:@"GET"]; +[request setAllHTTPHeaderFields:headers]; + +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/compression.ml b/test/fixtures/output/ocaml/cohttp/compression.ml new file mode 100644 index 0000000..e5703bd --- /dev/null +++ b/test/fixtures/output/ocaml/cohttp/compression.ml @@ -0,0 +1,10 @@ +open Cohttp_lwt_unix +open Cohttp +open Lwt + +let uri = Uri.of_string "http://mockbin.com/har" in +let headers = Header.add (Header.init ()) "accept-encoding" "deflate, gzip, br" in + +Client.call ~headers `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/compression.php b/test/fixtures/output/php/curl/compression.php new file mode 100644 index 0000000..6bf18d4 --- /dev/null +++ b/test/fixtures/output/php/curl/compression.php @@ -0,0 +1,27 @@ + "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", + CURLOPT_HTTPHEADER => [ + "accept-encoding: deflate, gzip, br" + ], +]); + +$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/compression.php b/test/fixtures/output/php/http1/compression.php new file mode 100644 index 0000000..357272c --- /dev/null +++ b/test/fixtures/output/php/http1/compression.php @@ -0,0 +1,17 @@ +setUrl('http://mockbin.com/har'); +$request->setMethod(HTTP_METH_GET); + +$request->setHeaders([ + 'accept-encoding' => 'deflate, gzip, br' +]); + +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/compression.php b/test/fixtures/output/php/http2/compression.php new file mode 100644 index 0000000..d6b15f2 --- /dev/null +++ b/test/fixtures/output/php/http2/compression.php @@ -0,0 +1,15 @@ +setRequestUrl('http://mockbin.com/har'); +$request->setRequestMethod('GET'); +$request->setHeaders([ + 'accept-encoding' => 'deflate, gzip, br' +]); + +$client->enqueue($request)->send(); +$response = $client->getResponse(); + +echo $response->getBody(); \ No newline at end of file diff --git a/test/fixtures/output/powershell/restmethod/compression.ps1 b/test/fixtures/output/powershell/restmethod/compression.ps1 new file mode 100644 index 0000000..c7d2e5a --- /dev/null +++ b/test/fixtures/output/powershell/restmethod/compression.ps1 @@ -0,0 +1,3 @@ +$headers=@{} +$headers.Add("accept-encoding", "deflate, gzip, br") +$response = Invoke-RestMethod -Uri 'http://mockbin.com/har' -Method GET -Headers $headers \ No newline at end of file diff --git a/test/fixtures/output/powershell/webrequest/compression.ps1 b/test/fixtures/output/powershell/webrequest/compression.ps1 new file mode 100644 index 0000000..1e9ada0 --- /dev/null +++ b/test/fixtures/output/powershell/webrequest/compression.ps1 @@ -0,0 +1,3 @@ +$headers=@{} +$headers.Add("accept-encoding", "deflate, gzip, br") +$response = Invoke-WebRequest -Uri 'http://mockbin.com/har' -Method GET -Headers $headers \ No newline at end of file diff --git a/test/fixtures/output/python/python3/compression.py b/test/fixtures/output/python/python3/compression.py new file mode 100644 index 0000000..a3bc5e3 --- /dev/null +++ b/test/fixtures/output/python/python3/compression.py @@ -0,0 +1,16 @@ +import http.client +import gzip + +conn = http.client.HTTPConnection("mockbin.com") + +headers = { "accept-encoding": "deflate, gzip, br" } + +conn.request("GET", "/har", headers=headers) + +res = conn.getresponse() +data = res.read() + +if res.headers['content-encoding'] == 'gzip': + print(gzip.decompress(data).decode("utf-8")) +else: + print(data.decode("utf-8")) \ No newline at end of file diff --git a/test/fixtures/output/python/python3/content-encoding-gzip.py b/test/fixtures/output/python/python3/content-encoding-gzip.py new file mode 100644 index 0000000..7273599 --- /dev/null +++ b/test/fixtures/output/python/python3/content-encoding-gzip.py @@ -0,0 +1,16 @@ +import http.client +import gzip + +conn = http.client.HTTPConnection("mockbin.com") + +headers = { "accept-encoding": "gzip" } + +conn.request("GET", "/har", headers=headers) + +res = conn.getresponse() +data = res.read() + +if res.headers['content-encoding'] == 'gzip': + print(gzip.decompress(data).decode("utf-8")) +else: + print(data.decode("utf-8")) diff --git a/test/fixtures/output/python/requests/compression.py b/test/fixtures/output/python/requests/compression.py new file mode 100644 index 0000000..9461c17 --- /dev/null +++ b/test/fixtures/output/python/requests/compression.py @@ -0,0 +1,9 @@ +import requests + +url = "http://mockbin.com/har" + +headers = { "accept-encoding": "deflate, gzip, br" } + +response = requests.get(url, headers=headers) + +print(response.text) \ No newline at end of file diff --git a/test/fixtures/output/r/httr/compression.r b/test/fixtures/output/r/httr/compression.r new file mode 100644 index 0000000..60df700 --- /dev/null +++ b/test/fixtures/output/r/httr/compression.r @@ -0,0 +1,7 @@ +library(httr) + +url <- "http://mockbin.com/har" + +response <- VERB("GET", url, add_headers(accept_encoding = 'deflate, gzip, br'), content_type("application/octet-stream")) + +content(response, "text") \ No newline at end of file diff --git a/test/fixtures/output/ruby/native/compression.rb b/test/fixtures/output/ruby/native/compression.rb new file mode 100644 index 0000000..d2f7260 --- /dev/null +++ b/test/fixtures/output/ruby/native/compression.rb @@ -0,0 +1,12 @@ +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) +request["accept-encoding"] = 'deflate, gzip, br' + +response = http.request(request) +puts response.read_body \ No newline at end of file diff --git a/test/fixtures/output/shell/curl/compression.sh b/test/fixtures/output/shell/curl/compression.sh new file mode 100644 index 0000000..da25c0d --- /dev/null +++ b/test/fixtures/output/shell/curl/compression.sh @@ -0,0 +1,4 @@ +curl --request GET \ + --url http://mockbin.com/har \ + --compressed \ + --header 'accept-encoding: deflate, gzip, br' \ No newline at end of file diff --git a/test/fixtures/output/shell/httpie/compression.sh b/test/fixtures/output/shell/httpie/compression.sh new file mode 100644 index 0000000..2e8d060 --- /dev/null +++ b/test/fixtures/output/shell/httpie/compression.sh @@ -0,0 +1,2 @@ +http GET http://mockbin.com/har \ + accept-encoding:'deflate, gzip, br' \ No newline at end of file diff --git a/test/fixtures/output/shell/wget/compression.sh b/test/fixtures/output/shell/wget/compression.sh new file mode 100644 index 0000000..50d8266 --- /dev/null +++ b/test/fixtures/output/shell/wget/compression.sh @@ -0,0 +1,5 @@ +wget --quiet \ + --method GET \ + --header 'accept-encoding: deflate, gzip, br' \ + --output-document \ + - http://mockbin.com/har \ No newline at end of file diff --git a/test/fixtures/output/swift/nsurlsession/compression.swift b/test/fixtures/output/swift/nsurlsession/compression.swift new file mode 100644 index 0000000..96f296b --- /dev/null +++ b/test/fixtures/output/swift/nsurlsession/compression.swift @@ -0,0 +1,21 @@ +import Foundation + +let headers = ["accept-encoding": "deflate, gzip, br"] + +let request = NSMutableURLRequest(url: NSURL(string: "http://mockbin.com/har")! as URL, + cachePolicy: .useProtocolCachePolicy, + timeoutInterval: 10.0) +request.httpMethod = "GET" +request.allHTTPHeaderFields = headers + +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/curl/compression.json b/test/fixtures/requests/compression.json similarity index 100% rename from test/fixtures/curl/compression.json rename to test/fixtures/requests/compression.json diff --git a/test/targets/shell/curl.js b/test/targets/shell/curl.js index 4f1819e..44323bb 100644 --- a/test/targets/shell/curl.js +++ b/test/targets/shell/curl.js @@ -74,15 +74,6 @@ module.exports = function (HTTPSnippet, fixtures) { result.should.eql('curl --request GET --url http://mockbin.com/request --http1.0') }) - it('should use --compressed for requests that accept encodings', function () { - const result = new HTTPSnippet(fixtures.curl.compression).convert('shell', 'curl', { - indent: false - }) - - result.should.be.a.String() - result.should.eql("curl --request GET --url http://mockbin.com/har --compressed --header 'accept-encoding: deflate, gzip, br'") - }) - it('should use custom indentation', function () { const result = new HTTPSnippet(fixtures.requests.full).convert('shell', 'curl', { indent: '@' From 8432facd6e15e8ff0046f0d9604dcf779ba7866a Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Mon, 8 Apr 2024 14:05:59 +0200 Subject: [PATCH 38/83] Add libcurl & Go compression handling too --- src/targets/c/libcurl.js | 10 ++++++++-- src/targets/go/native.js | 6 ++++++ test/fixtures/output/c/libcurl/compression.c | 2 ++ test/fixtures/output/go/native/compression.go | 2 -- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/targets/c/libcurl.js b/src/targets/c/libcurl.js index be3a218..729bbec 100644 --- a/src/targets/c/libcurl.js +++ b/src/targets/c/libcurl.js @@ -1,6 +1,7 @@ 'use strict' const CodeBuilder = require('../../helpers/code-builder') +const helpers = require('../../helpers/headers') module.exports = function (source, options) { const code = new CodeBuilder() @@ -26,9 +27,9 @@ module.exports = function (source, options) { } // construct cookies - if (source.allHeaders.cookie) { + if (helpers.hasHeader(source.allHeaders, 'cookie')) { code.blank() - .push('curl_easy_setopt(hnd, CURLOPT_COOKIE, "%s");', source.allHeaders.cookie) + .push('curl_easy_setopt(hnd, CURLOPT_COOKIE, "%s");', helpers.getHeader(source.allHeaders, 'cookie')) } if (source.postData.text) { @@ -36,6 +37,11 @@ module.exports = function (source, options) { .push('curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, %s);', JSON.stringify(source.postData.text)) } + if (helpers.hasHeader(source.allHeaders, 'accept-encoding')) { + code.blank() + .push('curl_easy_setopt(hnd, CURLOPT_ACCEPT_ENCODING, "");') + } + code.blank() .push('CURLcode ret = curl_easy_perform(hnd);') diff --git a/src/targets/go/native.js b/src/targets/go/native.js index 9a6feee..af038d5 100644 --- a/src/targets/go/native.js +++ b/src/targets/go/native.js @@ -11,6 +11,7 @@ 'use strict' const CodeBuilder = require('../../helpers/code-builder') +const helpers = require('../../helpers/headers') module.exports = function (source, options) { // Let's Go! @@ -110,6 +111,11 @@ module.exports = function (source, options) { errorCheck() // Add headers + + // Go automatically adds this and handles decompression, as long as we don't try to + // manually add it ourselves: + delete source.allHeaders[helpers.getHeaderName(source.allHeaders, 'accept-encoding')] + if (Object.keys(source.allHeaders).length) { Object.keys(source.allHeaders).forEach(function (key) { code.push(indent, 'req.Header.Add("%s", "%qd")', key, source.allHeaders[key]) diff --git a/test/fixtures/output/c/libcurl/compression.c b/test/fixtures/output/c/libcurl/compression.c index dd0bff6..c008a40 100644 --- a/test/fixtures/output/c/libcurl/compression.c +++ b/test/fixtures/output/c/libcurl/compression.c @@ -7,4 +7,6 @@ struct curl_slist *headers = NULL; headers = curl_slist_append(headers, "accept-encoding: deflate, gzip, br"); curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers); +curl_easy_setopt(hnd, CURLOPT_ACCEPT_ENCODING, ""); + CURLcode ret = curl_easy_perform(hnd); \ No newline at end of file diff --git a/test/fixtures/output/go/native/compression.go b/test/fixtures/output/go/native/compression.go index 11a1717..fae06af 100644 --- a/test/fixtures/output/go/native/compression.go +++ b/test/fixtures/output/go/native/compression.go @@ -12,8 +12,6 @@ func main() { req, _ := http.NewRequest("GET", url, nil) - req.Header.Add("accept-encoding", "deflate, gzip, br") - res, _ := http.DefaultClient.Do(req) defer res.Body.Close() From 17ce2efad4e1a6c2c860aed060fc7ca7ddbc44ca Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Mon, 8 Apr 2024 16:58:37 +0200 Subject: [PATCH 39/83] 2.1.4 --- 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 18b8f06..8745b17 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@httptoolkit/httpsnippet", - "version": "2.1.3", + "version": "2.1.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@httptoolkit/httpsnippet", - "version": "2.1.3", + "version": "2.1.4", "license": "MIT", "dependencies": { "chalk": "^1.1.1", diff --git a/package.json b/package.json index a661db3..b790218 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "2.1.3", + "version": "2.1.4", "name": "@httptoolkit/httpsnippet", "description": "HTTP request snippet generator for *most* languages", "author": "Tim Perry ", From a9deb0da9755f42bd6793180f849ca524bcd3251 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Thu, 27 Jun 2024 15:29:59 +0200 Subject: [PATCH 40/83] Commit all-escapes test case with all working (apparently) safe outputs Goal here is that for all _valid_ HTTP inputs, we should correctly escape special characters throughout. This is tricky to get 100% right in so many different languages and targets, but this gives us a test case and a set of checked correctly outputs, and we can incrementally fix the other cases with broken escaping to resolve the remaining cases until everything is escaped everywhere correctly. --- test/fixtures/output/c/libcurl/malicious.c | 22 +++ .../output/csharp/httpclient/malicious.cs | 33 ++++ .../output/csharp/restsharp/malicious.cs | 15 ++ test/fixtures/output/go/native/malicious.go | 38 +++++ test/fixtures/output/http/1.1/malicious | 16 ++ .../output/java/asynchttp/malicious.java | 20 +++ .../output/java/nethttp/malicious.java | 17 +++ .../output/java/okhttp/malicious.java | 21 +++ .../output/java/unirest/malicious.java | 14 ++ .../output/javascript/jquery/malicious.js | 24 +++ .../output/javascript/xhr/malicious.js | 25 +++ .../output/kotlin/okhttp/malicious.kt | 21 +++ test/fixtures/output/node/native/malicious.js | 37 +++++ .../fixtures/output/node/unirest/malicious.js | 50 ++++++ .../fixtures/output/ocaml/cohttp/malicious.ml | 23 +++ test/fixtures/output/php/curl/malicious.php | 38 +++++ test/fixtures/output/php/http1/malicious.php | 54 +++++++ test/fixtures/output/php/http2/malicious.php | 55 +++++++ .../output/python/python3/malicious.py | 26 ++++ test/fixtures/output/ruby/native/malicious.rb | 23 +++ test/fixtures/output/shell/curl/malicious.sh | 14 ++ .../fixtures/output/shell/httpie/malicious.sh | 13 ++ test/fixtures/output/shell/wget/malicious.sh | 16 ++ test/fixtures/requests/malicious.json | 144 ++++++++++++++++++ test/targets.js | 27 +++- 25 files changed, 785 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/output/c/libcurl/malicious.c create mode 100644 test/fixtures/output/csharp/httpclient/malicious.cs create mode 100644 test/fixtures/output/csharp/restsharp/malicious.cs create mode 100644 test/fixtures/output/go/native/malicious.go create mode 100644 test/fixtures/output/http/1.1/malicious create mode 100644 test/fixtures/output/java/asynchttp/malicious.java create mode 100644 test/fixtures/output/java/nethttp/malicious.java create mode 100644 test/fixtures/output/java/okhttp/malicious.java create mode 100644 test/fixtures/output/java/unirest/malicious.java create mode 100644 test/fixtures/output/javascript/jquery/malicious.js create mode 100644 test/fixtures/output/javascript/xhr/malicious.js create mode 100644 test/fixtures/output/kotlin/okhttp/malicious.kt create mode 100644 test/fixtures/output/node/native/malicious.js create mode 100644 test/fixtures/output/node/unirest/malicious.js create mode 100644 test/fixtures/output/ocaml/cohttp/malicious.ml create mode 100644 test/fixtures/output/php/curl/malicious.php create mode 100644 test/fixtures/output/php/http1/malicious.php create mode 100644 test/fixtures/output/php/http2/malicious.php create mode 100644 test/fixtures/output/python/python3/malicious.py create mode 100644 test/fixtures/output/ruby/native/malicious.rb create mode 100644 test/fixtures/output/shell/curl/malicious.sh create mode 100644 test/fixtures/output/shell/httpie/malicious.sh create mode 100644 test/fixtures/output/shell/wget/malicious.sh create mode 100644 test/fixtures/requests/malicious.json diff --git a/test/fixtures/output/c/libcurl/malicious.c b/test/fixtures/output/c/libcurl/malicious.c new file mode 100644 index 0000000..21f004d --- /dev/null +++ b/test/fixtures/output/c/libcurl/malicious.c @@ -0,0 +1,22 @@ +CURL *hnd = curl_easy_init(); + +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-value-test: '"); +headers = curl_slist_append(headers, "dquote-value-test: \""); +headers = curl_slist_append(headers, "backtick-value-test: `"); +headers = curl_slist_append(headers, "dollar-parenthesis-value-test: $("); +headers = curl_slist_append(headers, "hash-brace-value-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: {{"); +headers = curl_slist_append(headers, "null-value-test: \\0"); +headers = curl_slist_append(headers, "string-fmt-value-test: %s"); +headers = curl_slist_append(headers, "slash-value-test: \\"); +curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers); + +curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, "' \" ` $( #{ %( %{ {{ \\0 %s \\"); + +CURLcode ret = curl_easy_perform(hnd); \ No newline at end of file diff --git a/test/fixtures/output/csharp/httpclient/malicious.cs b/test/fixtures/output/csharp/httpclient/malicious.cs new file mode 100644 index 0000000..b88e5e2 --- /dev/null +++ b/test/fixtures/output/csharp/httpclient/malicious.cs @@ -0,0 +1,33 @@ +var client = new HttpClient(); +var request = new HttpRequestMessage +{ + Method = HttpMethod.Post, + 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-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 = new StringContent("' \" ` $( #{ %( %{ {{ \\0 %s \\") + { + Headers = + { + ContentType = new MediaTypeHeaderValue("text/plain") + } + } +}; +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/malicious.cs b/test/fixtures/output/csharp/restsharp/malicious.cs new file mode 100644 index 0000000..91dca32 --- /dev/null +++ b/test/fixtures/output/csharp/restsharp/malicious.cs @@ -0,0 +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-value-test", "'"); +request.AddHeader("dquote-value-test", "\""); +request.AddHeader("backtick-value-test", "`"); +request.AddHeader("dollar-parenthesis-value-test", "$("); +request.AddHeader("hash-brace-value-test", "#{"); +request.AddHeader("percent-parenthesis-value-test", "%("); +request.AddHeader("percent-brace-value-test", "%{"); +request.AddHeader("double-brace-value-test", "{{"); +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 diff --git a/test/fixtures/output/go/native/malicious.go b/test/fixtures/output/go/native/malicious.go new file mode 100644 index 0000000..70c67a9 --- /dev/null +++ b/test/fixtures/output/go/native/malicious.go @@ -0,0 +1,38 @@ +package main + +import ( + "fmt" + "strings" + "net/http" + "io" +) + +func main() { + + 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" + + payload := strings.NewReader("' \" ` $( #{ %( %{ {{ \\0 %s \\") + + req, _ := http.NewRequest("POST", url, payload) + + req.Header.Add("squote-value-test", "'") + req.Header.Add("dquote-value-test", "\"") + req.Header.Add("backtick-value-test", "`") + req.Header.Add("dollar-parenthesis-value-test", "$(") + req.Header.Add("hash-brace-value-test", "#{") + req.Header.Add("percent-parenthesis-value-test", "%(") + req.Header.Add("percent-brace-value-test", "%{") + req.Header.Add("double-brace-value-test", "{{") + req.Header.Add("null-value-test", "\\0") + req.Header.Add("string-fmt-value-test", "%s") + req.Header.Add("slash-value-test", "\\") + + 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/malicious b/test/fixtures/output/http/1.1/malicious new file mode 100644 index 0000000..114186f --- /dev/null +++ b/test/fixtures/output/http/1.1/malicious @@ -0,0 +1,16 @@ +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-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: \ +Host: example.test +Content-Length: 28 + +' " ` $( #{ %( %{ {{ \0 %s \ \ No newline at end of file diff --git a/test/fixtures/output/java/asynchttp/malicious.java b/test/fixtures/output/java/asynchttp/malicious.java new file mode 100644 index 0000000..7ff3d80 --- /dev/null +++ b/test/fixtures/output/java/asynchttp/malicious.java @@ -0,0 +1,20 @@ +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-value-test", "'") + .setHeader("dquote-value-test", "\"") + .setHeader("backtick-value-test", "`") + .setHeader("dollar-parenthesis-value-test", "$(") + .setHeader("hash-brace-value-test", "#{") + .setHeader("percent-parenthesis-value-test", "%(") + .setHeader("percent-brace-value-test", "%{") + .setHeader("double-brace-value-test", "{{") + .setHeader("null-value-test", "\\0") + .setHeader("string-fmt-value-test", "%s") + .setHeader("slash-value-test", "\\") + .setBody("' \" ` $( #{ %( %{ {{ \\0 %s \\") + .execute() + .toCompletableFuture() + .thenAccept(System.out::println) + .join(); + +client.close(); \ No newline at end of file diff --git a/test/fixtures/output/java/nethttp/malicious.java b/test/fixtures/output/java/nethttp/malicious.java new file mode 100644 index 0000000..cd72894 --- /dev/null +++ b/test/fixtures/output/java/nethttp/malicious.java @@ -0,0 +1,17 @@ +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-value-test", "'") + .header("dquote-value-test", "\"") + .header("backtick-value-test", "`") + .header("dollar-parenthesis-value-test", "$(") + .header("hash-brace-value-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", "\\") + .method("POST", HttpRequest.BodyPublishers.ofString("' \" ` $( #{ %( %{ {{ \\0 %s \\")) + .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/malicious.java b/test/fixtures/output/java/okhttp/malicious.java new file mode 100644 index 0000000..13d2499 --- /dev/null +++ b/test/fixtures/output/java/okhttp/malicious.java @@ -0,0 +1,21 @@ +OkHttpClient client = new OkHttpClient(); + +MediaType mediaType = MediaType.parse("text/plain"); +RequestBody body = RequestBody.create(mediaType, "' \" ` $( #{ %( %{ {{ \\0 %s \\"); +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-value-test", "'") + .addHeader("dquote-value-test", "\"") + .addHeader("backtick-value-test", "`") + .addHeader("dollar-parenthesis-value-test", "$(") + .addHeader("hash-brace-value-test", "#{") + .addHeader("percent-parenthesis-value-test", "%(") + .addHeader("percent-brace-value-test", "%{") + .addHeader("double-brace-value-test", "{{") + .addHeader("null-value-test", "\\0") + .addHeader("string-fmt-value-test", "%s") + .addHeader("slash-value-test", "\\") + .build(); + +Response response = client.newCall(request).execute(); \ No newline at end of file diff --git a/test/fixtures/output/java/unirest/malicious.java b/test/fixtures/output/java/unirest/malicious.java new file mode 100644 index 0000000..346a5ce --- /dev/null +++ b/test/fixtures/output/java/unirest/malicious.java @@ -0,0 +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-value-test", "'") + .header("dquote-value-test", "\"") + .header("backtick-value-test", "`") + .header("dollar-parenthesis-value-test", "$(") + .header("hash-brace-value-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", "\\") + .body("' \" ` $( #{ %( %{ {{ \\0 %s \\") + .asString(); \ No newline at end of file diff --git a/test/fixtures/output/javascript/jquery/malicious.js b/test/fixtures/output/javascript/jquery/malicious.js new file mode 100644 index 0000000..476209e --- /dev/null +++ b/test/fixtures/output/javascript/jquery/malicious.js @@ -0,0 +1,24 @@ +const settings = { + "async": true, + "crossDomain": true, + "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-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": "\\" + }, + "data": "' \" ` $( #{ %( %{ {{ \\0 %s \\" +}; + +$.ajax(settings).done(function (response) { + console.log(response); +}); \ No newline at end of file diff --git a/test/fixtures/output/javascript/xhr/malicious.js b/test/fixtures/output/javascript/xhr/malicious.js new file mode 100644 index 0000000..d998152 --- /dev/null +++ b/test/fixtures/output/javascript/xhr/malicious.js @@ -0,0 +1,25 @@ +const data = "' \" ` $( #{ %( %{ {{ \\0 %s \\"; + +const xhr = new XMLHttpRequest(); +xhr.withCredentials = true; + +xhr.addEventListener("readystatechange", function () { + if (this.readyState === this.DONE) { + console.log(this.responseText); + } +}); + +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-value-test", "'"); +xhr.setRequestHeader("dquote-value-test", "\""); +xhr.setRequestHeader("backtick-value-test", "`"); +xhr.setRequestHeader("dollar-parenthesis-value-test", "$("); +xhr.setRequestHeader("hash-brace-value-test", "#{"); +xhr.setRequestHeader("percent-parenthesis-value-test", "%("); +xhr.setRequestHeader("percent-brace-value-test", "%{"); +xhr.setRequestHeader("double-brace-value-test", "{{"); +xhr.setRequestHeader("null-value-test", "\\0"); +xhr.setRequestHeader("string-fmt-value-test", "%s"); +xhr.setRequestHeader("slash-value-test", "\\"); + +xhr.send(data); \ No newline at end of file diff --git a/test/fixtures/output/kotlin/okhttp/malicious.kt b/test/fixtures/output/kotlin/okhttp/malicious.kt new file mode 100644 index 0000000..ccd65e0 --- /dev/null +++ b/test/fixtures/output/kotlin/okhttp/malicious.kt @@ -0,0 +1,21 @@ +val client = OkHttpClient() + +val mediaType = MediaType.parse("text/plain") +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-value-test", "'") + .addHeader("dquote-value-test", "\"") + .addHeader("backtick-value-test", "`") + .addHeader("dollar-parenthesis-value-test", "$(") + .addHeader("hash-brace-value-test", "#{") + .addHeader("percent-parenthesis-value-test", "%(") + .addHeader("percent-brace-value-test", "%{") + .addHeader("double-brace-value-test", "{{") + .addHeader("null-value-test", "\\0") + .addHeader("string-fmt-value-test", "%s") + .addHeader("slash-value-test", "\\") + .build() + +val response = client.newCall(request).execute() \ No newline at end of file diff --git a/test/fixtures/output/node/native/malicious.js b/test/fixtures/output/node/native/malicious.js new file mode 100644 index 0000000..830baac --- /dev/null +++ b/test/fixtures/output/node/native/malicious.js @@ -0,0 +1,37 @@ +const http = require("http"); + +const options = { + "method": "POST", + "hostname": "example.test", + "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-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": "\\" + } +}; + +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.write("' \" ` $( #{ %( %{ {{ \\0 %s \\"); +req.end(); \ No newline at end of file diff --git a/test/fixtures/output/node/unirest/malicious.js b/test/fixtures/output/node/unirest/malicious.js new file mode 100644 index 0000000..58f76fd --- /dev/null +++ b/test/fixtures/output/node/unirest/malicious.js @@ -0,0 +1,50 @@ +const unirest = require("unirest"); + +const req = unirest("POST", "http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//"); + +req.query({ + "'": "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": "\\" +}); + +req.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": "\\" +}); + +req.send("' \" ` $( #{ %( %{ {{ \\0 %s \\"); + +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/ocaml/cohttp/malicious.ml b/test/fixtures/output/ocaml/cohttp/malicious.ml new file mode 100644 index 0000000..20b0757 --- /dev/null +++ b/test/fixtures/output/ocaml/cohttp/malicious.ml @@ -0,0 +1,23 @@ +open Cohttp_lwt_unix +open Cohttp +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-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", "\\"); +] in +let body = Cohttp_lwt_body.of_string "' \" ` $( #{ %( %{ {{ \\0 %s \\" in + +Client.call ~headers ~body `POST uri +>>= fun (res, body_stream) -> + (* Do stuff with the result *) \ No newline at end of file diff --git a/test/fixtures/output/php/curl/malicious.php b/test/fixtures/output/php/curl/malicious.php new file mode 100644 index 0000000..10b4e54 --- /dev/null +++ b/test/fixtures/output/php/curl/malicious.php @@ -0,0 +1,38 @@ + "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_MAXREDIRS => 10, + CURLOPT_TIMEOUT => 30, + CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, + CURLOPT_CUSTOMREQUEST => "POST", + CURLOPT_POSTFIELDS => "' \" ` $( #{ %( %{ {{ \\0 %s \\", + CURLOPT_HTTPHEADER => [ + "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" + ], +]); + +$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/malicious.php b/test/fixtures/output/php/http1/malicious.php new file mode 100644 index 0000000..de63752 --- /dev/null +++ b/test/fixtures/output/php/http1/malicious.php @@ -0,0 +1,54 @@ +setUrl('http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//'); +$request->setMethod(HTTP_METH_POST); + +$request->setQueryData([ + '\'' => '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' => '\\' +]); + +$request->setHeaders([ + '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' => '\\' +]); + +$request->setBody('\' " ` $( #{ %( %{ {{ \\0 %s \\'); + +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/malicious.php b/test/fixtures/output/php/http2/malicious.php new file mode 100644 index 0000000..0dea61b --- /dev/null +++ b/test/fixtures/output/php/http2/malicious.php @@ -0,0 +1,55 @@ +append('\' " ` $( #{ %( %{ {{ \\0 %s \\'); + +$request->setRequestUrl('http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//'); +$request->setRequestMethod('POST'); +$request->setBody($body); + +$request->setQuery(new http\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' => '\\' +])); + +$request->setHeaders([ + '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' => '\\' +]); + +$client->enqueue($request)->send(); +$response = $client->getResponse(); + +echo $response->getBody(); \ No newline at end of file diff --git a/test/fixtures/output/python/python3/malicious.py b/test/fixtures/output/python/python3/malicious.py new file mode 100644 index 0000000..706ecd0 --- /dev/null +++ b/test/fixtures/output/python/python3/malicious.py @@ -0,0 +1,26 @@ +import http.client + +conn = http.client.HTTPConnection("example.test") + +payload = "' \" ` $( #{ %( %{ {{ \\0 %s \\" + +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": "\\" +} + +conn.request("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", payload, headers) + +res = conn.getresponse() +data = res.read() + +print(data.decode("utf-8")) \ No newline at end of file diff --git a/test/fixtures/output/ruby/native/malicious.rb b/test/fixtures/output/ruby/native/malicious.rb new file mode 100644 index 0000000..9755a8a --- /dev/null +++ b/test/fixtures/output/ruby/native/malicious.rb @@ -0,0 +1,23 @@ +require 'uri' +require 'net/http' + +url = 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") + +http = Net::HTTP.new(url.host, url.port) + +request = Net::HTTP::Post.new(url) +request["squote-value-test"] = '\'' +request["dquote-value-test"] = '"' +request["backtick-value-test"] = '`' +request["dollar-parenthesis-value-test"] = '$(' +request["hash-brace-value-test"] = '#{' +request["percent-parenthesis-value-test"] = '%(' +request["percent-brace-value-test"] = '%{' +request["double-brace-value-test"] = '{{' +request["null-value-test"] = '\\0' +request["string-fmt-value-test"] = '%s' +request["slash-value-test"] = '\\' +request.body = "' \" ` $( #{ %( %{ {{ \\0 %s \\" + +response = http.request(request) +puts response.read_body \ No newline at end of file diff --git a/test/fixtures/output/shell/curl/malicious.sh b/test/fixtures/output/shell/curl/malicious.sh new file mode 100644 index 0000000..19c1c8d --- /dev/null +++ b/test/fixtures/output/shell/curl/malicious.sh @@ -0,0 +1,14 @@ +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 'backtick-value-test: `' \ + --header 'dollar-parenthesis-value-test: $(' \ + --header 'double-brace-value-test: {{' \ + --header 'dquote-value-test: "' \ + --header 'hash-brace-value-test: #{' \ + --header 'null-value-test: \0' \ + --header 'percent-brace-value-test: %{' \ + --header 'percent-parenthesis-value-test: %(' \ + --header 'slash-value-test: \' \ + --header 'squote-value-test: '\''' \ + --header 'string-fmt-value-test: %s' \ + --data ''\'' " ` $( #{ %( %{ {{ \0 %s \' \ No newline at end of file diff --git a/test/fixtures/output/shell/httpie/malicious.sh b/test/fixtures/output/shell/httpie/malicious.sh new file mode 100644 index 0000000..5a44864 --- /dev/null +++ b/test/fixtures/output/shell/httpie/malicious.sh @@ -0,0 +1,13 @@ +echo ''\'' " ` $( #{ %( %{ {{ \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' \ + 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 \ No newline at end of file diff --git a/test/fixtures/output/shell/wget/malicious.sh b/test/fixtures/output/shell/wget/malicious.sh new file mode 100644 index 0000000..cdd5905 --- /dev/null +++ b/test/fixtures/output/shell/wget/malicious.sh @@ -0,0 +1,16 @@ +wget --quiet \ + --method POST \ + --header 'squote-value-test: '\''' \ + --header 'dquote-value-test: "' \ + --header 'backtick-value-test: `' \ + --header 'dollar-parenthesis-value-test: $(' \ + --header 'hash-brace-value-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: \' \ + --body-data ''\'' " ` $( #{ %( %{ {{ \0 %s \' \ + --output-document \ + - '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' \ No newline at end of file diff --git a/test/fixtures/requests/malicious.json b/test/fixtures/requests/malicious.json new file mode 100644 index 0000000..1ad354e --- /dev/null +++ b/test/fixtures/requests/malicious.json @@ -0,0 +1,144 @@ +{ + "method": "POST", + "url": "http://example.test/'\"`$(%(%{{{\\0%s\\/", + "queryString": [ + { + "name": "'", + "value": "squote-key-test" + }, + { + "name": "squote-value-test", + "value": "'" + }, + { + "name": "\"", + "value": "dquote-key-test" + }, + { + "name": "dquote-value-test", + "value": "\"" + }, + { + "name": "`", + "value": "backtick-key-test" + }, + { + "name": "backtick-value-test", + "value": "`" + }, + { + "name": "$(", + "value": "dollar-parenthesis-key-test" + }, + { + "name": "dollar-parenthesis-value-test", + "value": "$(" + }, + { + "name": "#{", + "value": "hash-brace-key-test" + }, + { + "name": "hash-brace-value-test", + "value": "#{" + }, + { + "name": "%(", + "value": "percent-parenthesis-key-test" + }, + { + "name": "percent-parenthesis-value-test", + "value": "%(" + }, + { + "name": "%{", + "value": "percent-brace-key-test" + }, + { + "name": "percent-brace-value-test", + "value": "%{" + }, + { + "name": "{{", + "value": "double-brace-key-test" + }, + { + "name": "double-brace-value-test", + "value": "{{" + }, + { + "name": "\\0", + "value": "null-key-test" + }, + { + "name": "null-value-test", + "value": "\\0" + }, + { + "name": "%s", + "value": "string-fmt-key-test" + }, + { + "name": "string-fmt-value-test", + "value": "%s" + }, + { + "name": "\\", + "value": "slash-key-test" + }, + { + "name": "slash-value-test", + "value": "\\" + } + ], + "headers": [ + { + "name": "squote-value-test", + "value": "'" + }, + { + "name": "dquote-value-test", + "value": "\"" + }, + { + "name": "backtick-value-test", + "value": "`" + }, + { + "name": "dollar-parenthesis-value-test", + "value": "$(" + }, + { + "name": "hash-brace-value-test", + "value": "#{" + }, + { + "name": "percent-parenthesis-value-test", + "value": "%(" + }, + { + "name": "percent-brace-value-test", + "value": "%{" + }, + { + "name": "double-brace-value-test", + "value": "{{" + }, + { + "name": "null-value-test", + "value": "\\0" + }, + { + "name": "string-fmt-value-test", + "value": "%s" + }, + { + "name": "slash-value-test", + "value": "\\" + } + ], + "postData": { + "mimeType": "text/plain", + "text": "' \" ` $( #{ %( %{ {{ \\0 %s \\" + } + } diff --git a/test/targets.js b/test/targets.js index 58d77e3..d9ff38c 100644 --- a/test/targets.js +++ b/test/targets.js @@ -42,7 +42,32 @@ const itShouldHaveInfo = function (name, obj) { // TODO: investigate issues with these fixtures const skipMe = { clojure: { - clj_http: ['jsonObj-null-value', 'jsonObj-multiline'] + clj_http: ['jsonObj-null-value', 'jsonObj-multiline', 'malicious'] + }, + javascript: { + axios: ['malicious'], + fetch: ['malicious'] + }, + node: { + axios: ['malicious'], + fetch: ['malicious'], + request: ['malicious'] + }, + objc: { + nsurlsession: ['malicious'] + }, + powershell: { + restmethod: ['malicious'], + webrequest: ['malicious'] + }, + python: { + requests: ['malicious'] + }, + r: { + httr: ['malicious'] + }, + swift: { + nsurlsession: ['malicious'] }, '*': { '*': [] From 23b7e63eea8d31bf955c817b18ff6c4a9b5f7f33 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Mon, 1 Jul 2024 19:07:36 +0200 Subject: [PATCH 41/83] Fix JS test cases for in-depth escaping scenario --- package-lock.json | 62 +------- package.json | 3 +- src/helpers/stringify-js-object.js | 134 ++++++++++++++++++ src/targets/javascript/axios.js | 2 +- src/targets/javascript/fetch.js | 4 +- src/targets/node/axios.js | 2 +- src/targets/node/fetch.js | 4 +- src/targets/node/native.js | 2 +- src/targets/node/request.js | 2 +- .../output/javascript/axios/malicious.js | 50 +++++++ .../javascript/fetch/application-json.js | 2 +- .../output/javascript/fetch/malicious.js | 22 +++ test/fixtures/output/node/axios/malicious.js | 50 +++++++ .../output/node/fetch/application-json.js | 2 +- test/fixtures/output/node/fetch/malicious.js | 26 ++++ .../fixtures/output/node/request/malicious.js | 50 +++++++ test/targets.js | 9 -- 17 files changed, 344 insertions(+), 82 deletions(-) create mode 100644 src/helpers/stringify-js-object.js create mode 100644 test/fixtures/output/javascript/axios/malicious.js create mode 100644 test/fixtures/output/javascript/fetch/malicious.js create mode 100644 test/fixtures/output/node/axios/malicious.js create mode 100644 test/fixtures/output/node/fetch/malicious.js create mode 100644 test/fixtures/output/node/request/malicious.js diff --git a/package-lock.json b/package-lock.json index 8745b17..e507f1e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,8 +16,7 @@ "form-data": "3.0.0", "fs-readfile-promise": "^2.0.1", "fs-writefile-promise": "^1.0.3", - "har-validator": "^5.0.0", - "stringify-object": "^3.3.0" + "har-validator": "^5.0.0" }, "bin": { "httpsnippet": "bin/httpsnippet" @@ -1842,11 +1841,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-own-enumerable-property-symbols": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.0.tgz", - "integrity": "sha512-CIJYJC4GGF06TakLg8z4GQKvDsx9EMspVxOYih7LerEL/WosUnFIww45CGfxfeKHqlg3twgUrYRT1O3WQqjGCg==" - }, "node_modules/get-stdin": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", @@ -2201,14 +2195,6 @@ "node": ">=0.12.0" } }, - "node_modules/is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -2245,14 +2231,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-string": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", @@ -3998,19 +3976,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/stringify-object": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", - "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", - "dependencies": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", @@ -5944,11 +5909,6 @@ } } }, - "get-own-enumerable-property-symbols": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.0.tgz", - "integrity": "sha512-CIJYJC4GGF06TakLg8z4GQKvDsx9EMspVxOYih7LerEL/WosUnFIww45CGfxfeKHqlg3twgUrYRT1O3WQqjGCg==" - }, "get-stdin": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", @@ -6203,11 +6163,6 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, - "is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" - }, "is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -6231,11 +6186,6 @@ } } }, - "is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=" - }, "is-string": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", @@ -7560,16 +7510,6 @@ } } }, - "stringify-object": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", - "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", - "requires": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" - } - }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", diff --git a/package.json b/package.json index b790218..600a9a5 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,6 @@ "form-data": "3.0.0", "fs-readfile-promise": "^2.0.1", "fs-writefile-promise": "^1.0.3", - "har-validator": "^5.0.0", - "stringify-object": "^3.3.0" + "har-validator": "^5.0.0" } } diff --git a/src/helpers/stringify-js-object.js b/src/helpers/stringify-js-object.js new file mode 100644 index 0000000..186b351 --- /dev/null +++ b/src/helpers/stringify-js-object.js @@ -0,0 +1,134 @@ +// Closely based on v5.0.0 of stringify-object (BSD-2-Clause licensed), with +// modifications to simplify it for our use case (simpler obj & regex checks +// + object key retrieval) and no awkwardly incompatible ESM. + +module.exports = (input, options, pad) => { + const seen = [] + + return (function stringify (input, options = {}, pad = '') { + const indent = options.indent || '\t' + + let tokens + if (options.inlineCharacterLimit === undefined) { + tokens = { + newline: '\n', + newlineOrSpace: '\n', + pad, + indent: pad + indent + } + } else { + tokens = { + newline: '@@__STRINGIFY_OBJECT_NEW_LINE__@@', + newlineOrSpace: '@@__STRINGIFY_OBJECT_NEW_LINE_OR_SPACE__@@', + pad: '@@__STRINGIFY_OBJECT_PAD__@@', + indent: '@@__STRINGIFY_OBJECT_INDENT__@@' + } + } + + const expandWhiteSpace = string => { + if (options.inlineCharacterLimit === undefined) { + return string + } + + const oneLined = string + .replace(new RegExp(tokens.newline, 'g'), '') + .replace(new RegExp(tokens.newlineOrSpace, 'g'), ' ') + .replace(new RegExp(tokens.pad + '|' + tokens.indent, 'g'), '') + + if (oneLined.length <= options.inlineCharacterLimit) { + return oneLined + } + + return string + .replace(new RegExp(tokens.newline + '|' + tokens.newlineOrSpace, 'g'), '\n') + .replace(new RegExp(tokens.pad, 'g'), pad) + .replace(new RegExp(tokens.indent, 'g'), pad + indent) + } + + if (seen.includes(input)) { + return '"[Circular]"' + } + + if ( + input === null || + input === undefined || + typeof input === 'number' || + typeof input === 'boolean' || + typeof input === 'function' || + typeof input === 'symbol' || + input instanceof RegExp + ) { + return String(input) + } + + if (input instanceof Date) { + return `new Date('${input.toISOString()}')` + } + + if (Array.isArray(input)) { + if (input.length === 0) { + return '[]' + } + + seen.push(input) + + const returnValue = '[' + tokens.newline + input.map((element, i) => { + const eol = input.length - 1 === i ? tokens.newline : ',' + tokens.newlineOrSpace + + let value = stringify(element, options, pad + indent) + if (options.transform) { + value = options.transform(input, i, value) + } + + return tokens.indent + value + eol + }).join('') + tokens.pad + ']' + + seen.pop() + + return expandWhiteSpace(returnValue) + } + + if (typeof input === 'object') { + let objectKeys = Object.keys(input) + + if (options.filter) { + objectKeys = objectKeys.filter(element => options.filter(input, element)) + } + + if (objectKeys.length === 0) { + return '{}' + } + + seen.push(input) + + const returnValue = '{' + tokens.newline + objectKeys.map((element, index) => { + const eol = objectKeys.length - 1 === index ? tokens.newline : ',' + tokens.newlineOrSpace + const isSymbol = typeof element === 'symbol' + const isClassic = !isSymbol && /^[a-z$_][$\w]*$/i.test(element) + const key = isSymbol || isClassic ? element : stringify(element, options) + + let value = stringify(input[element], options, pad + indent) + if (options.transform) { + value = options.transform(input, element, value) + } + + return tokens.indent + String(key) + ': ' + value + eol + }).join('') + tokens.pad + '}' + + seen.pop() + + return expandWhiteSpace(returnValue) + } + + input = input.replace(/\\/g, '\\\\') + input = String(input).replace(/[\r\n]/g, x => x === '\n' ? '\\n' : '\\r') + + if (options.singleQuotes === false) { + input = input.replace(/"/g, '\\"') + return `"${input}"` + } + + input = input.replace(/'/g, '\\\'') + return `'${input}'` + })(input, options, pad) +} diff --git a/src/targets/javascript/axios.js b/src/targets/javascript/axios.js index 838eb0d..3b3db45 100644 --- a/src/targets/javascript/axios.js +++ b/src/targets/javascript/axios.js @@ -10,7 +10,7 @@ 'use strict' const util = require('util') -const stringifyObject = require('stringify-object') +const stringifyObject = require('../../helpers/stringify-js-object') const CodeBuilder = require('../../helpers/code-builder') module.exports = function (source, options) { diff --git a/src/targets/javascript/fetch.js b/src/targets/javascript/fetch.js index f76e396..aacebc1 100644 --- a/src/targets/javascript/fetch.js +++ b/src/targets/javascript/fetch.js @@ -21,7 +21,7 @@ module.exports = function (source, options) { options ) - const stringifyObject = require('stringify-object') + const stringifyObject = require('../../helpers/stringify-js-object') const code = new CodeBuilder(opts.indent) options = { @@ -85,7 +85,7 @@ module.exports = function (source, options) { .blank() } - code.push("fetch('%s', options)", source.fullUrl) + code.push('fetch(%s, options)', stringifyObject(source.fullUrl)) .push(1, '.then(response => response.json())') .push(1, '.then(response => console.log(response))') .push(1, '.catch(err => console.error(err));') diff --git a/src/targets/node/axios.js b/src/targets/node/axios.js index 92387de..8bf49e4 100644 --- a/src/targets/node/axios.js +++ b/src/targets/node/axios.js @@ -10,7 +10,7 @@ 'use strict' const util = require('util') -const stringifyObject = require('stringify-object') +const stringifyObject = require('../../helpers/stringify-js-object') const CodeBuilder = require('../../helpers/code-builder') module.exports = function (source, options) { diff --git a/src/targets/node/fetch.js b/src/targets/node/fetch.js index 971d817..3ed4a43 100644 --- a/src/targets/node/fetch.js +++ b/src/targets/node/fetch.js @@ -10,7 +10,7 @@ 'use strict' -const stringifyObject = require('stringify-object') +const stringifyObject = require('../../helpers/stringify-js-object') const CodeBuilder = require('../../helpers/code-builder') module.exports = function (source, options) { @@ -88,7 +88,7 @@ module.exports = function (source, options) { } } code.blank() - code.push('let url = \'' + url + '\';') + code.push('let url = ' + stringifyObject(url) + ';') .blank() code.push('let options = %s;', stringifyObject(reqOpts, { indent: ' ', inlineCharacterLimit: 80 })) .blank() diff --git a/src/targets/node/native.js b/src/targets/node/native.js index a6d8332..bb6e3fb 100644 --- a/src/targets/node/native.js +++ b/src/targets/node/native.js @@ -10,7 +10,7 @@ 'use strict' -const stringifyObject = require('stringify-object') +const stringifyObject = require('../../helpers/stringify-js-object') const CodeBuilder = require('../../helpers/code-builder') module.exports = function (source, options) { diff --git a/src/targets/node/request.js b/src/targets/node/request.js index 258c736..b47e9f5 100644 --- a/src/targets/node/request.js +++ b/src/targets/node/request.js @@ -11,7 +11,7 @@ 'use strict' const util = require('util') -const stringifyObject = require('stringify-object') +const stringifyObject = require('../../helpers/stringify-js-object') const CodeBuilder = require('../../helpers/code-builder') module.exports = function (source, options) { diff --git a/test/fixtures/output/javascript/axios/malicious.js b/test/fixtures/output/javascript/axios/malicious.js new file mode 100644 index 0000000..c6a440e --- /dev/null +++ b/test/fixtures/output/javascript/axios/malicious.js @@ -0,0 +1,50 @@ +import axios from "axios"; + +const options = { + method: 'POST', + url: 'http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//', + params: { + '\'': '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': '\\' + }, + 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': '\\' + }, + data: '\' " ` $( #{ %( %{ {{ \\0 %s \\' +}; + +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/application-json.js b/test/fixtures/output/javascript/fetch/application-json.js index 7aeb551..d1ef8ff 100644 --- a/test/fixtures/output/javascript/fetch/application-json.js +++ b/test/fixtures/output/javascript/fetch/application-json.js @@ -1,7 +1,7 @@ const options = { method: 'POST', headers: {'content-type': 'application/json'}, - body: '{"number":1,"string":"f\"oo","arr":[1,2,3],"nested":{"a":"b"},"arr_mix":[1,"a",{"arr_mix_nested":{}}],"boolean":false}' + body: '{"number":1,"string":"f\\"oo","arr":[1,2,3],"nested":{"a":"b"},"arr_mix":[1,"a",{"arr_mix_nested":{}}],"boolean":false}' }; fetch('http://mockbin.com/har', options) diff --git a/test/fixtures/output/javascript/fetch/malicious.js b/test/fixtures/output/javascript/fetch/malicious.js new file mode 100644 index 0000000..3a02317 --- /dev/null +++ b/test/fixtures/output/javascript/fetch/malicious.js @@ -0,0 +1,22 @@ +const options = { + method: 'POST', + 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': '\\' + }, + body: '\' " ` $( #{ %( %{ {{ \\0 %s \\' +}; + +fetch('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', 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/node/axios/malicious.js b/test/fixtures/output/node/axios/malicious.js new file mode 100644 index 0000000..c0c381f --- /dev/null +++ b/test/fixtures/output/node/axios/malicious.js @@ -0,0 +1,50 @@ +var axios = require("axios").default; + +var options = { + method: 'POST', + url: 'http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//', + params: { + '\'': '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': '\\' + }, + 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': '\\' + }, + data: '\' " ` $( #{ %( %{ {{ \\0 %s \\' +}; + +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/application-json.js b/test/fixtures/output/node/fetch/application-json.js index 618d55e..a21a86b 100644 --- a/test/fixtures/output/node/fetch/application-json.js +++ b/test/fixtures/output/node/fetch/application-json.js @@ -5,7 +5,7 @@ let url = 'http://mockbin.com/har'; let options = { method: 'POST', headers: {'content-type': 'application/json'}, - body: '{"number":1,"string":"f\"oo","arr":[1,2,3],"nested":{"a":"b"},"arr_mix":[1,"a",{"arr_mix_nested":{}}],"boolean":false}' + body: '{"number":1,"string":"f\\"oo","arr":[1,2,3],"nested":{"a":"b"},"arr_mix":[1,"a",{"arr_mix_nested":{}}],"boolean":false}' }; fetch(url, options) diff --git a/test/fixtures/output/node/fetch/malicious.js b/test/fixtures/output/node/fetch/malicious.js new file mode 100644 index 0000000..6f286b7 --- /dev/null +++ b/test/fixtures/output/node/fetch/malicious.js @@ -0,0 +1,26 @@ +const fetch = require('node-fetch'); + +let 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'; + +let options = { + method: 'POST', + 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': '\\' + }, + body: '\' " ` $( #{ %( %{ {{ \\0 %s \\' +}; + +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/request/malicious.js b/test/fixtures/output/node/request/malicious.js new file mode 100644 index 0000000..f502254 --- /dev/null +++ b/test/fixtures/output/node/request/malicious.js @@ -0,0 +1,50 @@ +const request = require('request'); + +const options = { + method: 'POST', + url: 'http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//', + qs: { + '\'': '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': '\\' + }, + 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': '\\' + }, + body: '\' " ` $( #{ %( %{ {{ \\0 %s \\' +}; + +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/targets.js b/test/targets.js index d9ff38c..2f9a2cc 100644 --- a/test/targets.js +++ b/test/targets.js @@ -44,15 +44,6 @@ const skipMe = { clojure: { clj_http: ['jsonObj-null-value', 'jsonObj-multiline', 'malicious'] }, - javascript: { - axios: ['malicious'], - fetch: ['malicious'] - }, - node: { - axios: ['malicious'], - fetch: ['malicious'], - request: ['malicious'] - }, objc: { nsurlsession: ['malicious'] }, From 01ec1044318ae7bdafb5c7509b33cfd3d6bddeae Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Mon, 1 Jul 2024 19:30:29 +0200 Subject: [PATCH 42/83] Fix clojure test cases for in-depth escaping scenario --- src/targets/clojure/clj_http.js | 12 +++++-- .../output/clojure/clj_http/malicious.clj | 36 +++++++++++++++++++ .../output/clojure/clj_http/nested.clj | 2 +- test/targets.js | 2 +- 4 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 test/fixtures/output/clojure/clj_http/malicious.clj diff --git a/src/targets/clojure/clj_http.js b/src/targets/clojure/clj_http.js index dd92864..82dc069 100644 --- a/src/targets/clojure/clj_http.js +++ b/src/targets/clojure/clj_http.js @@ -12,6 +12,7 @@ const CodeBuilder = require('../../helpers/code-builder') const helpers = require('../../helpers/headers') +const { escape } = require('../../helpers/format') const Keyword = function (name) { this.name = name @@ -60,7 +61,7 @@ const padBlock = function (x, s) { const jsToEdn = function (js) { switch (jsType(js)) { case 'string': - return '"' + js.replace(/"/g, '\\"') + '"' + return '"' + escape(js, { delimiter: '"' }) + '"' case 'file': return js.toString() case 'keyword': @@ -73,7 +74,14 @@ const jsToEdn = function (js) { const obj = Object.keys(js) .reduce(function (acc, key) { const val = padBlock(key.length + 2, jsToEdn(js[key])) - return acc + ':' + key + ' ' + val + '\n ' + + // This check is overly strict, but good enough for us for + // all typical HTTP values we care about + const safeKey = key.match(/^[a-zA-Z_][\w-]*$/) + ? ':' + key + : jsToEdn(key) + + return acc + safeKey + ' ' + val + '\n ' }, '') .trim() return '{' + padBlock(1, obj) + '}' diff --git a/test/fixtures/output/clojure/clj_http/malicious.clj b/test/fixtures/output/clojure/clj_http/malicious.clj new file mode 100644 index 0000000..9c99ba8 --- /dev/null +++ b/test/fixtures/output/clojure/clj_http/malicious.clj @@ -0,0 +1,36 @@ +(require '[clj-http.client :as client]) + +(client/post "http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//" {: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 "\\"} + :query-params {"'" "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 "\\"} + :body "' \" ` $( #{ %( %{ {{ \\0 %s \\"}) \ No newline at end of file diff --git a/test/fixtures/output/clojure/clj_http/nested.clj b/test/fixtures/output/clojure/clj_http/nested.clj index 73016ab..24a7dd6 100644 --- a/test/fixtures/output/clojure/clj_http/nested.clj +++ b/test/fixtures/output/clojure/clj_http/nested.clj @@ -1,5 +1,5 @@ (require '[clj-http.client :as client]) -(client/get "http://mockbin.com/har" {:query-params {:foo[bar] "baz,zap" +(client/get "http://mockbin.com/har" {:query-params {"foo[bar]" "baz,zap" :fiz "buz" :key "value"}}) diff --git a/test/targets.js b/test/targets.js index 2f9a2cc..cd74ae9 100644 --- a/test/targets.js +++ b/test/targets.js @@ -42,7 +42,7 @@ const itShouldHaveInfo = function (name, obj) { // TODO: investigate issues with these fixtures const skipMe = { clojure: { - clj_http: ['jsonObj-null-value', 'jsonObj-multiline', 'malicious'] + clj_http: ['jsonObj-null-value', 'jsonObj-multiline'] }, objc: { nsurlsession: ['malicious'] From 91ba1b418b77b8d32b9a271a6330c7917307a5a5 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Mon, 1 Jul 2024 20:19:53 +0200 Subject: [PATCH 43/83] Fix ObjC test cases for in-depth escaping scenario --- src/targets/objc/helpers.js | 4 ++- src/targets/objc/nsurlsession.js | 4 ++- .../output/objc/nsurlsession/malicious.m | 34 +++++++++++++++++++ test/targets.js | 3 -- 4 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 test/fixtures/output/objc/nsurlsession/malicious.m diff --git a/src/targets/objc/helpers.js b/src/targets/objc/helpers.js index 14d136e..18ded19 100644 --- a/src/targets/objc/helpers.js +++ b/src/targets/objc/helpers.js @@ -2,6 +2,8 @@ const util = require('util') +const { escape } = require('../../helpers/format') + module.exports = { /** * Create an string of given length filled with blank spaces @@ -73,7 +75,7 @@ module.exports = { if (value === null || value === undefined) { return '' } - return '@"' + value.toString().replace(/"/g, '\\"') + '"' + return '@"' + escape(value.toString(), { delimiter: '"' }) + '"' } } } diff --git a/src/targets/objc/nsurlsession.js b/src/targets/objc/nsurlsession.js index 1f17600..b3f7173 100644 --- a/src/targets/objc/nsurlsession.js +++ b/src/targets/objc/nsurlsession.js @@ -91,7 +91,9 @@ module.exports = function (source, options) { default: code.blank() - .push('NSData *postData = [[NSData alloc] initWithData:[@"' + source.postData.text + '" dataUsingEncoding:NSUTF8StringEncoding]];') + .push('NSData *postData = [[NSData alloc] initWithData:[' + + helpers.literalRepresentation(source.postData.text) + + ' dataUsingEncoding:NSUTF8StringEncoding]];') } } diff --git a/test/fixtures/output/objc/nsurlsession/malicious.m b/test/fixtures/output/objc/nsurlsession/malicious.m new file mode 100644 index 0000000..9c5ff77 --- /dev/null +++ b/test/fixtures/output/objc/nsurlsession/malicious.m @@ -0,0 +1,34 @@ +#import + +NSDictionary *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": @"\\" }; + +NSData *postData = [[NSData alloc] initWithData:[@"' \" ` $( #{ %( %{ {{ \\0 %s \\" dataUsingEncoding:NSUTF8StringEncoding]]; + +NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"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"] + cachePolicy:NSURLRequestUseProtocolCachePolicy + timeoutInterval:10.0]; +[request setHTTPMethod:@"POST"]; +[request setAllHTTPHeaderFields:headers]; +[request setHTTPBody:postData]; + +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/targets.js b/test/targets.js index cd74ae9..b9a9f55 100644 --- a/test/targets.js +++ b/test/targets.js @@ -44,9 +44,6 @@ const skipMe = { clojure: { clj_http: ['jsonObj-null-value', 'jsonObj-multiline'] }, - objc: { - nsurlsession: ['malicious'] - }, powershell: { restmethod: ['malicious'], webrequest: ['malicious'] From 24847f26c3e98bd1b5882000927c40316c3502bd Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Tue, 2 Jul 2024 13:07:06 +0200 Subject: [PATCH 44/83] Fix powershell test cases for in-depth escaping scenario This also handles a few other cases not specifically covered by the new scenario but which are obviously easily fixable --- src/targets/powershell/common.js | 37 +++++++++++++++---- .../restmethod/application-form-encoded.ps1 | 2 +- .../restmethod/application-json.ps1 | 2 +- .../powershell/restmethod/compression.ps1 | 2 +- .../output/powershell/restmethod/full.ps1 | 4 +- .../output/powershell/restmethod/headers.ps1 | 6 +-- .../restmethod/jsonObj-multiline.ps1 | 2 +- .../restmethod/jsonObj-null-value.ps1 | 2 +- .../powershell/restmethod/malicious.ps1 | 13 +++++++ .../powershell/restmethod/multipart-data.ps1 | 2 +- .../powershell/restmethod/multipart-file.ps1 | 2 +- .../restmethod/multipart-form-data.ps1 | 2 +- .../powershell/restmethod/text-plain.ps1 | 2 +- .../webrequest/application-form-encoded.ps1 | 2 +- .../webrequest/application-json.ps1 | 2 +- .../powershell/webrequest/compression.ps1 | 2 +- .../output/powershell/webrequest/full.ps1 | 4 +- .../output/powershell/webrequest/headers.ps1 | 6 +-- .../webrequest/jsonObj-multiline.ps1 | 2 +- .../webrequest/jsonObj-null-value.ps1 | 2 +- .../powershell/webrequest/malicious.ps1 | 13 +++++++ .../powershell/webrequest/multipart-data.ps1 | 2 +- .../powershell/webrequest/multipart-file.ps1 | 2 +- .../webrequest/multipart-form-data.ps1 | 2 +- .../powershell/webrequest/text-plain.ps1 | 2 +- test/targets.js | 4 -- 26 files changed, 83 insertions(+), 40 deletions(-) create mode 100644 test/fixtures/output/powershell/restmethod/malicious.ps1 create mode 100644 test/fixtures/output/powershell/webrequest/malicious.ps1 diff --git a/src/targets/powershell/common.js b/src/targets/powershell/common.js index fd32b85..aa5497e 100644 --- a/src/targets/powershell/common.js +++ b/src/targets/powershell/common.js @@ -1,9 +1,16 @@ 'use strict' const CodeBuilder = require('../../helpers/code-builder') -const { escape } = require('../../helpers/format') const helpers = require('../../helpers/headers') +// Within a single quote, the ONLY character to worry about is the single quote +// itself (escaped by doubling). Newlines, backticks, slashes etc are all treated +// as literal characters. +const psSqEscape = function (input) { + return input + .replace(/'/g, "''") +} + module.exports = function (command) { return function (source, options) { const code = new CodeBuilder() @@ -23,7 +30,10 @@ module.exports = function (command) { code.push('$headers=@{}') headers.forEach(function (key) { if (key !== 'connection') { // Not allowed - code.push('$headers.Add("%s", "%s")', key, escape(source.headersObj[key], { escapeChar: '`' })) + code.push("$headers.Add('%s', '%s')", + psSqEscape(key), + psSqEscape(source.headersObj[key]) + ) } }) commandOptions.push('-Headers $headers') @@ -36,9 +46,9 @@ module.exports = function (command) { source.cookies.forEach(function (cookie) { code.push('$cookie = New-Object System.Net.Cookie') - code.push("$cookie.Name = '%s'", cookie.name) - code.push("$cookie.Value = '%s'", cookie.value) - code.push("$cookie.Domain = '%s'", source.uriObj.host) + code.push("$cookie.Name = '%s'", psSqEscape(cookie.name)) + code.push("$cookie.Value = '%s'", psSqEscape(cookie.value)) + code.push("$cookie.Domain = '%s'", psSqEscape(source.uriObj.host)) code.push('$session.Cookies.Add($cookie)') }) @@ -46,11 +56,22 @@ module.exports = function (command) { } if (source.postData.text) { - commandOptions.push("-ContentType '" + helpers.getHeader(source.allHeaders, 'content-type') + "'") - commandOptions.push("-Body '" + source.postData.text + "'") + const contentType = helpers.getHeader(source.allHeaders, 'content-type') + if (contentType) { + commandOptions.push("-ContentType '" + psSqEscape(contentType) + "'") + } + + commandOptions.push( + "-Body '" + psSqEscape(source.postData.text) + "'" + ) } - code.push("$response = %s -Uri '%s' -Method %s %s", command, source.fullUrl, source.method, commandOptions.join(' ')) + code.push("$response = %s -Uri '%s' -Method %s %s", + command, + psSqEscape(source.fullUrl), + source.method, + commandOptions.join(' ') + ) return code.join() } } diff --git a/test/fixtures/output/powershell/restmethod/application-form-encoded.ps1 b/test/fixtures/output/powershell/restmethod/application-form-encoded.ps1 index 5cb5452..72ed8e1 100644 --- a/test/fixtures/output/powershell/restmethod/application-form-encoded.ps1 +++ b/test/fixtures/output/powershell/restmethod/application-form-encoded.ps1 @@ -1,3 +1,3 @@ $headers=@{} -$headers.Add("content-type", "application/x-www-form-urlencoded") +$headers.Add('content-type', 'application/x-www-form-urlencoded') $response = Invoke-RestMethod -Uri 'http://mockbin.com/har' -Method POST -Headers $headers -ContentType 'application/x-www-form-urlencoded' -Body 'foo=bar&hello=world' diff --git a/test/fixtures/output/powershell/restmethod/application-json.ps1 b/test/fixtures/output/powershell/restmethod/application-json.ps1 index 326ca27..ccd7418 100644 --- a/test/fixtures/output/powershell/restmethod/application-json.ps1 +++ b/test/fixtures/output/powershell/restmethod/application-json.ps1 @@ -1,3 +1,3 @@ $headers=@{} -$headers.Add("content-type", "application/json") +$headers.Add('content-type', 'application/json') $response = Invoke-RestMethod -Uri 'http://mockbin.com/har' -Method POST -Headers $headers -ContentType 'application/json' -Body '{"number":1,"string":"f\"oo","arr":[1,2,3],"nested":{"a":"b"},"arr_mix":[1,"a",{"arr_mix_nested":{}}],"boolean":false}' diff --git a/test/fixtures/output/powershell/restmethod/compression.ps1 b/test/fixtures/output/powershell/restmethod/compression.ps1 index c7d2e5a..f56137d 100644 --- a/test/fixtures/output/powershell/restmethod/compression.ps1 +++ b/test/fixtures/output/powershell/restmethod/compression.ps1 @@ -1,3 +1,3 @@ $headers=@{} -$headers.Add("accept-encoding", "deflate, gzip, br") +$headers.Add('accept-encoding', 'deflate, gzip, br') $response = Invoke-RestMethod -Uri 'http://mockbin.com/har' -Method GET -Headers $headers \ No newline at end of file diff --git a/test/fixtures/output/powershell/restmethod/full.ps1 b/test/fixtures/output/powershell/restmethod/full.ps1 index 1872466..6dc2d29 100644 --- a/test/fixtures/output/powershell/restmethod/full.ps1 +++ b/test/fixtures/output/powershell/restmethod/full.ps1 @@ -1,6 +1,6 @@ $headers=@{} -$headers.Add("accept", "application/json") -$headers.Add("content-type", "application/x-www-form-urlencoded") +$headers.Add('accept', 'application/json') +$headers.Add('content-type', 'application/x-www-form-urlencoded') $session = New-Object Microsoft.PowerShell.Commands.WebRequestSession $cookie = New-Object System.Net.Cookie $cookie.Name = 'foo' diff --git a/test/fixtures/output/powershell/restmethod/headers.ps1 b/test/fixtures/output/powershell/restmethod/headers.ps1 index 5f81709..ce31cb3 100644 --- a/test/fixtures/output/powershell/restmethod/headers.ps1 +++ b/test/fixtures/output/powershell/restmethod/headers.ps1 @@ -1,5 +1,5 @@ $headers=@{} -$headers.Add("accept", "application/json") -$headers.Add("x-foo", "Bar") -$headers.Add("quoted-value", "`"quoted`" 'string'") +$headers.Add('accept', 'application/json') +$headers.Add('x-foo', 'Bar') +$headers.Add('quoted-value', '"quoted" ''string''') $response = Invoke-RestMethod -Uri 'http://mockbin.com/har' -Method GET -Headers $headers diff --git a/test/fixtures/output/powershell/restmethod/jsonObj-multiline.ps1 b/test/fixtures/output/powershell/restmethod/jsonObj-multiline.ps1 index 3221803..810dc49 100644 --- a/test/fixtures/output/powershell/restmethod/jsonObj-multiline.ps1 +++ b/test/fixtures/output/powershell/restmethod/jsonObj-multiline.ps1 @@ -1,5 +1,5 @@ $headers=@{} -$headers.Add("content-type", "application/json") +$headers.Add('content-type', 'application/json') $response = Invoke-RestMethod -Uri 'http://mockbin.com/har' -Method POST -Headers $headers -ContentType 'application/json' -Body '{ "foo": "bar" }' diff --git a/test/fixtures/output/powershell/restmethod/jsonObj-null-value.ps1 b/test/fixtures/output/powershell/restmethod/jsonObj-null-value.ps1 index 68c52ea..7593e66 100644 --- a/test/fixtures/output/powershell/restmethod/jsonObj-null-value.ps1 +++ b/test/fixtures/output/powershell/restmethod/jsonObj-null-value.ps1 @@ -1,3 +1,3 @@ $headers=@{} -$headers.Add("content-type", "application/json") +$headers.Add('content-type', 'application/json') $response = Invoke-RestMethod -Uri 'http://mockbin.com/har' -Method POST -Headers $headers -ContentType 'application/json' -Body '{"foo":null}' diff --git a/test/fixtures/output/powershell/restmethod/malicious.ps1 b/test/fixtures/output/powershell/restmethod/malicious.ps1 new file mode 100644 index 0000000..da17c73 --- /dev/null +++ b/test/fixtures/output/powershell/restmethod/malicious.ps1 @@ -0,0 +1,13 @@ +$headers=@{} +$headers.Add('squote-value-test', '''') +$headers.Add('dquote-value-test', '"') +$headers.Add('backtick-value-test', '`') +$headers.Add('dollar-parenthesis-value-test', '$(') +$headers.Add('hash-brace-value-test', '#{') +$headers.Add('percent-parenthesis-value-test', '%(') +$headers.Add('percent-brace-value-test', '%{') +$headers.Add('double-brace-value-test', '{{') +$headers.Add('null-value-test', '\0') +$headers.Add('string-fmt-value-test', '%s') +$headers.Add('slash-value-test', '\') +$response = Invoke-RestMethod -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' -Method POST -Headers $headers -Body ''' " ` $( #{ %( %{ {{ \0 %s \' \ No newline at end of file diff --git a/test/fixtures/output/powershell/restmethod/multipart-data.ps1 b/test/fixtures/output/powershell/restmethod/multipart-data.ps1 index 9324af5..c98b409 100644 --- a/test/fixtures/output/powershell/restmethod/multipart-data.ps1 +++ b/test/fixtures/output/powershell/restmethod/multipart-data.ps1 @@ -1,5 +1,5 @@ $headers=@{} -$headers.Add("content-type", "multipart/form-data; boundary=---011000010111000001101001") +$headers.Add('content-type', 'multipart/form-data; boundary=---011000010111000001101001') $response = Invoke-RestMethod -Uri 'http://mockbin.com/har' -Method POST -Headers $headers -ContentType 'multipart/form-data; boundary=---011000010111000001101001' -Body '-----011000010111000001101001 Content-Disposition: form-data; name="foo"; filename="hello.txt" Content-Type: text/plain diff --git a/test/fixtures/output/powershell/restmethod/multipart-file.ps1 b/test/fixtures/output/powershell/restmethod/multipart-file.ps1 index e1329cb..9a60551 100644 --- a/test/fixtures/output/powershell/restmethod/multipart-file.ps1 +++ b/test/fixtures/output/powershell/restmethod/multipart-file.ps1 @@ -1,5 +1,5 @@ $headers=@{} -$headers.Add("content-type", "multipart/form-data; boundary=---011000010111000001101001") +$headers.Add('content-type', 'multipart/form-data; boundary=---011000010111000001101001') $response = Invoke-RestMethod -Uri 'http://mockbin.com/har' -Method POST -Headers $headers -ContentType 'multipart/form-data; boundary=---011000010111000001101001' -Body '-----011000010111000001101001 Content-Disposition: form-data; name="foo"; filename="hello.txt" Content-Type: text/plain diff --git a/test/fixtures/output/powershell/restmethod/multipart-form-data.ps1 b/test/fixtures/output/powershell/restmethod/multipart-form-data.ps1 index bb78bfb..f48c03e 100644 --- a/test/fixtures/output/powershell/restmethod/multipart-form-data.ps1 +++ b/test/fixtures/output/powershell/restmethod/multipart-form-data.ps1 @@ -1,5 +1,5 @@ $headers=@{} -$headers.Add("Content-Type", "multipart/form-data; boundary=---011000010111000001101001") +$headers.Add('Content-Type', 'multipart/form-data; boundary=---011000010111000001101001') $response = Invoke-RestMethod -Uri 'http://mockbin.com/har' -Method POST -Headers $headers -ContentType 'multipart/form-data; boundary=---011000010111000001101001' -Body '-----011000010111000001101001 Content-Disposition: form-data; name="foo" diff --git a/test/fixtures/output/powershell/restmethod/text-plain.ps1 b/test/fixtures/output/powershell/restmethod/text-plain.ps1 index ccfdf49..5cf7d20 100644 --- a/test/fixtures/output/powershell/restmethod/text-plain.ps1 +++ b/test/fixtures/output/powershell/restmethod/text-plain.ps1 @@ -1,3 +1,3 @@ $headers=@{} -$headers.Add("content-type", "text/plain") +$headers.Add('content-type', 'text/plain') $response = Invoke-RestMethod -Uri 'http://mockbin.com/har' -Method POST -Headers $headers -ContentType 'text/plain' -Body 'Hello World' diff --git a/test/fixtures/output/powershell/webrequest/application-form-encoded.ps1 b/test/fixtures/output/powershell/webrequest/application-form-encoded.ps1 index 9ea45de..cd01c2b 100644 --- a/test/fixtures/output/powershell/webrequest/application-form-encoded.ps1 +++ b/test/fixtures/output/powershell/webrequest/application-form-encoded.ps1 @@ -1,3 +1,3 @@ $headers=@{} -$headers.Add("content-type", "application/x-www-form-urlencoded") +$headers.Add('content-type', 'application/x-www-form-urlencoded') $response = Invoke-WebRequest -Uri 'http://mockbin.com/har' -Method POST -Headers $headers -ContentType 'application/x-www-form-urlencoded' -Body 'foo=bar&hello=world' diff --git a/test/fixtures/output/powershell/webrequest/application-json.ps1 b/test/fixtures/output/powershell/webrequest/application-json.ps1 index 786292d..024d331 100644 --- a/test/fixtures/output/powershell/webrequest/application-json.ps1 +++ b/test/fixtures/output/powershell/webrequest/application-json.ps1 @@ -1,3 +1,3 @@ $headers=@{} -$headers.Add("content-type", "application/json") +$headers.Add('content-type', 'application/json') $response = Invoke-WebRequest -Uri 'http://mockbin.com/har' -Method POST -Headers $headers -ContentType 'application/json' -Body '{"number":1,"string":"f\"oo","arr":[1,2,3],"nested":{"a":"b"},"arr_mix":[1,"a",{"arr_mix_nested":{}}],"boolean":false}' diff --git a/test/fixtures/output/powershell/webrequest/compression.ps1 b/test/fixtures/output/powershell/webrequest/compression.ps1 index 1e9ada0..4cdbf72 100644 --- a/test/fixtures/output/powershell/webrequest/compression.ps1 +++ b/test/fixtures/output/powershell/webrequest/compression.ps1 @@ -1,3 +1,3 @@ $headers=@{} -$headers.Add("accept-encoding", "deflate, gzip, br") +$headers.Add('accept-encoding', 'deflate, gzip, br') $response = Invoke-WebRequest -Uri 'http://mockbin.com/har' -Method GET -Headers $headers \ No newline at end of file diff --git a/test/fixtures/output/powershell/webrequest/full.ps1 b/test/fixtures/output/powershell/webrequest/full.ps1 index 42e308f..5e22949 100644 --- a/test/fixtures/output/powershell/webrequest/full.ps1 +++ b/test/fixtures/output/powershell/webrequest/full.ps1 @@ -1,6 +1,6 @@ $headers=@{} -$headers.Add("accept", "application/json") -$headers.Add("content-type", "application/x-www-form-urlencoded") +$headers.Add('accept', 'application/json') +$headers.Add('content-type', 'application/x-www-form-urlencoded') $session = New-Object Microsoft.PowerShell.Commands.WebRequestSession $cookie = New-Object System.Net.Cookie $cookie.Name = 'foo' diff --git a/test/fixtures/output/powershell/webrequest/headers.ps1 b/test/fixtures/output/powershell/webrequest/headers.ps1 index 03d1296..d23512b 100644 --- a/test/fixtures/output/powershell/webrequest/headers.ps1 +++ b/test/fixtures/output/powershell/webrequest/headers.ps1 @@ -1,5 +1,5 @@ $headers=@{} -$headers.Add("accept", "application/json") -$headers.Add("x-foo", "Bar") -$headers.Add("quoted-value", "`"quoted`" 'string'") +$headers.Add('accept', 'application/json') +$headers.Add('x-foo', 'Bar') +$headers.Add('quoted-value', '"quoted" ''string''') $response = Invoke-WebRequest -Uri 'http://mockbin.com/har' -Method GET -Headers $headers diff --git a/test/fixtures/output/powershell/webrequest/jsonObj-multiline.ps1 b/test/fixtures/output/powershell/webrequest/jsonObj-multiline.ps1 index 6548f20..4ed84da 100644 --- a/test/fixtures/output/powershell/webrequest/jsonObj-multiline.ps1 +++ b/test/fixtures/output/powershell/webrequest/jsonObj-multiline.ps1 @@ -1,5 +1,5 @@ $headers=@{} -$headers.Add("content-type", "application/json") +$headers.Add('content-type', 'application/json') $response = Invoke-WebRequest -Uri 'http://mockbin.com/har' -Method POST -Headers $headers -ContentType 'application/json' -Body '{ "foo": "bar" }' diff --git a/test/fixtures/output/powershell/webrequest/jsonObj-null-value.ps1 b/test/fixtures/output/powershell/webrequest/jsonObj-null-value.ps1 index 1ee9a4f..3be77fa 100644 --- a/test/fixtures/output/powershell/webrequest/jsonObj-null-value.ps1 +++ b/test/fixtures/output/powershell/webrequest/jsonObj-null-value.ps1 @@ -1,3 +1,3 @@ $headers=@{} -$headers.Add("content-type", "application/json") +$headers.Add('content-type', 'application/json') $response = Invoke-WebRequest -Uri 'http://mockbin.com/har' -Method POST -Headers $headers -ContentType 'application/json' -Body '{"foo":null}' diff --git a/test/fixtures/output/powershell/webrequest/malicious.ps1 b/test/fixtures/output/powershell/webrequest/malicious.ps1 new file mode 100644 index 0000000..4676ad7 --- /dev/null +++ b/test/fixtures/output/powershell/webrequest/malicious.ps1 @@ -0,0 +1,13 @@ +$headers=@{} +$headers.Add('squote-value-test', '''') +$headers.Add('dquote-value-test', '"') +$headers.Add('backtick-value-test', '`') +$headers.Add('dollar-parenthesis-value-test', '$(') +$headers.Add('hash-brace-value-test', '#{') +$headers.Add('percent-parenthesis-value-test', '%(') +$headers.Add('percent-brace-value-test', '%{') +$headers.Add('double-brace-value-test', '{{') +$headers.Add('null-value-test', '\0') +$headers.Add('string-fmt-value-test', '%s') +$headers.Add('slash-value-test', '\') +$response = Invoke-WebRequest -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' -Method POST -Headers $headers -Body ''' " ` $( #{ %( %{ {{ \0 %s \' \ No newline at end of file diff --git a/test/fixtures/output/powershell/webrequest/multipart-data.ps1 b/test/fixtures/output/powershell/webrequest/multipart-data.ps1 index 64a05c8..e483ba0 100644 --- a/test/fixtures/output/powershell/webrequest/multipart-data.ps1 +++ b/test/fixtures/output/powershell/webrequest/multipart-data.ps1 @@ -1,5 +1,5 @@ $headers=@{} -$headers.Add("content-type", "multipart/form-data; boundary=---011000010111000001101001") +$headers.Add('content-type', 'multipart/form-data; boundary=---011000010111000001101001') $response = Invoke-WebRequest -Uri 'http://mockbin.com/har' -Method POST -Headers $headers -ContentType 'multipart/form-data; boundary=---011000010111000001101001' -Body '-----011000010111000001101001 Content-Disposition: form-data; name="foo"; filename="hello.txt" Content-Type: text/plain diff --git a/test/fixtures/output/powershell/webrequest/multipart-file.ps1 b/test/fixtures/output/powershell/webrequest/multipart-file.ps1 index c1dc54b..7c6bfd1 100644 --- a/test/fixtures/output/powershell/webrequest/multipart-file.ps1 +++ b/test/fixtures/output/powershell/webrequest/multipart-file.ps1 @@ -1,5 +1,5 @@ $headers=@{} -$headers.Add("content-type", "multipart/form-data; boundary=---011000010111000001101001") +$headers.Add('content-type', 'multipart/form-data; boundary=---011000010111000001101001') $response = Invoke-WebRequest -Uri 'http://mockbin.com/har' -Method POST -Headers $headers -ContentType 'multipart/form-data; boundary=---011000010111000001101001' -Body '-----011000010111000001101001 Content-Disposition: form-data; name="foo"; filename="hello.txt" Content-Type: text/plain diff --git a/test/fixtures/output/powershell/webrequest/multipart-form-data.ps1 b/test/fixtures/output/powershell/webrequest/multipart-form-data.ps1 index 91f16b8..92b1a25 100644 --- a/test/fixtures/output/powershell/webrequest/multipart-form-data.ps1 +++ b/test/fixtures/output/powershell/webrequest/multipart-form-data.ps1 @@ -1,5 +1,5 @@ $headers=@{} -$headers.Add("Content-Type", "multipart/form-data; boundary=---011000010111000001101001") +$headers.Add('Content-Type', 'multipart/form-data; boundary=---011000010111000001101001') $response = Invoke-WebRequest -Uri 'http://mockbin.com/har' -Method POST -Headers $headers -ContentType 'multipart/form-data; boundary=---011000010111000001101001' -Body '-----011000010111000001101001 Content-Disposition: form-data; name="foo" diff --git a/test/fixtures/output/powershell/webrequest/text-plain.ps1 b/test/fixtures/output/powershell/webrequest/text-plain.ps1 index 876683a..f095d4b 100644 --- a/test/fixtures/output/powershell/webrequest/text-plain.ps1 +++ b/test/fixtures/output/powershell/webrequest/text-plain.ps1 @@ -1,3 +1,3 @@ $headers=@{} -$headers.Add("content-type", "text/plain") +$headers.Add('content-type', 'text/plain') $response = Invoke-WebRequest -Uri 'http://mockbin.com/har' -Method POST -Headers $headers -ContentType 'text/plain' -Body 'Hello World' diff --git a/test/targets.js b/test/targets.js index b9a9f55..501821c 100644 --- a/test/targets.js +++ b/test/targets.js @@ -44,10 +44,6 @@ const skipMe = { clojure: { clj_http: ['jsonObj-null-value', 'jsonObj-multiline'] }, - powershell: { - restmethod: ['malicious'], - webrequest: ['malicious'] - }, python: { requests: ['malicious'] }, From 0a7fa5d504d9fe84511e6742ef6dac6b954d15e5 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Tue, 2 Jul 2024 16:34:02 +0200 Subject: [PATCH 45/83] Fix python test cases for in-depth escaping scenario --- src/targets/python/helpers.js | 7 ++- .../output/python/requests/malicious.py | 47 +++++++++++++++++++ test/targets.js | 3 -- 3 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 test/fixtures/output/python/requests/malicious.py diff --git a/src/targets/python/helpers.js b/src/targets/python/helpers.js index a3c5ee7..cdec9ca 100644 --- a/src/targets/python/helpers.js +++ b/src/targets/python/helpers.js @@ -62,7 +62,12 @@ module.exports = { case '[object Object]': { const keyValuePairs = [] for (const k in value) { - keyValuePairs.push(util.format('"%s": %s', k, this.literalRepresentation(value[k], opts, indentLevel))) + keyValuePairs.push( + util.format('%s: %s', + this.literalRepresentation(k, opts, indentLevel), + this.literalRepresentation(value[k], opts, indentLevel) + ) + ) } return concatValues('object', keyValuePairs, opts.pretty && keyValuePairs.length > 1, opts.indent, indentLevel) } diff --git a/test/fixtures/output/python/requests/malicious.py b/test/fixtures/output/python/requests/malicious.py new file mode 100644 index 0000000..0e9a043 --- /dev/null +++ b/test/fixtures/output/python/requests/malicious.py @@ -0,0 +1,47 @@ +import requests + +url = "http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//" + +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": "\\" +} + +payload = "' \" ` $( #{ %( %{ {{ \\0 %s \\" +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": "\\" +} + +response = requests.post(url, data=payload, headers=headers, params=querystring) + +print(response.text) \ No newline at end of file diff --git a/test/targets.js b/test/targets.js index 501821c..2c0e61a 100644 --- a/test/targets.js +++ b/test/targets.js @@ -44,9 +44,6 @@ const skipMe = { clojure: { clj_http: ['jsonObj-null-value', 'jsonObj-multiline'] }, - python: { - requests: ['malicious'] - }, r: { httr: ['malicious'] }, From b3a3ff7dfcd40b3b86fb7e45c2094d392ce8adae Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Tue, 2 Jul 2024 16:40:24 +0200 Subject: [PATCH 46/83] Fix Swift test cases for in-depth escaping scenario (and others) --- src/targets/swift/helpers.js | 10 ++++-- src/targets/swift/nsurlsession.js | 10 +++--- .../output/swift/nsurlsession/malicious.swift | 36 +++++++++++++++++++ test/targets.js | 3 -- 4 files changed, 49 insertions(+), 10 deletions(-) create mode 100644 test/fixtures/output/swift/nsurlsession/malicious.swift diff --git a/src/targets/swift/helpers.js b/src/targets/swift/helpers.js index 62a2121..1a609fc 100644 --- a/src/targets/swift/helpers.js +++ b/src/targets/swift/helpers.js @@ -1,6 +1,7 @@ 'use strict' const util = require('util') +const { escape } = require('../../helpers/format') /** * Create an string of given length filled with blank spaces @@ -72,7 +73,12 @@ module.exports = { case '[object Object]': { const keyValuePairs = [] for (const k in value) { - keyValuePairs.push(util.format('"%s": %s', k, this.literalRepresentation(value[k], opts, indentLevel))) + keyValuePairs.push( + util.format('%s: %s', + this.literalRepresentation(k, opts, indentLevel), + this.literalRepresentation(value[k], opts, indentLevel) + ) + ) } return concatArray(keyValuePairs, opts.pretty && keyValuePairs.length > 1, opts.indent, indentLevel) } @@ -84,7 +90,7 @@ module.exports = { if (value === null || value === undefined) { return '' } - return '"' + value.toString().replace(/"/g, '\\"') + '"' + return '"' + escape(value.toString()) + '"' } } } diff --git a/src/targets/swift/nsurlsession.js b/src/targets/swift/nsurlsession.js index d3b48a7..d57548c 100644 --- a/src/targets/swift/nsurlsession.js +++ b/src/targets/swift/nsurlsession.js @@ -46,9 +46,9 @@ module.exports = function (source, options) { // we make it easier for the user to edit it according to his or her needs after pasting. // The user can just add/remove lines adding/removing body parameters. code.blank() - .push('let postData = NSMutableData(data: "%s=%s".data(using: String.Encoding.utf8)!)', source.postData.params[0].name, source.postData.params[0].value) + .push('let postData = NSMutableData(data: "%qd=%qd".data(using: String.Encoding.utf8)!)', source.postData.params[0].name, source.postData.params[0].value) for (let i = 1, len = source.postData.params.length; i < len; i++) { - code.push('postData.append("&%s=%s".data(using: String.Encoding.utf8)!)', source.postData.params[i].name, source.postData.params[i].value) + code.push('postData.append("&%qd=%qd".data(using: String.Encoding.utf8)!)', source.postData.params[i].name, source.postData.params[i].value) } break @@ -68,7 +68,7 @@ module.exports = function (source, options) { */ code.push(helpers.literalDeclaration('parameters', source.postData.params, opts)) .blank() - .push('let boundary = "%s"', source.postData.boundary) + .push('let boundary = "%qd"', source.postData.boundary) .blank() .push('var body = ""') .push('var error: NSError? = nil') @@ -93,13 +93,13 @@ module.exports = function (source, options) { default: code.blank() - .push('let postData = NSData(data: "%s".data(using: String.Encoding.utf8)!)', source.postData.text) + .push('let postData = NSData(data: "%qd".data(using: String.Encoding.utf8)!)', source.postData.text) } } code.blank() // NSURLRequestUseProtocolCachePolicy is the default policy, let's just always set it to avoid confusion. - .push('let request = NSMutableURLRequest(url: NSURL(string: "%s")! as URL,', source.fullUrl) + .push('let request = NSMutableURLRequest(url: NSURL(string: "%qd")! as URL,', source.fullUrl) .push(' cachePolicy: .useProtocolCachePolicy,') .push(' timeoutInterval: %s)', parseInt(opts.timeout, 10).toFixed(1)) .push('request.httpMethod = "%s"', source.method) diff --git a/test/fixtures/output/swift/nsurlsession/malicious.swift b/test/fixtures/output/swift/nsurlsession/malicious.swift new file mode 100644 index 0000000..a6c5ff6 --- /dev/null +++ b/test/fixtures/output/swift/nsurlsession/malicious.swift @@ -0,0 +1,36 @@ +import Foundation + +let 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": "\\" +] + +let postData = NSData(data: "' \" ` $( #{ %( %{ {{ \\0 %s \\".data(using: String.Encoding.utf8)!) + +let request = NSMutableURLRequest(url: NSURL(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")! as URL, + cachePolicy: .useProtocolCachePolicy, + timeoutInterval: 10.0) +request.httpMethod = "POST" +request.allHTTPHeaderFields = headers +request.httpBody = postData as Data + +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/targets.js b/test/targets.js index 2c0e61a..ce38024 100644 --- a/test/targets.js +++ b/test/targets.js @@ -47,9 +47,6 @@ const skipMe = { r: { httr: ['malicious'] }, - swift: { - nsurlsession: ['malicious'] - }, '*': { '*': [] } From ebf709c31238e4c47c70060092db7d4873c1e676 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Tue, 2 Jul 2024 17:02:10 +0200 Subject: [PATCH 47/83] Fix R test cases for in-depth escaping scenario --- src/targets/r/httr.js | 8 ++++-- test/fixtures/output/r/httr/malicious.r | 36 +++++++++++++++++++++++++ test/fixtures/output/r/httr/nested.r | 2 +- test/targets.js | 3 --- 4 files changed, 43 insertions(+), 6 deletions(-) create mode 100644 test/fixtures/output/r/httr/malicious.r diff --git a/src/targets/r/httr.js b/src/targets/r/httr.js index 5a7f557..11ba99a 100644 --- a/src/targets/r/httr.js +++ b/src/targets/r/httr.js @@ -41,10 +41,14 @@ module.exports = function (source, options) { code.push('queryString <- list(') for (const query in qs) { + const safeKey = query.match(/^[a-zA-Z][\w._]*$/) + ? query + : '"' + escape(query) + '"' + if (count++ !== queryCount - 1) { - code.push(' %s = "%s",', query, qs[query].toString()) + code.push(' %s = "%qd",', safeKey, qs[query].toString()) } else { - code.push(' %s = "%s"', query, qs[query].toString()) + code.push(' %s = "%qd"', safeKey, qs[query].toString()) } } diff --git a/test/fixtures/output/r/httr/malicious.r b/test/fixtures/output/r/httr/malicious.r new file mode 100644 index 0000000..8275064 --- /dev/null +++ b/test/fixtures/output/r/httr/malicious.r @@ -0,0 +1,36 @@ +library(httr) + +url <- "http://example.test/%27%22%60$(%(%%7B%7B%7B/0%s//" + +queryString <- list( + "'" = "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" = "\\", +) + +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) + +content(response, "text") \ No newline at end of file diff --git a/test/fixtures/output/r/httr/nested.r b/test/fixtures/output/r/httr/nested.r index 669352c..07aa1a1 100644 --- a/test/fixtures/output/r/httr/nested.r +++ b/test/fixtures/output/r/httr/nested.r @@ -3,7 +3,7 @@ library(httr) url <- "http://mockbin.com/har" queryString <- list( - foo[bar] = "baz,zap", + "foo[bar]" = "baz,zap", fiz = "buz" ) diff --git a/test/targets.js b/test/targets.js index ce38024..58d77e3 100644 --- a/test/targets.js +++ b/test/targets.js @@ -44,9 +44,6 @@ const skipMe = { clojure: { clj_http: ['jsonObj-null-value', 'jsonObj-multiline'] }, - r: { - httr: ['malicious'] - }, '*': { '*': [] } From 65658c1e1e39497a6c0f11cf11827fdaf3613dd3 Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Tue, 2 Jul 2024 18:13:21 +0200 Subject: [PATCH 48/83] 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 49/83] 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 50/83] 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 51/83] 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 52/83] 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 53/83] 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 54/83] 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 55/83] 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 56/83] 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 57/83] 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 58/83] 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 59/83] 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 60/83] 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 61/83] 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 62/83] 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 63/83] 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 64/83] 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 65/83] 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 66/83] 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 67/83] 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 68/83] 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 69/83] 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 70/83] 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 71/83] 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 72/83] 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 73/83] 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 74/83] 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 75/83] 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 76/83] 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 77/83] 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 78/83] 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 79/83] 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 80/83] 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 81/83] 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 82/83] 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 83/83] 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 ",