From 57da1a3cbb67787473fbc061db2d3f0a1bf3a99c Mon Sep 17 00:00:00 2001 From: Lux Date: Tue, 23 Jul 2019 22:33:11 +0200 Subject: [PATCH 1/6] move globals to getters to allow overwrite. This will fix #151 --- index.js | 45 +++++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/index.js b/index.js index 1be5d501..051071bc 100644 --- a/index.js +++ b/index.js @@ -21,18 +21,27 @@ const getGlobal = property => { } }; -const document = getGlobal('document'); -const Headers = getGlobal('Headers'); -const Response = getGlobal('Response'); -const ReadableStream = getGlobal('ReadableStream'); -const fetch = getGlobal('fetch'); -const AbortController = getGlobal('AbortController'); -const FormData = getGlobal('FormData'); +const globals = [ + 'document', + 'Headers', + 'Response', + 'ReadableStream', + 'fetch', + 'AbortController', + 'FormData' +].reduce((acc, key) => { + Object.defineProperty(acc, key, { + get() { + return getGlobal(key); + } + }); + return acc; +}, {}); const isObject = value => value !== null && typeof value === 'object'; -const supportsAbortController = typeof AbortController === 'function'; -const supportsStreams = typeof ReadableStream === 'function'; -const supportsFormData = typeof FormData === 'function'; +const supportsAbortController = typeof globals.AbortController === 'function'; +const supportsStreams = typeof globals.ReadableStream === 'function'; +const supportsFormData = typeof globals.FormData === 'function'; const deepMerge = (...sources) => { let returnValue = {}; @@ -183,7 +192,7 @@ class Ky { this._input = this._options.prefixUrl + this._input; if (searchParams) { - const url = new URL(this._input, document && document.baseURI); + const url = new URL(this._input, globals.document && globals.document.baseURI); if (typeof searchParams === 'string' || (URLSearchParams && searchParams instanceof URLSearchParams)) { url.search = searchParams; } else if (Object.values(searchParams).every(param => typeof param === 'number' || typeof param === 'string')) { @@ -202,9 +211,9 @@ class Ky { }, hooks); this._throwHttpErrors = throwHttpErrors; - const headers = new Headers(this._options.headers || {}); + const headers = new globals.Headers(this._options.headers || {}); - if (((supportsFormData && this._options.body instanceof FormData) || this._options.body instanceof URLSearchParams) && headers.has('content-type')) { + if (((supportsFormData && this._options.body instanceof globals.FormData) || this._options.body instanceof URLSearchParams) && headers.has('content-type')) { throw new Error(`The \`content-type\` header cannot be used with a ${this._options.body.constructor.name} body. It will be set automatically.`); } @@ -227,7 +236,7 @@ class Ky { // eslint-disable-next-line no-await-in-loop const modifiedResponse = await hook(response.clone()); - if (modifiedResponse instanceof Response) { + if (modifiedResponse instanceof globals.Response) { response = modifiedResponse; } } @@ -322,10 +331,10 @@ class Ky { } if (this._timeout === false) { - return fetch(this._input, this._options); + return globals.fetch(this._input, this._options); } - return timeout(fetch(this._input, this._options), this._timeout, this.abortController); + return timeout(globals.fetch(this._input, this._options), this._timeout, this.abortController); } /* istanbul ignore next */ @@ -333,8 +342,8 @@ class Ky { const totalBytes = Number(response.headers.get('content-length')) || 0; let transferredBytes = 0; - return new Response( - new ReadableStream({ + return new globals.Response( + new globals.ReadableStream({ start(controller) { const reader = response.body.getReader(); From f27df360052379983117b3079b2d8ef57846ad97 Mon Sep 17 00:00:00 2001 From: Szymon Marczak <36894700+szmarczak@users.noreply.github.com> Date: Sat, 7 Sep 2019 19:52:34 +0200 Subject: [PATCH 2/6] Update index.js --- index.js | 70 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 31 deletions(-) diff --git a/index.js b/index.js index 051071bc..cc9a6f02 100644 --- a/index.js +++ b/index.js @@ -1,42 +1,50 @@ /*! MIT License © Sindre Sorhus */ -const getGlobal = property => { - /* istanbul ignore next */ - if (typeof self !== 'undefined' && self && property in self) { - return self[property]; - } +const globals = {}; - /* istanbul ignore next */ - if (typeof window !== 'undefined' && window && property in window) { - return window[property]; - } +{ + const getGlobal = property => { + /* istanbul ignore next */ + if (typeof self !== 'undefined' && self && property in self) { + return self[property]; + } - if (typeof global !== 'undefined' && global && property in global) { - return global[property]; - } + /* istanbul ignore next */ + if (typeof window !== 'undefined' && window && property in window) { + return window[property]; + } - /* istanbul ignore next */ - if (typeof globalThis !== 'undefined' && globalThis) { - return globalThis[property]; - } -}; + if (typeof global !== 'undefined' && global && property in global) { + return global[property]; + } -const globals = [ - 'document', - 'Headers', - 'Response', - 'ReadableStream', - 'fetch', - 'AbortController', - 'FormData' -].reduce((acc, key) => { - Object.defineProperty(acc, key, { + /* istanbul ignore next */ + if (typeof globalThis !== 'undefined' && globalThis) { + return globalThis[property]; + } + }; + + const globalProperties = [ + 'document', + 'Headers', + 'Response', + 'ReadableStream', + 'fetch', + 'AbortController', + 'FormData' + ]; + + const props = {}; + for (const property of globalProperties) { + props[property] = { get() { - return getGlobal(key); + return getGlobal(property); } - }); - return acc; -}, {}); + } + } + + Object.defineProperties(globals, props); +} const isObject = value => value !== null && typeof value === 'object'; const supportsAbortController = typeof globals.AbortController === 'function'; From 2ecbc1c515f955b91a13385884c155762508c123 Mon Sep 17 00:00:00 2001 From: Szymon Marczak <36894700+szmarczak@users.noreply.github.com> Date: Sat, 7 Sep 2019 20:00:23 +0200 Subject: [PATCH 3/6] Update index.js --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 2b1f506e..1a9b67f4 100644 --- a/index.js +++ b/index.js @@ -57,7 +57,7 @@ const deepMerge = (...sources) => { for (const source of sources) { if (Array.isArray(source)) { - if (!(Array.isArray(returnValue))) { + if (!(Array.isArray(returnValue))) { returnValue = []; } From 2a0905a4868f7c70af1860a11a480c1c89e34908 Mon Sep 17 00:00:00 2001 From: Szymon Marczak <36894700+szmarczak@users.noreply.github.com> Date: Sat, 7 Sep 2019 20:04:48 +0200 Subject: [PATCH 4/6] no trailing spaces --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 1a9b67f4..b5f8c5b0 100644 --- a/index.js +++ b/index.js @@ -23,10 +23,10 @@ const globals = {}; return globalThis[property]; } }; - + const globalProperties = [ 'document', - 'Headers', + 'Headers', 'Request', 'Response', 'ReadableStream', From 82480673efeb74d5bd0bf1783b45c978cd80f6c3 Mon Sep 17 00:00:00 2001 From: Szymon Marczak <36894700+szmarczak@users.noreply.github.com> Date: Sat, 7 Sep 2019 21:04:56 +0200 Subject: [PATCH 5/6] fixes --- index.js | 24 +++++++++++++++++------- test/browser.js | 1 + 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/index.js b/index.js index b5f8c5b0..60762397 100644 --- a/index.js +++ b/index.js @@ -4,24 +4,34 @@ const globals = {}; { const getGlobal = property => { + let parent; + /* istanbul ignore next */ if (typeof self !== 'undefined' && self && property in self) { - return self[property]; + parent = self; } /* istanbul ignore next */ if (typeof window !== 'undefined' && window && property in window) { - return window[property]; + parent = window; } if (typeof global !== 'undefined' && global && property in global) { - return global[property]; + parent = global; } /* istanbul ignore next */ if (typeof globalThis !== 'undefined' && globalThis) { - return globalThis[property]; + parent = globalThis; } + + const globalProperty = parent[property]; + + if (typeof globalProperty === 'function') { + return globalProperty.bind(parent); + } + + return globalProperty; }; const globalProperties = [ @@ -217,7 +227,7 @@ class Ky { ...otherOptions }; - if (input instanceof Request) { + if (input instanceof globals.Request) { this._input = input; // `ky` options have precedence over `Request` options @@ -243,7 +253,7 @@ class Ky { this._input = this._options.prefixUrl + this._input; if (searchParams) { - const url = new URL(this._input, document && document.baseURI); + const url = new URL(this._input, globals.document && globals.document.baseURI); if (typeof searchParams === 'string' || (URLSearchParams && searchParams instanceof URLSearchParams)) { url.search = searchParams; } else if (Object.values(searchParams).every(param => typeof param === 'number' || typeof param === 'string')) { @@ -257,7 +267,7 @@ class Ky { } if (supportsAbortController) { - this.abortController = new AbortController(); + this.abortController = new globals.AbortController(); if (this._options.signal) { this._options.signal.addEventListener('abort', () => { this.abortController.abort(); diff --git a/test/browser.js b/test/browser.js index 7f5e1587..5af881d7 100644 --- a/test/browser.js +++ b/test/browser.js @@ -86,6 +86,7 @@ test('throws TimeoutError even though it does not support AbortController', with }, server.url); t.is(error, 'TimeoutError: Request timed out'); + // A note from @szmarczak: await server.close() hangs on my machine await server.close(); }); From f8f41621204676f3cdeea76b18e979f2785f3c8f Mon Sep 17 00:00:00 2001 From: Szymon Marczak <36894700+szmarczak@users.noreply.github.com> Date: Sat, 7 Sep 2019 21:13:29 +0200 Subject: [PATCH 6/6] more fixes --- index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/index.js b/index.js index 60762397..84fda6ba 100644 --- a/index.js +++ b/index.js @@ -25,6 +25,10 @@ const globals = {}; parent = globalThis; } + if (typeof parent === 'undefined') { + return; + } + const globalProperty = parent[property]; if (typeof globalProperty === 'function') {