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

Commit

Permalink
Handle invalid iterators
Browse files Browse the repository at this point in the history
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
  • Loading branch information
isaacs committed Dec 6, 2021
1 parent 52ca449 commit 2904f99
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 4 deletions.
16 changes: 13 additions & 3 deletions lib/format.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
const arrayFrom = obj => {
try {
return Array.from(obj)
} catch (e) {
return null
}
}
class Format {
constructor (obj, options = {}) {
this.options = options
Expand Down Expand Up @@ -51,9 +58,12 @@ class Format {

get objectAsArray () {
const value = Array.isArray(this.object) ? this.object
: this.isArray() ? Array.from(this.object)
: this.isArray() ? arrayFrom(this.object)
: null

if (value === null)
this.isArray = () => false

Object.defineProperty(this, 'objectAsArray', { value })
return value
}
Expand Down Expand Up @@ -207,7 +217,7 @@ class Format {
: this.isSet() ? this.set()
: this.isMap() ? this.map()
: this.isBuffer() ? this.buffer()
: this.isArray() ? this.array()
: this.isArray() && this.objectAsArray ? this.array()
// TODO streams, JSX
: this.pojo()

Expand Down Expand Up @@ -441,7 +451,7 @@ class Format {
}
}
}
return Array.from(own)
return arrayFrom(own)
} else
return Object.keys(obj || this.object)
}
Expand Down
4 changes: 4 additions & 0 deletions tap-snapshots/test/format.js.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -3374,6 +3374,10 @@ Null Object {
}
`

exports[`test/format.js TAP invalid iterator > must match snapshot 1`] = `
Object {}
`

exports[`test/format.js TAP locale sorting > must match snapshot 1`] = `
Object {
"cat": "meow",
Expand Down
13 changes: 13 additions & 0 deletions test/format.js
Original file line number Diff line number Diff line change
Expand Up @@ -256,3 +256,16 @@ t.test('locale sorting', t => {
t.matchSnapshot(format(obj, { sort: true }))
t.end()
})

t.test('invalid iterator', t => {
const obj = { [Symbol.iterator] () { return {} } }
t.matchSnapshot(format(obj))
const f = new Format(obj)
// looks like an array
t.equal(f.isArray(), true)
// until you try to format it
t.equal(f.print(), 'Object {}')
// then it realizes it's actually not
t.equal(f.isArray(), false)
t.end()
})
2 changes: 1 addition & 1 deletion test/same.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ t.test('array-likes', t => {
a.push(1,2,3)
const b = [1, 2, 3]
t.ok(same(t, a, b))
t.notEqual(a.constructor, b.constructor)
t.not(a.constructor, b.constructor)

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

0 comments on commit 2904f99

Please sign in to comment.