Skip to content

Commit

Permalink
fix: produce results should never be frozen when returned from nested…
Browse files Browse the repository at this point in the history
… produces, to prevent 'hiding' drafts. Fixes #935
  • Loading branch information
mweststrate committed Jan 15, 2023
1 parent 46867f8 commit a810960
Show file tree
Hide file tree
Showing 3 changed files with 10 additions and 5 deletions.
10 changes: 8 additions & 2 deletions __tests__/regressions.js
Expand Up @@ -252,7 +252,7 @@ function runBaseTest(name, useProxies, autoFreeze, useListener) {
})
})

test("Nested and chained produce calls throw 'Cannot perform 'get' on a proxy that has been revoked' error", () => {
test.only("Nested and chained produce calls throw 'Cannot perform 'get' on a proxy that has been revoked' error", () => {
const state = {
foo: {
bar: {
Expand All @@ -267,9 +267,15 @@ function runBaseTest(name, useProxies, autoFreeze, useListener) {
draft.foo = produce(draft.foo, fooDraft => {
/* another produce call makes this fail */
/* no actual mutation necessary to make this happen */
// This happened before becouse the outer object is not modified,
// so assumed to be safely freezable by Immer, while it actually still
// contains a draft of bar, which wasn't retracted since we don't do that in nested
// producers, as it can still be modified outside a produce
})
})
JSON.stringify(newState)
expect(newState).toEqual({
foo: {baz: "apple", bar: {baz: "banana"}}
})
})
})
}
3 changes: 2 additions & 1 deletion src/core/finalize.ts
Expand Up @@ -161,7 +161,8 @@ function finalizeProperty(
}

function maybeFreeze(scope: ImmerScope, value: any, deep = false) {
if (scope.immer_.autoFreeze_ && scope.canAutoFreeze_) {
// we never freeze for a non-root scope; as it would prevent pruning for drafts inside wrapping objects
if (!scope.parent_ && scope.immer_.autoFreeze_ && scope.canAutoFreeze_) {
freeze(value, deep)
}
}
2 changes: 0 additions & 2 deletions src/core/immerClass.ts
Expand Up @@ -88,8 +88,6 @@ export class Immer implements ProducersFns {
// Only plain objects, arrays, and "immerable classes" are drafted.
if (isDraftable(base)) {
const scope = enterScope(this)
//when base is a draft,can't freeze
scope.canAutoFreeze_ = !isDraft(base)
const proxy = createProxy(this, base, undefined)
let hasError = true
try {
Expand Down

0 comments on commit a810960

Please sign in to comment.