From f341994f19cfbd775b17d55c254f962d93c61e4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Gorej?= Date: Wed, 13 Sep 2023 09:16:00 +0200 Subject: [PATCH] feat: use FormData, File and Blob from fetch implementation (#3139) Refs #3137 --- config/jest/jest.unit.coverage.config.js | 2 +- package-lock.json | 21 ------------------- package.json | 1 - src/helpers/fetch-polyfill.browser.js | 19 ++++++++++++++++- src/helpers/fetch-polyfill.node.js | 15 +++++++++++++ src/helpers/fetch-ponyfill-node-fetch.node.js | 4 ++-- src/helpers/fetch-ponyfill-undici.node.js | 7 +++++-- src/helpers/fetch-ponyfill.browser.js | 4 ++-- src/http/index.js | 1 - test/execute/main.js | 1 - test/http/http-multipart.js | 15 +++++++++---- test/http/index.js | 1 - test/jest.setup.js | 13 +++++++++++- test/oas3/execute/build-request.js | 4 +--- 14 files changed, 67 insertions(+), 41 deletions(-) diff --git a/config/jest/jest.unit.coverage.config.js b/config/jest/jest.unit.coverage.config.js index f1d23fa74..06f882eda 100644 --- a/config/jest/jest.unit.coverage.config.js +++ b/config/jest/jest.unit.coverage.config.js @@ -6,7 +6,7 @@ module.exports = { collectCoverageFrom: ['src/**/*.js'], coverageThreshold: { './src/': { - branches: 85, + branches: 84, functions: 91, lines: 89, statements: 89, diff --git a/package-lock.json b/package-lock.json index 9b7bd7d01..eec82aa08 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,6 @@ "cookie": "~0.5.0", "deepmerge": "~4.3.0", "fast-json-patch": "^3.0.0-1", - "formdata-node": "^4.0.0", "is-plain-object": "^5.0.0", "js-yaml": "^4.1.0", "node-fetch-commonjs": "^3.3.1", @@ -7251,18 +7250,6 @@ "node": ">= 6" } }, - "node_modules/formdata-node": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", - "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", - "dependencies": { - "node-domexception": "1.0.0", - "web-streams-polyfill": "4.0.0-beta.3" - }, - "engines": { - "node": ">= 12.20" - } - }, "node_modules/fp-ts": { "version": "2.16.1", "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.16.1.tgz", @@ -14766,14 +14753,6 @@ "node": ">=10.13.0" } }, - "node_modules/web-streams-polyfill": { - "version": "4.0.0-beta.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", - "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", - "engines": { - "node": ">= 14" - } - }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", diff --git a/package.json b/package.json index e96f688d3..c97a80821 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,6 @@ "cookie": "~0.5.0", "deepmerge": "~4.3.0", "fast-json-patch": "^3.0.0-1", - "formdata-node": "^4.0.0", "is-plain-object": "^5.0.0", "js-yaml": "^4.1.0", "node-fetch-commonjs": "^3.3.1", diff --git a/src/helpers/fetch-polyfill.browser.js b/src/helpers/fetch-polyfill.browser.js index 3b5c29ffa..67de456f2 100644 --- a/src/helpers/fetch-polyfill.browser.js +++ b/src/helpers/fetch-polyfill.browser.js @@ -1,4 +1,12 @@ -import { fetch, Headers, Request, Response } from './fetch-ponyfill.browser.js'; +import { + fetch, + Headers, + Request, + Response, + FormData, + File, + Blob, +} from './fetch-ponyfill.browser.js'; if (typeof globalThis.fetch === 'undefined') { globalThis.fetch = fetch; @@ -12,3 +20,12 @@ if (typeof globalThis.Request === 'undefined') { if (typeof globalThis.Response === 'undefined') { globalThis.Response = Response; } +if (typeof globalThis.FormData === 'undefined') { + globalThis.FormData = FormData; +} +if (typeof globalThis.File === 'undefined') { + globalThis.File = File; +} +if (typeof globalThis.Blob === 'undefined') { + globalThis.Blob = Blob; +} diff --git a/src/helpers/fetch-polyfill.node.js b/src/helpers/fetch-polyfill.node.js index 5f83cabfd..d7be99e6a 100644 --- a/src/helpers/fetch-polyfill.node.js +++ b/src/helpers/fetch-polyfill.node.js @@ -3,12 +3,18 @@ import { Headers as HeaderU, Request as RequestU, Response as ResponseU, + FormData as FormDataU, + File as FileU, + Blob as BlobU, } from './fetch-ponyfill-undici.node.js'; import { fetch as fetchNF, Headers as HeadersNF, Request as RequestNF, Response as ResponseNF, + FormData as FormDataNF, + File as FileNF, + Blob as BlobNF, } from './fetch-ponyfill-node-fetch.node.js'; if (typeof globalThis.fetch === 'undefined') { @@ -23,3 +29,12 @@ if (typeof globalThis.Request === 'undefined') { if (typeof globalThis.Response === 'undefined') { globalThis.Response = ResponseU || ResponseNF; } +if (typeof globalThis.FormData === 'undefined') { + globalThis.FormData = FormDataU || FormDataNF; +} +if (typeof globalThis.File === 'undefined') { + globalThis.File = FileU || FileNF; +} +if (typeof globalThis.Blob === 'undefined') { + globalThis.Blob = BlobU || BlobNF; +} diff --git a/src/helpers/fetch-ponyfill-node-fetch.node.js b/src/helpers/fetch-ponyfill-node-fetch.node.js index 3e1a4b60c..59f02241a 100644 --- a/src/helpers/fetch-ponyfill-node-fetch.node.js +++ b/src/helpers/fetch-ponyfill-node-fetch.node.js @@ -1,4 +1,4 @@ // we cannot use `node-fetch@3` as it's pure ESM package not compatible with CommonJS -import fetch, { Response, Headers, Request } from 'node-fetch-commonjs'; +import fetch, { Response, Headers, Request, FormData, File, Blob } from 'node-fetch-commonjs'; -export { fetch, Response, Headers, Request }; +export { fetch, Response, Headers, Request, FormData, File, Blob }; diff --git a/src/helpers/fetch-ponyfill-undici.node.js b/src/helpers/fetch-ponyfill-undici.node.js index 4bf8220be..b3b479c4c 100644 --- a/src/helpers/fetch-ponyfill-undici.node.js +++ b/src/helpers/fetch-ponyfill-undici.node.js @@ -1,3 +1,6 @@ -import { fetch, Response, Headers, Request } from 'undici'; +import { Blob } from 'buffer'; +import { fetch, Response, Headers, Request, FormData, File } from 'undici'; -export { fetch, Response, Headers, Request }; +const BlobU = typeof fetch === 'undefined' ? undefined : Blob; + +export { fetch, Response, Headers, Request, FormData, File, BlobU as Blob }; diff --git a/src/helpers/fetch-ponyfill.browser.js b/src/helpers/fetch-ponyfill.browser.js index e1238d4c4..9e0d0620f 100644 --- a/src/helpers/fetch-ponyfill.browser.js +++ b/src/helpers/fetch-ponyfill.browser.js @@ -1,4 +1,4 @@ // we're targeting browsers that already support fetch API -const { fetch, Response, Headers, Request } = globalThis; +const { fetch, Response, Headers, Request, FormData, File, Blob } = globalThis; -export { fetch, Response, Headers, Request }; +export { fetch, Response, Headers, Request, FormData, File, Blob }; diff --git a/src/http/index.js b/src/http/index.js index 2d44bb2cc..9d8b81b53 100644 --- a/src/http/index.js +++ b/src/http/index.js @@ -1,6 +1,5 @@ import qs from 'qs'; import jsYaml from 'js-yaml'; -import { FormData, File, Blob } from 'formdata-node'; import '../helpers/fetch-polyfill.node.js'; import { encodeDisallowedCharacters } from '../execute/oas3/style-serializer.js'; diff --git a/test/execute/main.js b/test/execute/main.js index 7ad7ee5ee..7f46555a6 100644 --- a/test/execute/main.js +++ b/test/execute/main.js @@ -1,4 +1,3 @@ -import { FormData } from 'formdata-node'; import AbortController from 'abort-controller'; import { execute, buildRequest, self as stubs } from '../../src/execute/index.js'; diff --git a/test/http/http-multipart.js b/test/http/http-multipart.js index 5b1121413..713c6f1f7 100644 --- a/test/http/http-multipart.js +++ b/test/http/http-multipart.js @@ -1,7 +1,6 @@ +import fs from 'node:fs'; import path from 'node:path'; import * as undici from 'undici'; -import { FormData, File, Blob } from 'formdata-node'; -import { fileFromPathSync } from 'formdata-node/lib/cjs/fileFromPath.js'; import { buildRequest } from '../../src/execute/index.js'; import sampleMultipartOpenApi2 from '../data/sample-multipart-oas2.js'; @@ -263,8 +262,16 @@ describe('buildRequest - openapi 3.0', () => { * `fileFromPathSync` helper should be used to load files from Node.js env * that are further used as values for FormData. */ - const file1 = fileFromPathSync(path.join(__dirname, 'data', 'file1.txt')); - const file2 = fileFromPathSync(path.join(__dirname, 'data', 'file2.txt')); + const file1 = new File( + fs.readFileSync(path.join(__dirname, 'data', 'file1.txt')), + 'file1.txt', + { type: 'text/plain' } + ); + const file2 = new File( + fs.readFileSync(path.join(__dirname, 'data', 'file1.txt')), + 'file1.txt', + { type: 'text/plain' } + ); const req = buildRequest({ spec: sampleMultipartOpenApi3, diff --git a/test/http/index.js b/test/http/index.js index 6b1db2ef5..e25e880d1 100644 --- a/test/http/index.js +++ b/test/http/index.js @@ -1,4 +1,3 @@ -import { File, Blob } from 'formdata-node'; import * as undici from 'undici'; import http, { diff --git a/test/jest.setup.js b/test/jest.setup.js index bde767878..ff576a794 100644 --- a/test/jest.setup.js +++ b/test/jest.setup.js @@ -4,13 +4,24 @@ import path from 'node:path'; import fs from 'node:fs'; import AbortController from 'abort-controller'; -import { fetch, Headers, Request, Response } from '../src/helpers/fetch-ponyfill-undici.node.js'; +import { + fetch, + Headers, + Request, + Response, + FormData, + File, + Blob, +} from '../src/helpers/fetch-ponyfill-undici.node.js'; // force using undici for testing globalThis.fetch = fetch; globalThis.Headers = Headers; globalThis.Request = Request; globalThis.Response = Response; +globalThis.FormData = FormData; +globalThis.File = File; +globalThis.Blob = Blob; // provide AbortController for older Node.js versions globalThis.AbortController = AbortController; diff --git a/test/oas3/execute/build-request.js b/test/oas3/execute/build-request.js index 88ca8259c..27c787d1e 100644 --- a/test/oas3/execute/build-request.js +++ b/test/oas3/execute/build-request.js @@ -1,5 +1,3 @@ -import { File } from 'formdata-node'; - // https://github.com/swagger-api/swagger-js/issues/1116 import { buildRequest } from '../../../src/execute/index.js'; @@ -145,7 +143,7 @@ describe('buildRequest - OAS 3.0.x', () => { expect(json).toStrictEqual(JSON.stringify(options)); expect(file).toBeInstanceOf(File); expect(file.valueOf()).toStrictEqual(JSON.stringify(options)); - expect(file.type).toStrictEqual('application/json; charset=utf-8'); + expect(file.type).toStrictEqual('application/json;charset=utf-8'); }); });