Skip to content

Commit

Permalink
Fix infinite loop in Map#iterator
Browse files Browse the repository at this point in the history
  • Loading branch information
drborges committed Sep 7, 2024
1 parent 91c1d6c commit bf5f80e
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 3 deletions.
7 changes: 4 additions & 3 deletions packages/arbor-store/src/handlers/map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ export class MapHandler<T extends object = object> extends DefaultHandler<
}

*[Symbol.iterator]() {
if (!isNode<Map<unknown, T>>(this)) throw new NotAnArborNodeError()
const mapProxy = this.$tree.getNodeFor(this) as unknown as Map<unknown, T>

for (const entry of this.entries()) {
yield entry
for (const entry of this.$value.entries()) {
const childProxy = mapProxy.get(entry[0])
yield [entry[0], childProxy]
}
}

Expand Down
4 changes: 4 additions & 0 deletions packages/arbor-store/src/scoping/scope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ export class Scope<T extends object> {
return target
}

// TODO: handlers/map.ts must intercept child access so it can proxy them
// otherwise, accessing a child from a scoped map will not yield a scoped
// child but the actual underlying value.

const child = Reflect.get(target, prop, proxy)
const descriptor = Object.getOwnPropertyDescriptor(target, prop)

Expand Down
43 changes: 43 additions & 0 deletions packages/arbor-store/tests/scoping/map.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { describe, expect, it } from "vitest"
import { Arbor } from "../../src/arbor"
import { ScopedStore } from "../../src/scoping/store"

describe("map", () => {
describe("Symbol.iterator", () => {
it("can convert a map node from a scoped store to array", () => {
const store = new Arbor(
new Map([
[1, "Alice"],
[2, "Bob"],
])
)

const scope = new ScopedStore(store)
const list = Array.from(scope.state)

expect(list).toEqual([
[1, "Alice"],
[2, "Bob"],
])
})

it.skip("exposes scoped nodes", () => {
const bob = { name: "Bob" }
const alice = { name: "Alice" }
const store = new Arbor(
new Map([
[1, alice],
[2, bob],
])
)

const scope = new ScopedStore(store)
const list = Array.from(scope.state)

expect(list[0][1]).toBeNodeOf(alice)
expect(list[1][1]).toBeNodeOf(bob)
expect(list[0][1]).toBeTrackedNode()
expect(list[1][1]).toBeTrackedNode()
})
})
})

0 comments on commit bf5f80e

Please sign in to comment.