Skip to content

Commit 282a52b

Browse files
KhafraDevronag
authored andcommitted
feat: implement FormData Iterator
1 parent 30a464b commit 282a52b

File tree

5 files changed

+205
-123
lines changed

5 files changed

+205
-123
lines changed

lib/fetch/formdata.js

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict'
22

3-
const { isBlobLike, isFileLike, toUSVString } = require('./util')
3+
const { isBlobLike, isFileLike, toUSVString, makeIterator } = require('./util')
44
const { kState } = require('./symbols')
55
const { File, FileLike } = require('./file')
66
const { Blob } = require('buffer')
@@ -187,45 +187,42 @@ class FormData {
187187
return this.constructor.name
188188
}
189189

190-
* entries () {
190+
entries () {
191191
if (!(this instanceof FormData)) {
192192
throw new TypeError('Illegal invocation')
193193
}
194194

195-
for (const pair of this) {
196-
yield pair
197-
}
195+
return makeIterator(
196+
makeIterable(this[kState], 'entries'),
197+
'FormData'
198+
)
198199
}
199200

200-
* keys () {
201+
keys () {
201202
if (!(this instanceof FormData)) {
202203
throw new TypeError('Illegal invocation')
203204
}
204205

205-
for (const [key] of this) {
206-
yield key
207-
}
206+
return makeIterator(
207+
makeIterable(this[kState], 'keys'),
208+
'FormData'
209+
)
208210
}
209211

210-
* values () {
212+
values () {
211213
if (!(this instanceof FormData)) {
212214
throw new TypeError('Illegal invocation')
213215
}
214216

215-
for (const [, value] of this) {
216-
yield value
217-
}
218-
}
219-
220-
* [Symbol.iterator] () {
221-
// The value pairs to iterate over are this’s entry list’s entries with
222-
// the key being the name and the value being the value.
223-
for (const { name, value } of this[kState]) {
224-
yield [name, value]
225-
}
217+
return makeIterator(
218+
makeIterable(this[kState], 'values'),
219+
'FormData'
220+
)
226221
}
227222
}
228223

224+
FormData.prototype[Symbol.iterator] = FormData.prototype.entries
225+
229226
function makeEntry (name, value, filename) {
230227
// To create an entry for name, value, and optionally a filename, run these
231228
// steps:
@@ -267,4 +264,18 @@ function makeEntry (name, value, filename) {
267264
return entry
268265
}
269266

267+
function * makeIterable (entries, type) {
268+
// The value pairs to iterate over are this’s entry list’s entries
269+
// with the key being the name and the value being the value.
270+
for (const { name, value } of entries) {
271+
if (type === 'entries') {
272+
yield [name, value]
273+
} else if (type === 'values') {
274+
yield value
275+
} else {
276+
yield name
277+
}
278+
}
279+
}
280+
270281
module.exports = { FormData }

lib/fetch/headers.js

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const { validateHeaderName, validateHeaderValue } = require('http')
66
const { kHeadersList } = require('../core/symbols')
77
const { kGuard } = require('./symbols')
88
const { kEnumerableProperty } = require('../core/util')
9+
const { makeIterator } = require('./util')
910

1011
const kHeadersMap = Symbol('headers map')
1112
const kHeadersSortedMap = Symbol('headers map sorted')
@@ -73,33 +74,6 @@ function fill (headers, object) {
7374
}
7475
}
7576

76-
// https://tc39.es/ecma262/#sec-%25iteratorprototype%25-object
77-
const esIteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]()))
78-
79-
// https://webidl.spec.whatwg.org/#dfn-iterator-prototype-object
80-
function makeHeadersIterator (iterator) {
81-
const i = {
82-
next () {
83-
if (Object.getPrototypeOf(this) !== i) {
84-
throw new TypeError(
85-
'\'next\' called on an object that does not implement interface Headers Iterator.'
86-
)
87-
}
88-
89-
return iterator.next()
90-
},
91-
// The class string of an iterator prototype object for a given interface is the
92-
// result of concatenating the identifier of the interface and the string " Iterator".
93-
[Symbol.toStringTag]: 'Headers Iterator'
94-
}
95-
96-
// The [[Prototype]] internal slot of an iterator prototype object must be %IteratorPrototype%.
97-
Object.setPrototypeOf(i, esIteratorPrototype)
98-
// esIteratorPrototype needs to be the prototype of i
99-
// which is the prototype of an empty object. Yes, it's confusing.
100-
return Object.setPrototypeOf({}, i)
101-
}
102-
10377
class HeadersList {
10478
constructor (init) {
10579
if (init instanceof HeadersList) {
@@ -306,23 +280,23 @@ class Headers {
306280
throw new TypeError('Illegal invocation')
307281
}
308282

309-
return makeHeadersIterator(this[kHeadersSortedMap].keys())
283+
return makeIterator(this[kHeadersSortedMap].keys(), 'Headers')
310284
}
311285

312286
values () {
313287
if (!(this instanceof Headers)) {
314288
throw new TypeError('Illegal invocation')
315289
}
316290

317-
return makeHeadersIterator(this[kHeadersSortedMap].values())
291+
return makeIterator(this[kHeadersSortedMap].values(), 'Headers')
318292
}
319293

320294
entries () {
321295
if (!(this instanceof Headers)) {
322296
throw new TypeError('Illegal invocation')
323297
}
324298

325-
return makeHeadersIterator(this[kHeadersSortedMap].entries())
299+
return makeIterator(this[kHeadersSortedMap].entries(), 'Headers')
326300
}
327301

328302
/**

lib/fetch/util.js

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,33 @@ function serializeJavascriptValueToJSONString (value) {
361361
return result
362362
}
363363

364+
// https://tc39.es/ecma262/#sec-%25iteratorprototype%25-object
365+
const esIteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]()))
366+
367+
// https://webidl.spec.whatwg.org/#dfn-iterator-prototype-object
368+
function makeIterator (iterator, name) {
369+
const i = {
370+
next () {
371+
if (Object.getPrototypeOf(this) !== i) {
372+
throw new TypeError(
373+
`'next' called on an object that does not implement interface ${name} Iterator.`
374+
)
375+
}
376+
377+
return iterator.next()
378+
},
379+
// The class string of an iterator prototype object for a given interface is the
380+
// result of concatenating the identifier of the interface and the string " Iterator".
381+
[Symbol.toStringTag]: `${name} Iterator`
382+
}
383+
384+
// The [[Prototype]] internal slot of an iterator prototype object must be %IteratorPrototype%.
385+
Object.setPrototypeOf(i, esIteratorPrototype)
386+
// esIteratorPrototype needs to be the prototype of i
387+
// which is the prototype of an empty object. Yes, it's confusing.
388+
return Object.setPrototypeOf({}, i)
389+
}
390+
364391
module.exports = {
365392
isAborted,
366393
isCancelled,
@@ -390,5 +417,6 @@ module.exports = {
390417
isValidReasonPhrase,
391418
sameOrigin,
392419
normalizeMethod,
393-
serializeJavascriptValueToJSONString
420+
serializeJavascriptValueToJSONString,
421+
makeIterator
394422
}

test/fetch/headers-iterator.js

Lines changed: 0 additions & 71 deletions
This file was deleted.

0 commit comments

Comments
 (0)