From ecfc94fe661390aa64e51eb48e05edc377de0fa1 Mon Sep 17 00:00:00 2001 From: Joshua T Kalis Date: Fri, 14 Feb 2020 09:06:11 -0500 Subject: [PATCH 1/4] refactor response create function outside of promise handler not sure that this is favorable or not but thought that it might be and it allows for easier testing of the creation of responses and their properties. --- .gitignore | 1 + src/index.mjs | 51 ++++++++++++++++++++++++++------------------------- test/index.js | 31 ++++++++++++++++++++++++++++++- 3 files changed, 57 insertions(+), 26 deletions(-) diff --git a/.gitignore b/.gitignore index 368fbf5..2518a0b 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ node_modules npm-debug.log .DS_Store /polyfill/index.js +coverage diff --git a/src/index.mjs b/src/index.mjs index 783ad42..6d1ccef 100644 --- a/src/index.mjs +++ b/src/index.mjs @@ -1,37 +1,36 @@ +const regex = /^(.*?):[^\S\n]*([\s\S]*?)$/gm; +const response = (request, headers) => ({ + ok: (request.status/100|0) == 2, // 200-299 + statusText: request.statusText, + status: request.status, + url: request.responseURL, + text: () => Promise.resolve(request.responseText), + json: () => Promise.resolve(JSON.parse(request.responseText)), + blob: () => Promise.resolve(new Blob([request.response])), + clone: () => response(request, headers), + headers: { + keys: () => headers.keys, + entries: () => headers.all, + get: n => headers.raw[n.toLowerCase()], + has: n => n.toLowerCase() in headers.raw + } +}); + export default function(url, options) { options = options || {}; return new Promise( (resolve, reject) => { const request = new XMLHttpRequest(); - const keys = []; - const all = []; - const headers = {}; - - const response = () => ({ - ok: (request.status/100|0) == 2, // 200-299 - statusText: request.statusText, - status: request.status, - url: request.responseURL, - text: () => Promise.resolve(request.responseText), - json: () => Promise.resolve(JSON.parse(request.responseText)), - blob: () => Promise.resolve(new Blob([request.response])), - clone: response, - headers: { - keys: () => keys, - entries: () => all, - get: n => headers[n.toLowerCase()], - has: n => n.toLowerCase() in headers - } - }); request.open(options.method || 'get', url, true); request.onload = () => { - request.getAllResponseHeaders().replace(/^(.*?):[^\S\n]*([\s\S]*?)$/gm, (m, key, value) => { - keys.push(key = key.toLowerCase()); - all.push([key, value]); - headers[key] = headers[key] ? `${headers[key]},${value}` : value; + const head = { all: [], keys: [], raw: {} }; + request.getAllResponseHeaders().replace(regex, (m, key, value) => { + head.all.push([key, value]); + head.keys.push(key = key.toLowerCase()); + head.raw[key] = head.raw[key] ? `${head.raw[key]},${value}` : value; }); - resolve(response()); + resolve(response(request, head)); }; request.onerror = reject; @@ -45,3 +44,5 @@ export default function(url, options) { request.send(options.body || null); }); } + +export { response }; diff --git a/test/index.js b/test/index.js index 3a9e598..0336596 100644 --- a/test/index.js +++ b/test/index.js @@ -1,4 +1,4 @@ -import fetch from '../src/index.mjs'; +import fetch, { response } from '../src/index.mjs'; import fetchDist from '..'; describe('unfetch', () => { @@ -81,4 +81,33 @@ describe('unfetch', () => { return p; }); }); + + describe('response()', () => { + it('returns text()', () => response({ responseText: 'A passing test.' }) + .text() + .then((text) => expect(text).toBe('A passing test.')) + ); + + it('returns blob()', () => response({ response: 'A passing test.' }) + .blob() + .then((text) => expect(text.toString()).toBe(new Blob(['A passing test.']).toString())) + ); + + it('returns headers', () => { + const all = [['x-foo', 'bar'], ['x-baz', 'boo']]; + const result = response({}, { all }).headers.entries(); + expect(result).toEqual(all); + }); + + it('returns header keys', () => { + const result = response({}, { keys: ['x-foo'] }).headers.keys(); + expect(result).toEqual(['x-foo']); + }); + + it('returns headers has', () => { + const raw = { 'x-foo': 'bar', 'x-baz': 'boo' }; + const test = response({}, { raw }).headers; + expect(test.has('x-foo')).toBe(true); + }); + }); }); From ac63b91e6a92a87c1a8e8b8fc2cdd9e87dc06c70 Mon Sep 17 00:00:00 2001 From: Joshua T Kalis Date: Tue, 18 Feb 2020 12:09:12 -0500 Subject: [PATCH 2/4] remove non default export to another file --- src/index.mjs | 20 ++------------------ src/lib/response.mjs | 18 ++++++++++++++++++ test/index.js | 31 +------------------------------ test/lib/response.js | 30 ++++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 48 deletions(-) create mode 100644 src/lib/response.mjs create mode 100644 test/lib/response.js diff --git a/src/index.mjs b/src/index.mjs index 6d1ccef..90dd431 100644 --- a/src/index.mjs +++ b/src/index.mjs @@ -1,20 +1,6 @@ +import response from './lib/response'; + const regex = /^(.*?):[^\S\n]*([\s\S]*?)$/gm; -const response = (request, headers) => ({ - ok: (request.status/100|0) == 2, // 200-299 - statusText: request.statusText, - status: request.status, - url: request.responseURL, - text: () => Promise.resolve(request.responseText), - json: () => Promise.resolve(JSON.parse(request.responseText)), - blob: () => Promise.resolve(new Blob([request.response])), - clone: () => response(request, headers), - headers: { - keys: () => headers.keys, - entries: () => headers.all, - get: n => headers.raw[n.toLowerCase()], - has: n => n.toLowerCase() in headers.raw - } -}); export default function(url, options) { options = options || {}; @@ -44,5 +30,3 @@ export default function(url, options) { request.send(options.body || null); }); } - -export { response }; diff --git a/src/lib/response.mjs b/src/lib/response.mjs new file mode 100644 index 0000000..48c4cc6 --- /dev/null +++ b/src/lib/response.mjs @@ -0,0 +1,18 @@ +export default function response (request, headers) { + return { + ok: (request.status/100|0) == 2, // 200-299 + statusText: request.statusText, + status: request.status, + url: request.responseURL, + text: () => Promise.resolve(request.responseText), + json: () => Promise.resolve(JSON.parse(request.responseText)), + blob: () => Promise.resolve(new Blob([request.response])), + clone: () => response(request, headers), + headers: { + keys: () => headers.keys, + entries: () => headers.all, + get: n => headers.raw[n.toLowerCase()], + has: n => n.toLowerCase() in headers.raw + } + }; +} diff --git a/test/index.js b/test/index.js index 0336596..3a9e598 100644 --- a/test/index.js +++ b/test/index.js @@ -1,4 +1,4 @@ -import fetch, { response } from '../src/index.mjs'; +import fetch from '../src/index.mjs'; import fetchDist from '..'; describe('unfetch', () => { @@ -81,33 +81,4 @@ describe('unfetch', () => { return p; }); }); - - describe('response()', () => { - it('returns text()', () => response({ responseText: 'A passing test.' }) - .text() - .then((text) => expect(text).toBe('A passing test.')) - ); - - it('returns blob()', () => response({ response: 'A passing test.' }) - .blob() - .then((text) => expect(text.toString()).toBe(new Blob(['A passing test.']).toString())) - ); - - it('returns headers', () => { - const all = [['x-foo', 'bar'], ['x-baz', 'boo']]; - const result = response({}, { all }).headers.entries(); - expect(result).toEqual(all); - }); - - it('returns header keys', () => { - const result = response({}, { keys: ['x-foo'] }).headers.keys(); - expect(result).toEqual(['x-foo']); - }); - - it('returns headers has', () => { - const raw = { 'x-foo': 'bar', 'x-baz': 'boo' }; - const test = response({}, { raw }).headers; - expect(test.has('x-foo')).toBe(true); - }); - }); }); diff --git a/test/lib/response.js b/test/lib/response.js new file mode 100644 index 0000000..471b7d3 --- /dev/null +++ b/test/lib/response.js @@ -0,0 +1,30 @@ +import response from '../../src/lib/response.mjs'; + +describe('response()', () => { + it('returns text()', () => response({ responseText: 'A passing test.' }) + .text() + .then((text) => expect(text).toBe('A passing test.')) + ); + + it('returns blob()', () => response({ response: 'A passing test.' }) + .blob() + .then((text) => expect(text.toString()).toBe(new Blob(['A passing test.']).toString())) + ); + + it('returns headers', () => { + const all = [['x-foo', 'bar'], ['x-baz', 'boo']]; + const result = response({}, { all }).headers.entries(); + expect(result).toEqual(all); + }); + + it('returns header keys', () => { + const result = response({}, { keys: ['x-foo'] }).headers.keys(); + expect(result).toEqual(['x-foo']); + }); + + it('returns headers has', () => { + const raw = { 'x-foo': 'bar', 'x-baz': 'boo' }; + const test = response({}, { raw }).headers; + expect(test.has('x-foo')).toBe(true); + }); +}); From be0e6cd6ccf932e6b18159c970a60c3c66d7ecbb Mon Sep 17 00:00:00 2001 From: Jason Miller Date: Tue, 18 Feb 2020 22:27:31 -0500 Subject: [PATCH 3/4] backport fix from #112 --- src/lib/response.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/response.mjs b/src/lib/response.mjs index 48c4cc6..ec05a98 100644 --- a/src/lib/response.mjs +++ b/src/lib/response.mjs @@ -5,7 +5,7 @@ export default function response (request, headers) { status: request.status, url: request.responseURL, text: () => Promise.resolve(request.responseText), - json: () => Promise.resolve(JSON.parse(request.responseText)), + json: () => Promise.resolve(request.responseText).then(JSON.parse), blob: () => Promise.resolve(new Blob([request.response])), clone: () => response(request, headers), headers: { From 3986993c03a35b387360527492911ffb2f776979 Mon Sep 17 00:00:00 2001 From: Joshua T Kalis Date: Wed, 19 Feb 2020 08:56:11 -0500 Subject: [PATCH 4/4] reduce the size of the compiled output --- src/index.mjs | 10 +++++----- src/lib/response.mjs | 12 ++++++------ test/lib/response.js | 20 +++++++++++--------- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/index.mjs b/src/index.mjs index 90dd431..84c7f43 100644 --- a/src/index.mjs +++ b/src/index.mjs @@ -10,13 +10,13 @@ export default function(url, options) { request.open(options.method || 'get', url, true); request.onload = () => { - const head = { all: [], keys: [], raw: {} }; + const all = [], keys = [], raw = {}; request.getAllResponseHeaders().replace(regex, (m, key, value) => { - head.all.push([key, value]); - head.keys.push(key = key.toLowerCase()); - head.raw[key] = head.raw[key] ? `${head.raw[key]},${value}` : value; + all.push([key, value]); + keys.push(key = key.toLowerCase()); + raw[key] = raw[key] ? `${raw[key]},${value}` : value; }); - resolve(response(request, head)); + resolve(response(request, all, keys, raw)); }; request.onerror = reject; diff --git a/src/lib/response.mjs b/src/lib/response.mjs index ec05a98..4c2a548 100644 --- a/src/lib/response.mjs +++ b/src/lib/response.mjs @@ -1,4 +1,4 @@ -export default function response (request, headers) { +export default function response (request, all, keys, raw) { return { ok: (request.status/100|0) == 2, // 200-299 statusText: request.statusText, @@ -7,12 +7,12 @@ export default function response (request, headers) { text: () => Promise.resolve(request.responseText), json: () => Promise.resolve(request.responseText).then(JSON.parse), blob: () => Promise.resolve(new Blob([request.response])), - clone: () => response(request, headers), + clone: () => response(request, all, keys, raw), headers: { - keys: () => headers.keys, - entries: () => headers.all, - get: n => headers.raw[n.toLowerCase()], - has: n => n.toLowerCase() in headers.raw + keys: () => keys, + entries: () => all, + get: n => raw[n.toLowerCase()], + has: n => n.toLowerCase() in raw } }; } diff --git a/test/lib/response.js b/test/lib/response.js index 471b7d3..24cd324 100644 --- a/test/lib/response.js +++ b/test/lib/response.js @@ -1,7 +1,12 @@ import response from '../../src/lib/response.mjs'; describe('response()', () => { - it('returns text()', () => response({ responseText: 'A passing test.' }) + const raw = { 'x-foo': 'foo', 'x-bar': 'bar' }; + const keys = Object.keys(raw); + const all = Object.entries(raw); + const resp = response({}, all, keys, raw); + + it('returns text()', () => response({ responseText: 'A passing test.' }, [], [], {}) .text() .then((text) => expect(text).toBe('A passing test.')) ); @@ -12,19 +17,16 @@ describe('response()', () => { ); it('returns headers', () => { - const all = [['x-foo', 'bar'], ['x-baz', 'boo']]; - const result = response({}, { all }).headers.entries(); - expect(result).toEqual(all); + expect(resp.headers.entries()).toEqual(all); }); it('returns header keys', () => { - const result = response({}, { keys: ['x-foo'] }).headers.keys(); - expect(result).toEqual(['x-foo']); + expect(resp.headers.keys()).toEqual(['x-foo', 'x-bar']); }); it('returns headers has', () => { - const raw = { 'x-foo': 'bar', 'x-baz': 'boo' }; - const test = response({}, { raw }).headers; - expect(test.has('x-foo')).toBe(true); + expect(resp.headers.has('x-foo')).toBe(true); + expect(resp.headers.has('x-bar')).toBe(true); + expect(resp.headers.has('x-baz')).toBe(false); }); });