Skip to content

Commit

Permalink
Merge pull request #295 from github/iterators
Browse files Browse the repository at this point in the history
Add Headers iterators
  • Loading branch information
dgraham committed Mar 13, 2016
2 parents 31bd9c4 + a1b7674 commit 57b7f98
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 31 deletions.
99 changes: 80 additions & 19 deletions fetch.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,20 @@
return
}

var support = {
iterable: 'Symbol' in self && 'iterator' in Symbol,
blob: 'FileReader' in self && 'Blob' in self && (function() {
try {
new Blob()
return true
} catch(e) {
return false
}
})(),
formData: 'FormData' in self,
arrayBuffer: 'ArrayBuffer' in self
}

function normalizeName(name) {
if (typeof name !== 'string') {
name = String(name)
Expand Down Expand Up @@ -77,6 +91,67 @@
}, this)
}

Headers.prototype.keys = function() {
var items = []
this.forEach(function(value, name) { items.push(name) })
var iterator = {
next: function() {
var value = items.shift()
return {done: value === undefined, value: value}
}
}

if (support.iterable) {
iterator[Symbol.iterator] = function() {
return iterator
}
}

return iterator
}

Headers.prototype.values = function() {
var items = []
this.forEach(function(value) { items.push(value) })
var iterator = {
next: function() {
var value = items.shift()
return {done: value === undefined, value: value}
}
}

if (support.iterable) {
iterator[Symbol.iterator] = function() {
return iterator
}
}

return iterator
}

Headers.prototype.entries = function() {
var items = []
this.forEach(function(value, name) { items.push([name, value]) })
var iterator = {
next: function() {
var value = items.shift()
return {done: value === undefined, value: value}
}
}

if (support.iterable) {
iterator[Symbol.iterator] = function() {
return iterator
}
}

return iterator
}

if (support.iterable) {
Headers.prototype[Symbol.iterator] = Headers.prototype.entries
}

function consumed(body) {
if (body.bodyUsed) {
return Promise.reject(new TypeError('Already read'))
Expand Down Expand Up @@ -107,23 +182,9 @@
return fileReaderReady(reader)
}

var support = {
blob: 'FileReader' in self && 'Blob' in self && (function() {
try {
new Blob();
return true
} catch(e) {
return false
}
})(),
formData: 'FormData' in self,
arrayBuffer: 'ArrayBuffer' in self
}

function Body() {
this.bodyUsed = false


this._initBody = function(body) {
this._bodyInit = body
if (typeof body === 'string') {
Expand Down Expand Up @@ -320,9 +381,9 @@
return new Response(null, {status: status, headers: {location: url}})
}

self.Headers = Headers;
self.Request = Request;
self.Response = Response;
self.Headers = Headers
self.Request = Request
self.Response = Response

self.fetch = function(input, init) {
return new Promise(function(resolve, reject) {
Expand All @@ -345,7 +406,7 @@
return xhr.getResponseHeader('X-Request-URL')
}

return;
return
}

xhr.onload = function() {
Expand All @@ -355,7 +416,7 @@
headers: headers(xhr),
url: responseURL()
}
var body = 'response' in xhr ? xhr.response : xhr.responseText;
var body = 'response' in xhr ? xhr.response : xhr.responseText
resolve(new Response(body, options))
}

Expand Down
60 changes: 48 additions & 12 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -185,16 +185,16 @@ suite('Headers', function() {
test('converts field value to string on set and get', function() {
var headers = new Headers()
headers.set('Content-Type', 1)
headers.set('X-CSRF-Token', undefined);
headers.set('X-CSRF-Token', undefined)
assert.equal(headers.get('Content-Type'), '1')
assert.equal(headers.get('X-CSRF-Token'), 'undefined')
})
test('throws TypeError on invalid character in field name', function() {
assert.throws(function() { new Headers({'<Accept>': ['application/json']}) }, TypeError)
assert.throws(function() { new Headers({'Accept:': ['application/json']}) }, TypeError)
assert.throws(function() {
var headers = new Headers();
headers.set({field: 'value'}, 'application/json');
var headers = new Headers()
headers.set({field: 'value'}, 'application/json')
}, TypeError)
})
featureDependent(test, !nativeFirefox, 'is iterable with forEach', function() {
Expand All @@ -220,6 +220,42 @@ suite('Headers', function() {
assert.equal(this, thisArg)
}, thisArg)
})
test('is iterable with keys', function() {
var headers = new Headers()
headers.append('Accept', 'application/json')
headers.append('Accept', 'text/plain')
headers.append('Content-Type', 'text/html')

var iterator = headers.keys()
assert.deepEqual({done: false, value: 'accept'}, iterator.next())
assert.deepEqual({done: false, value: 'accept'}, iterator.next())
assert.deepEqual({done: false, value: 'content-type'}, iterator.next())
assert.deepEqual({done: true, value: undefined}, iterator.next())
})
test('is iterable with values', function() {
var headers = new Headers()
headers.append('Accept', 'application/json')
headers.append('Accept', 'text/plain')
headers.append('Content-Type', 'text/html')

var iterator = headers.values()
assert.deepEqual({done: false, value: 'application/json'}, iterator.next())
assert.deepEqual({done: false, value: 'text/plain'}, iterator.next())
assert.deepEqual({done: false, value: 'text/html'}, iterator.next())
assert.deepEqual({done: true, value: undefined}, iterator.next())
})
test('is iterable with entries', function() {
var headers = new Headers()
headers.append('Accept', 'application/json')
headers.append('Accept', 'text/plain')
headers.append('Content-Type', 'text/html')

var iterator = headers.entries()
assert.deepEqual({done: false, value: ['accept', 'application/json']}, iterator.next())
assert.deepEqual({done: false, value: ['accept', 'text/plain']}, iterator.next())
assert.deepEqual({done: false, value: ['content-type', 'text/html']}, iterator.next())
assert.deepEqual({done: true, value: undefined}, iterator.next())
})
})

// https://fetch.spec.whatwg.org/#request-class
Expand Down Expand Up @@ -527,11 +563,11 @@ suite('Response', function() {
})

test('creates Headers object from raw headers', function() {
var r = new Response('{"foo":"bar"}', {headers: {'content-type': 'application/json'}});
assert.equal(r.headers instanceof Headers, true);
var r = new Response('{"foo":"bar"}', {headers: {'content-type': 'application/json'}})
assert.equal(r.headers instanceof Headers, true)
return r.json().then(function(json){
assert.equal(json.foo, 'bar');
return json;
assert.equal(json.foo, 'bar')
return json
})
})

Expand Down Expand Up @@ -574,7 +610,7 @@ suite('Response', function() {

test('redirect creates redirect Response', function() {
var r = Response.redirect('https://fetch.spec.whatwg.org/', 301)
assert(r instanceof Response);
assert(r instanceof Response)
assert.equal(r.status, 301)
assert.equal(r.headers.get('Location'), 'https://fetch.spec.whatwg.org/')
})
Expand Down Expand Up @@ -949,7 +985,7 @@ suite('Atomic HTTP redirect handling', function() {
// https://fetch.spec.whatwg.org/#concept-request-credentials-mode
suite('credentials mode', function() {
setup(function() {
return fetch('/cookie?name=foo&value=reset', {credentials: 'same-origin'});
return fetch('/cookie?name=foo&value=reset', {credentials: 'same-origin'})
})

featureDependent(suite, exerciseMode === 'native', 'omit', function() {
Expand All @@ -960,7 +996,7 @@ suite('credentials mode', function() {

test('does not accept cookies with implicit omit credentials', function() {
return fetch('/cookie?name=foo&value=bar').then(function() {
return fetch('/cookie?name=foo', {credentials: 'same-origin'});
return fetch('/cookie?name=foo', {credentials: 'same-origin'})
}).then(function(response) {
return response.text()
}).then(function(data) {
Expand All @@ -970,7 +1006,7 @@ suite('credentials mode', function() {

test('does not accept cookies with omit credentials', function() {
return fetch('/cookie?name=foo&value=bar', {credentials: 'omit'}).then(function() {
return fetch('/cookie?name=foo', {credentials: 'same-origin'});
return fetch('/cookie?name=foo', {credentials: 'same-origin'})
}).then(function(response) {
return response.text()
}).then(function(data) {
Expand All @@ -980,7 +1016,7 @@ suite('credentials mode', function() {

test('does not send cookies with implicit omit credentials', function() {
return fetch('/cookie?name=foo&value=bar', {credentials: 'same-origin'}).then(function() {
return fetch('/cookie?name=foo');
return fetch('/cookie?name=foo')
}).then(function(response) {
return response.text()
}).then(function(data) {
Expand Down

0 comments on commit 57b7f98

Please sign in to comment.