Skip to content
This repository was archived by the owner on Sep 15, 2023. It is now read-only.

Commit 2904f99

Browse files
committed
Handle invalid iterators
If an object has Symbol.iterator method, but it throws when used with Array.from, then it is actually not an Array-like. Detect this situation, and switch to pojo-mode for those types of objects. Fix: tapjs/tapjs#791
1 parent 52ca449 commit 2904f99

File tree

4 files changed

+31
-4
lines changed

4 files changed

+31
-4
lines changed

lib/format.js

+13-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
const arrayFrom = obj => {
2+
try {
3+
return Array.from(obj)
4+
} catch (e) {
5+
return null
6+
}
7+
}
18
class Format {
29
constructor (obj, options = {}) {
310
this.options = options
@@ -51,9 +58,12 @@ class Format {
5158

5259
get objectAsArray () {
5360
const value = Array.isArray(this.object) ? this.object
54-
: this.isArray() ? Array.from(this.object)
61+
: this.isArray() ? arrayFrom(this.object)
5562
: null
5663

64+
if (value === null)
65+
this.isArray = () => false
66+
5767
Object.defineProperty(this, 'objectAsArray', { value })
5868
return value
5969
}
@@ -207,7 +217,7 @@ class Format {
207217
: this.isSet() ? this.set()
208218
: this.isMap() ? this.map()
209219
: this.isBuffer() ? this.buffer()
210-
: this.isArray() ? this.array()
220+
: this.isArray() && this.objectAsArray ? this.array()
211221
// TODO streams, JSX
212222
: this.pojo()
213223

@@ -441,7 +451,7 @@ class Format {
441451
}
442452
}
443453
}
444-
return Array.from(own)
454+
return arrayFrom(own)
445455
} else
446456
return Object.keys(obj || this.object)
447457
}

tap-snapshots/test/format.js.test.cjs

+4
Original file line numberDiff line numberDiff line change
@@ -3374,6 +3374,10 @@ Null Object {
33743374
}
33753375
`
33763376

3377+
exports[`test/format.js TAP invalid iterator > must match snapshot 1`] = `
3378+
Object {}
3379+
`
3380+
33773381
exports[`test/format.js TAP locale sorting > must match snapshot 1`] = `
33783382
Object {
33793383
"cat": "meow",

test/format.js

+13
Original file line numberDiff line numberDiff line change
@@ -256,3 +256,16 @@ t.test('locale sorting', t => {
256256
t.matchSnapshot(format(obj, { sort: true }))
257257
t.end()
258258
})
259+
260+
t.test('invalid iterator', t => {
261+
const obj = { [Symbol.iterator] () { return {} } }
262+
t.matchSnapshot(format(obj))
263+
const f = new Format(obj)
264+
// looks like an array
265+
t.equal(f.isArray(), true)
266+
// until you try to format it
267+
t.equal(f.print(), 'Object {}')
268+
// then it realizes it's actually not
269+
t.equal(f.isArray(), false)
270+
t.end()
271+
})

test/same.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ t.test('array-likes', t => {
7979
a.push(1,2,3)
8080
const b = [1, 2, 3]
8181
t.ok(same(t, a, b))
82-
t.notEqual(a.constructor, b.constructor)
82+
t.not(a.constructor, b.constructor)
8383

8484
const args = (function () { return arguments })(1,2,3)
8585
const o = {[Symbol.iterator]: function*() { for (let i of a) { yield i } } }

0 commit comments

Comments
 (0)