From b638fac379a8aa35740d1f6f48a4cf9ea5a2c431 Mon Sep 17 00:00:00 2001 From: Nick K Date: Thu, 12 Aug 2021 16:57:51 +0300 Subject: [PATCH 01/14] Implement multipart/form-data encoding using form-data-encoder. --- package.json | 2 ++ source/core/index.ts | 11 +++++++++++ source/core/options.ts | 8 +++++--- test/headers.ts | 23 +++++++++++++++++++++++ 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 6542fed18..ff6c3a45e 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,8 @@ "cacheable-lookup": "^6.0.0", "cacheable-request": "^7.0.2", "decompress-response": "^6.0.0", + "form-data-encoder": "^1.4.3", + "formdata-node": "^3.6.4", "get-stream": "^6.0.1", "http2-wrapper": "^2.0.7", "lowercase-keys": "^2.0.0", diff --git a/source/core/index.ts b/source/core/index.ts index 601aa3486..477c09604 100644 --- a/source/core/index.ts +++ b/source/core/index.ts @@ -8,6 +8,7 @@ import CacheableRequest from 'cacheable-request'; import decompressResponse from 'decompress-response'; import is from '@sindresorhus/is'; import {buffer as getBuffer} from 'get-stream'; +import {FormDataEncoder, isFormDataLike} from 'form-data-encoder'; import type {ClientRequestWithTimings, Timings, IncomingMessageWithTimings} from '@szmarczak/http-timer'; import type ResponseLike from 'responselike'; import getBodySize from './utils/get-body-size.js'; @@ -570,6 +571,16 @@ export default class Request extends Duplex implements RequestEvents { const noContentType = !is.string(headers['content-type']); if (isBody) { + // Body is spec-compliant FormData + if (isFormDataLike(options.body) && noContentType) { + const encoder = new FormDataEncoder(options.body); + + headers['content-type'] = encoder.headers['Content-Type']; + headers['content-length'] = encoder.headers['Content-Length']; + + options.body = encoder.encode(); + } + // Special case for https://github.com/form-data/form-data if (isFormData(options.body) && noContentType) { headers['content-type'] = `multipart/form-data; boundary=${options.body.getBoundary()}`; diff --git a/source/core/options.ts b/source/core/options.ts index 7c070cf78..aa1cd4aca 100644 --- a/source/core/options.ts +++ b/source/core/options.ts @@ -19,6 +19,8 @@ import is, {assert} from '@sindresorhus/is'; import lowercaseKeys from 'lowercase-keys'; import CacheableLookup from 'cacheable-lookup'; import http2wrapper, {ClientHttp2Session} from 'http2-wrapper'; +import {isFormDataLike} from 'form-data-encoder'; +import type {FormDataLike} from 'form-data-encoder'; import type CacheableRequest from 'cacheable-request'; import type ResponseLike from 'responselike'; import type {IncomingMessageWithTimings} from '@szmarczak/http-timer'; @@ -1179,12 +1181,12 @@ export default class Options { Since Got 12, the `content-length` is not automatically set when `body` is a `fs.createReadStream`. */ - get body(): string | Buffer | Readable | Generator | AsyncGenerator | undefined { + get body(): string | Buffer | Readable | Generator | AsyncGenerator | FormDataLike | undefined { return this._internals.body; } - set body(value: string | Buffer | Readable | Generator | AsyncGenerator | undefined) { - assert.any([is.string, is.buffer, is.nodeStream, is.generator, is.asyncGenerator, is.undefined], value); + set body(value: string | Buffer | Readable | Generator | AsyncGenerator | FormDataLike | undefined) { + assert.any([is.string, is.buffer, is.nodeStream, is.generator, is.asyncGenerator, isFormDataLike, is.undefined], value); if (is.nodeStream(value)) { assert.truthy(value.readable); diff --git a/test/headers.ts b/test/headers.ts index d56ac605e..f0fc4e8b2 100644 --- a/test/headers.ts +++ b/test/headers.ts @@ -3,6 +3,8 @@ import path from 'path'; import test from 'ava'; import {Handler} from 'express'; import FormData from 'form-data'; +import {FormDataEncoder} from 'form-data-encoder'; +import {FormData as FormDataNode} from 'formdata-node'; import got, {Headers} from '../source/index.js'; import withServer from './helpers/with-server.js'; @@ -173,6 +175,27 @@ test('form-data sets `content-length` header', withServer, async (t, server, got t.is(headers['content-length'], '157'); }); +test('sets `content-type` header for spec-compliant FormData', withServer, async (t, server, got) => { + server.post('/', echoHeaders); + + const form = new FormDataNode(); + form.set('a', 'b'); + const {body} = await got.post({body: form}); + const headers = JSON.parse(body); + t.true((headers['content-type'] as string).startsWith('multipart/form-data')); +}); + +test('sets `content-length` header for spec-compliant FormData', withServer, async (t, server, got) => { + server.post('/', echoHeaders); + + const form = new FormDataNode(); + form.set('a', 'b'); + const encoder = new FormDataEncoder(form); + const {body} = await got.post({body: form}); + const headers = JSON.parse(body); + t.is(headers['content-length'], encoder.headers['Content-Length']); +}); + test('stream as `options.body` does not set `content-length` header', withServer, async (t, server, got) => { server.post('/', echoHeaders); From a3c944676628e26bfb55ed190d2bdb983a87a860 Mon Sep 17 00:00:00 2001 From: Nick K Date: Thu, 12 Aug 2021 18:27:02 +0300 Subject: [PATCH 02/14] fix: Move formdata-node to devDependencies. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ff6c3a45e..45b5bcc92 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,6 @@ "cacheable-request": "^7.0.2", "decompress-response": "^6.0.0", "form-data-encoder": "^1.4.3", - "formdata-node": "^3.6.4", "get-stream": "^6.0.1", "http2-wrapper": "^2.0.7", "lowercase-keys": "^2.0.0", @@ -83,6 +82,7 @@ "delay": "^5.0.0", "express": "^4.17.1", "form-data": "^4.0.0", + "formdata-node": "^3.6.4", "nock": "^13.1.1", "node-fetch": "^2.6.1", "np": "^7.5.0", From 56454f6130e76b9667637bd07fa0547784845aa7 Mon Sep 17 00:00:00 2001 From: Nick K Date: Thu, 12 Aug 2021 21:34:58 +0300 Subject: [PATCH 03/14] Add test for custom headers usage with spec-compliant FormData. Set content-type header provided by form-data-encoder only if this header is not set by a developer. Mention spec-compliant FormData implementations in documentation. --- documentation/2-options.md | 18 +++++++++++++++++- source/core/index.ts | 9 ++++++--- test/headers.ts | 15 +++++++++++++++ 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/documentation/2-options.md b/documentation/2-options.md index 0ac3faacb..86230be70 100644 --- a/documentation/2-options.md +++ b/documentation/2-options.md @@ -271,7 +271,7 @@ stream.on('data', console.log); ### `body` -**Type: `string | Buffer | stream.Readable | Generator | AsyncGenerator` or [`form-data` instance](https://github.com/form-data/form-data)** +**Type: `string | Buffer | stream.Readable | Generator | AsyncGenerator | FormData` or [`form-data` instance](https://github.com/form-data/form-data)** The payload to send. @@ -290,6 +290,22 @@ console.log(data); //=> 'Hello, world!' ``` +Since Got 12 you can use spec-compliant FormData objects as request body, such as [`formdata-node`](https://github.com/octet-stream/form-data) or [`formdata-polyfill`](https://github.com/jimmywarting/FormData): + +```js +import got from 'got'; + +import {FormData} from 'formdata-node'; // or 'formdata-polyfill/esm.min.js' + +const form = new FormData(); + +form.set('greeting', 'Hello, world!'); + +const {data} = await got.post('https://httpbin.org/post', { + body: form +}); +``` + #### **Note:** > - If `body` is specified, then the `json` or `form` option cannot be used. diff --git a/source/core/index.ts b/source/core/index.ts index 477c09604..566f15ae9 100644 --- a/source/core/index.ts +++ b/source/core/index.ts @@ -128,7 +128,7 @@ const proxiedRequestEvents = [ 'upgrade', ] as const; -const noop = () => {}; +const noop = (): void => {}; type UrlType = ConstructorParameters[0]; type OptionsType = ConstructorParameters[1]; @@ -572,10 +572,13 @@ export default class Request extends Duplex implements RequestEvents { if (isBody) { // Body is spec-compliant FormData - if (isFormDataLike(options.body) && noContentType) { + if (isFormDataLike(options.body)) { const encoder = new FormDataEncoder(options.body); - headers['content-type'] = encoder.headers['Content-Type']; + if (noContentType) { + headers['content-type'] = encoder.headers['Content-Type']; + } + headers['content-length'] = encoder.headers['Content-Length']; options.body = encoder.encode(); diff --git a/test/headers.ts b/test/headers.ts index f0fc4e8b2..c1b551d31 100644 --- a/test/headers.ts +++ b/test/headers.ts @@ -196,6 +196,21 @@ test('sets `content-length` header for spec-compliant FormData', withServer, asy t.is(headers['content-length'], encoder.headers['Content-Length']); }); +test('manual `content-type` header should be allowed with spec-compliant FormData', withServer, async (t, server, got) => { + server.post('/', echoHeaders); + + const form = new FormDataNode(); + form.set('a', 'b'); + const {body} = await got.post({ + headers: { + 'content-type': 'custom' + }, + body: form, + }); + const headers = JSON.parse(body); + t.is(headers['content-type'], 'custom'); +}); + test('stream as `options.body` does not set `content-length` header', withServer, async (t, server, got) => { server.post('/', echoHeaders); From 3a6182b0ff890e9fb771fcb635390a5e8c39d7ac Mon Sep 17 00:00:00 2001 From: Nick K Date: Thu, 12 Aug 2021 21:42:31 +0300 Subject: [PATCH 04/14] Remove unnecessary empty line from options example. Co-authored-by: Szymon Marczak <36894700+szmarczak@users.noreply.github.com> --- documentation/2-options.md | 1 - 1 file changed, 1 deletion(-) diff --git a/documentation/2-options.md b/documentation/2-options.md index 86230be70..84448ea0c 100644 --- a/documentation/2-options.md +++ b/documentation/2-options.md @@ -294,7 +294,6 @@ Since Got 12 you can use spec-compliant FormData objects as request body, such a ```js import got from 'got'; - import {FormData} from 'formdata-node'; // or 'formdata-polyfill/esm.min.js' const form = new FormData(); From 60ee1992aa1d9d6f0b441bdeb41ce779799454a4 Mon Sep 17 00:00:00 2001 From: Nick K Date: Fri, 13 Aug 2021 01:41:19 +0300 Subject: [PATCH 05/14] Add tests for spec-compliant FormData body in post queries. --- package.json | 1 + test/post.ts | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/package.json b/package.json index 45b5bcc92..2c7631cae 100644 --- a/package.json +++ b/package.json @@ -95,6 +95,7 @@ "sinon": "^10.0.0", "slow-stream": "0.0.4", "tempy": "^1.0.1", + "then-busboy": "^5.0.0", "to-readable-stream": "^3.0.0", "tough-cookie": "^4.0.0", "ts-node": "^10.1.0", diff --git a/test/post.ts b/test/post.ts index 4d0814680..92f6e3dc9 100644 --- a/test/post.ts +++ b/test/post.ts @@ -1,11 +1,14 @@ import {promisify} from 'util'; import stream from 'stream'; import fs from 'fs'; +import fsPromises from 'fs/promises'; import path from 'path'; import test from 'ava'; import delay from 'delay'; import pEvent from 'p-event'; import {Handler} from 'express'; +import {parse, Body, BodyRawEntries, isBodyFile} from 'then-busboy'; +import {FormData as FormDataNode, Blob, File, fileFromPath} from 'formdata-node'; import getStream from 'get-stream'; import FormData from 'form-data'; import toReadableStream from 'to-readable-stream'; @@ -23,6 +26,18 @@ const echoHeaders: Handler = (request, response) => { response.end(JSON.stringify(request.headers)); }; +const echoMultipartBody: Handler = async (request, response) => { + const body = await parse(request); + const entries: BodyRawEntries = []; + + // Read every file before respond + for (const [name, value] of body) { + entries.push([name, isBodyFile(value) ? await value.text() : value]); + } + + response.json(Body.json(entries)); +} + test('GET cannot have body without the `allowGetBody` option', withServer, async (t, server, got) => { server.post('/', defaultEndpoint); @@ -315,6 +330,37 @@ test('body - file read stream, wait for `ready` event', withServer, async (t, se t.is(toSend, body); }); +test('body - sends spec-compliant FormData', withServer, async (t, server, got) => { + server.post('/', echoMultipartBody); + + const form = new FormDataNode(); + form.set('a', 'b'); + const {body} = await got.post({body: form}); + const actual = JSON.parse(body); + t.is(actual.a, 'b'); +}); + +test('body - sends files with spec-compliant FormData', withServer, async (t, server, got) => { + server.post('/', echoMultipartBody); + + const fullPath = path.resolve('test/fixtures/ok'); + const blobContent = "Blob content"; + const fileContent = "File content"; + const anotherFileContent = await fsPromises.readFile(fullPath, 'utf-8'); + const expected = { + blob: blobContent, + file: fileContent, + anotherFile: anotherFileContent, + }; + + const form = new FormDataNode(); + form.set('blob', new Blob([blobContent])); + form.set('file', new File([fileContent], 'file.txt'), {type: 'text/plain'}); + form.set('anotherFile', await fileFromPath(fullPath), {type: 'text/plain'}); + const body = await got.post({body: form}).json(); + t.deepEqual(body, expected); +}); + test('throws on upload error', withServer, async (t, server, got) => { server.post('/', defaultEndpoint); From fac63646d7a31caefa42c2e5a70a2b3de17a6917 Mon Sep 17 00:00:00 2001 From: Nick K Date: Fri, 13 Aug 2021 03:31:16 +0300 Subject: [PATCH 06/14] Fix for response in one of multipart/form-data tests. --- test/post.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/post.ts b/test/post.ts index 92f6e3dc9..7d1b53184 100644 --- a/test/post.ts +++ b/test/post.ts @@ -335,9 +335,8 @@ test('body - sends spec-compliant FormData', withServer, async (t, server, got) const form = new FormDataNode(); form.set('a', 'b'); - const {body} = await got.post({body: form}); - const actual = JSON.parse(body); - t.is(actual.a, 'b'); + const body = await got.post({body: form}).json<{a: string}>(); + t.is(body.a, 'b'); }); test('body - sends files with spec-compliant FormData', withServer, async (t, server, got) => { From e368612a4cd71eee202fb1644f7f25d0b0399204 Mon Sep 17 00:00:00 2001 From: Nick K Date: Fri, 13 Aug 2021 03:37:04 +0300 Subject: [PATCH 07/14] Code style fixes in tests to match got code style. --- test/post.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/post.ts b/test/post.ts index 7d1b53184..b47d6eeb2 100644 --- a/test/post.ts +++ b/test/post.ts @@ -343,8 +343,8 @@ test('body - sends files with spec-compliant FormData', withServer, async (t, se server.post('/', echoMultipartBody); const fullPath = path.resolve('test/fixtures/ok'); - const blobContent = "Blob content"; - const fileContent = "File content"; + const blobContent = 'Blob content'; + const fileContent = 'File content'; const anotherFileContent = await fsPromises.readFile(fullPath, 'utf-8'); const expected = { blob: blobContent, From 5320c85ea243a7a89707e22e31b7ae5860345ab5 Mon Sep 17 00:00:00 2001 From: Nick K Date: Fri, 13 Aug 2021 14:57:47 +0300 Subject: [PATCH 08/14] Fixes for tests to match Got code style. --- test/headers.ts | 2 +- test/post.ts | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/test/headers.ts b/test/headers.ts index c1b551d31..3e7c2f6ef 100644 --- a/test/headers.ts +++ b/test/headers.ts @@ -203,7 +203,7 @@ test('manual `content-type` header should be allowed with spec-compliant FormDat form.set('a', 'b'); const {body} = await got.post({ headers: { - 'content-type': 'custom' + 'content-type': 'custom', }, body: form, }); diff --git a/test/post.ts b/test/post.ts index b47d6eeb2..7c030fcad 100644 --- a/test/post.ts +++ b/test/post.ts @@ -7,7 +7,7 @@ import test from 'ava'; import delay from 'delay'; import pEvent from 'p-event'; import {Handler} from 'express'; -import {parse, Body, BodyRawEntries, isBodyFile} from 'then-busboy'; +import {parse, Body, BodyEntryPath, BodyEntryRawValue, isBodyFile} from 'then-busboy'; import {FormData as FormDataNode, Blob, File, fileFromPath} from 'formdata-node'; import getStream from 'get-stream'; import FormData from 'form-data'; @@ -28,15 +28,11 @@ const echoHeaders: Handler = (request, response) => { const echoMultipartBody: Handler = async (request, response) => { const body = await parse(request); - const entries: BodyRawEntries = []; - - // Read every file before respond - for (const [name, value] of body) { - entries.push([name, isBodyFile(value) ? await value.text() : value]); - } + const entries = await Promise.all([...body.entries()] + .map>(async ([name, value]) => [name, isBodyFile(value) ? await value.text() : value])); response.json(Body.json(entries)); -} +}; test('GET cannot have body without the `allowGetBody` option', withServer, async (t, server, got) => { server.post('/', defaultEndpoint); From 9a0c3b9fbbe38feb6fca497dfdaa7bfb00654698 Mon Sep 17 00:00:00 2001 From: Nick K Date: Fri, 13 Aug 2021 17:59:42 +0300 Subject: [PATCH 09/14] Code style fix. --- test/post.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/post.ts b/test/post.ts index 7c030fcad..ddf312870 100644 --- a/test/post.ts +++ b/test/post.ts @@ -28,8 +28,7 @@ const echoHeaders: Handler = (request, response) => { const echoMultipartBody: Handler = async (request, response) => { const body = await parse(request); - const entries = await Promise.all([...body.entries()] - .map>(async ([name, value]) => [name, isBodyFile(value) ? await value.text() : value])); + const entries = await Promise.all([...body.entries()].map>(async ([name, value]) => [name, isBodyFile(value) ? await value.text() : value])); response.json(Body.json(entries)); }; From 5177c10d7271e494dca7669aba31e8e4e5abd07e Mon Sep 17 00:00:00 2001 From: Nick K Date: Mon, 16 Aug 2021 22:34:41 +0300 Subject: [PATCH 10/14] Add a link to FormData MDN docs in options documentation. Co-authored-by: Sindre Sorhus --- documentation/2-options.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/2-options.md b/documentation/2-options.md index 84448ea0c..0a37bde87 100644 --- a/documentation/2-options.md +++ b/documentation/2-options.md @@ -290,7 +290,7 @@ console.log(data); //=> 'Hello, world!' ``` -Since Got 12 you can use spec-compliant FormData objects as request body, such as [`formdata-node`](https://github.com/octet-stream/form-data) or [`formdata-polyfill`](https://github.com/jimmywarting/FormData): +Since Got 12, you can use spec-compliant [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) objects as request body, such as [`formdata-node`](https://github.com/octet-stream/form-data) or [`formdata-polyfill`](https://github.com/jimmywarting/FormData): ```js import got from 'got'; From 93b747c2878cd531d321defa841a782f331972a8 Mon Sep 17 00:00:00 2001 From: Nick K Date: Tue, 17 Aug 2021 02:07:36 +0300 Subject: [PATCH 11/14] Mention spec-compliant FormData in options.ts + add a ling to MDN docs. --- source/core/options.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/core/options.ts b/source/core/options.ts index aa1cd4aca..be2bcc2f4 100644 --- a/source/core/options.ts +++ b/source/core/options.ts @@ -1177,7 +1177,7 @@ export default class Options { __Note #4__: This option is not enumerable and will not be merged with the instance defaults. - The `content-length` header will be automatically set if `body` is a `string` / `Buffer` / [`form-data` instance](https://github.com/form-data/form-data), and `content-length` and `transfer-encoding` are not manually set in `options.headers`. + The `content-length` header will be automatically set if `body` is a `string` / `Buffer` / [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) / [`form-data` instance](https://github.com/form-data/form-data), and `content-length` and `transfer-encoding` are not manually set in `options.headers`. Since Got 12, the `content-length` is not automatically set when `body` is a `fs.createReadStream`. */ From 139956d8899f83a67f796b6a6f44e1b4bfdb6e0b Mon Sep 17 00:00:00 2001 From: Nick K Date: Tue, 17 Aug 2021 18:39:53 +0300 Subject: [PATCH 12/14] Update formdata-node to 4.x and fix spec-compliant FormData usage in post.ts tests. --- package.json | 2 +- test/post.ts | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 2c7631cae..09c612671 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ "delay": "^5.0.0", "express": "^4.17.1", "form-data": "^4.0.0", - "formdata-node": "^3.6.4", + "formdata-node": "^4.0.0", "nock": "^13.1.1", "node-fetch": "^2.6.1", "np": "^7.5.0", diff --git a/test/post.ts b/test/post.ts index ddf312870..a66f900bd 100644 --- a/test/post.ts +++ b/test/post.ts @@ -8,7 +8,8 @@ import delay from 'delay'; import pEvent from 'p-event'; import {Handler} from 'express'; import {parse, Body, BodyEntryPath, BodyEntryRawValue, isBodyFile} from 'then-busboy'; -import {FormData as FormDataNode, Blob, File, fileFromPath} from 'formdata-node'; +import {FormData as FormDataNode, Blob, File} from 'formdata-node'; +import {fileFromPath} from 'formdata-node/file-from-path'; import getStream from 'get-stream'; import FormData from 'form-data'; import toReadableStream from 'to-readable-stream'; @@ -349,8 +350,8 @@ test('body - sends files with spec-compliant FormData', withServer, async (t, se const form = new FormDataNode(); form.set('blob', new Blob([blobContent])); - form.set('file', new File([fileContent], 'file.txt'), {type: 'text/plain'}); - form.set('anotherFile', await fileFromPath(fullPath), {type: 'text/plain'}); + form.set('file', new File([fileContent], 'file.txt', {type: 'text/plain'})); + form.set('anotherFile', await fileFromPath(fullPath, {type: 'text/plain'})); const body = await got.post({body: form}).json(); t.deepEqual(body, expected); }); From 295257fc11f64f6073a1c9fb8e0ea9b7b1e80711 Mon Sep 17 00:00:00 2001 From: Szymon Marczak <36894700+szmarczak@users.noreply.github.com> Date: Sat, 21 Aug 2021 16:57:36 +0200 Subject: [PATCH 13/14] Update 2-options.md --- documentation/2-options.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/documentation/2-options.md b/documentation/2-options.md index 0a37bde87..58a769293 100644 --- a/documentation/2-options.md +++ b/documentation/2-options.md @@ -294,15 +294,18 @@ Since Got 12, you can use spec-compliant [`FormData`](https://developer.mozilla. ```js import got from 'got'; -import {FormData} from 'formdata-node'; // or 'formdata-polyfill/esm.min.js' +import {FormData} from 'formdata-node'; // or: +// import {FormData} from 'formdata-polyfill/esm.min.js'; const form = new FormData(); - form.set('greeting', 'Hello, world!'); -const {data} = await got.post('https://httpbin.org/post', { +const data = await got.post('https://httpbin.org/post', { body: form -}); +}).json(); + +console.log(data.form.greeting); +//=> 'Hello, world!' ``` #### **Note:** From f787188ab170c91ad4dc4db9db949f3742437a27 Mon Sep 17 00:00:00 2001 From: Szymon Marczak <36894700+szmarczak@users.noreply.github.com> Date: Sat, 21 Aug 2021 17:02:07 +0200 Subject: [PATCH 14/14] Code style --- test/post.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/post.ts b/test/post.ts index a0438b3c5..164b61143 100644 --- a/test/post.ts +++ b/test/post.ts @@ -31,7 +31,11 @@ const echoHeaders: Handler = (request, response) => { const echoMultipartBody: Handler = async (request, response) => { const body = await parse(request); - const entries = await Promise.all([...body.entries()].map>(async ([name, value]) => [name, isBodyFile(value) ? await value.text() : value])); + const entries = await Promise.all( + [...body.entries()].map>( + async ([name, value]) => [name, isBodyFile(value) ? await value.text() : value], + ), + ); response.json(Body.json(entries)); };