From e71aebdaad77d168c507649bb15817638cbb1af5 Mon Sep 17 00:00:00 2001 From: Michel Weststrate Date: Fri, 24 Mar 2023 16:29:14 +0100 Subject: [PATCH] feat: Introduce strictShallowCopy, See #941, hrsh7th-use-strict-shallow-copy --- __tests__/__prod_snapshots__/base.js.snap | 332 +++++++++++++-- __tests__/__snapshots__/base.js.snap | 492 ++++++++++++++++++---- __tests__/base.js | 62 ++- __tests__/map-set.js | 2 +- __tests__/not-strict-copy.ts | 37 ++ package.json | 2 +- src/core/current.ts | 12 +- src/core/immerClass.ts | 14 +- src/core/proxy.ts | 12 +- src/immer.ts | 7 + src/types/index.js.flow | 7 + src/utils/common.ts | 13 +- website/docs/api.md | 1 + website/docs/complex-objects.md | 14 +- 14 files changed, 859 insertions(+), 148 deletions(-) create mode 100644 __tests__/not-strict-copy.ts diff --git a/__tests__/__prod_snapshots__/base.js.snap b/__tests__/__prod_snapshots__/base.js.snap index 0f0e1796..68c33478 100644 --- a/__tests__/__prod_snapshots__/base.js.snap +++ b/__tests__/__prod_snapshots__/base.js.snap @@ -1,76 +1,148 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`base functionality - proxy (autofreeze) map drafts revokes map proxies 1`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false map drafts revokes map proxies 1`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (autofreeze) map drafts revokes map proxies 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false map drafts revokes map proxies 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (autofreeze) recipe functions cannot return a modified child draft 1`] = `"[Immer] minified error nr: 4. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false recipe functions cannot return a modified child draft 1`] = `"[Immer] minified error nr: 4. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (autofreeze) recipe functions cannot return an object that references itself 1`] = `"Maximum call stack size exceeded"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false recipe functions cannot return an object that references itself 1`] = `"Maximum call stack size exceeded"`; -exports[`base functionality - proxy (autofreeze) set drafts revokes sets 1`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false set drafts revokes sets 1`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (autofreeze) set drafts revokes sets 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false set drafts revokes sets 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (autofreeze) throws when Object.defineProperty() is used on drafts 1`] = `"[Immer] minified error nr: 11. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false throws when Object.defineProperty() is used on drafts 1`] = `"[Immer] minified error nr: 11. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (autofreeze) throws when Object.setPrototypeOf() is used on a draft 1`] = `"[Immer] minified error nr: 12. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false throws when Object.setPrototypeOf() is used on a draft 1`] = `"[Immer] minified error nr: 12. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (autofreeze) throws when the draft is modified and another object is returned 1`] = `"[Immer] minified error nr: 4. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false throws when the draft is modified and another object is returned 1`] = `"[Immer] minified error nr: 4. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (autofreeze)(patch listener) map drafts revokes map proxies 1`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true map drafts revokes map proxies 1`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (autofreeze)(patch listener) map drafts revokes map proxies 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true map drafts revokes map proxies 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (autofreeze)(patch listener) recipe functions cannot return a modified child draft 1`] = `"[Immer] minified error nr: 4. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true recipe functions cannot return a modified child draft 1`] = `"[Immer] minified error nr: 4. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (autofreeze)(patch listener) recipe functions cannot return an object that references itself 1`] = `"Maximum call stack size exceeded"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true recipe functions cannot return an object that references itself 1`] = `"Maximum call stack size exceeded"`; -exports[`base functionality - proxy (autofreeze)(patch listener) set drafts revokes sets 1`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true set drafts revokes sets 1`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (autofreeze)(patch listener) set drafts revokes sets 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true set drafts revokes sets 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (autofreeze)(patch listener) throws when Object.defineProperty() is used on drafts 1`] = `"[Immer] minified error nr: 11. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true throws when Object.defineProperty() is used on drafts 1`] = `"[Immer] minified error nr: 11. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (autofreeze)(patch listener) throws when Object.setPrototypeOf() is used on a draft 1`] = `"[Immer] minified error nr: 12. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true throws when Object.setPrototypeOf() is used on a draft 1`] = `"[Immer] minified error nr: 12. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (autofreeze)(patch listener) throws when the draft is modified and another object is returned 1`] = `"[Immer] minified error nr: 4. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true throws when the draft is modified and another object is returned 1`] = `"[Immer] minified error nr: 4. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (no freeze) map drafts revokes map proxies 1`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false map drafts revokes map proxies 1`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (no freeze) map drafts revokes map proxies 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false map drafts revokes map proxies 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (no freeze) recipe functions cannot return a modified child draft 1`] = `"[Immer] minified error nr: 4. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false recipe functions cannot return a modified child draft 1`] = `"[Immer] minified error nr: 4. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (no freeze) recipe functions cannot return an object that references itself 1`] = `"Maximum call stack size exceeded"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false recipe functions cannot return an object that references itself 1`] = `"Maximum call stack size exceeded"`; -exports[`base functionality - proxy (no freeze) set drafts revokes sets 1`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false set drafts revokes sets 1`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (no freeze) set drafts revokes sets 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false set drafts revokes sets 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (no freeze) throws when Object.defineProperty() is used on drafts 1`] = `"[Immer] minified error nr: 11. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false throws when Object.defineProperty() is used on drafts 1`] = `"[Immer] minified error nr: 11. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (no freeze) throws when Object.setPrototypeOf() is used on a draft 1`] = `"[Immer] minified error nr: 12. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false throws when Object.setPrototypeOf() is used on a draft 1`] = `"[Immer] minified error nr: 12. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (no freeze) throws when the draft is modified and another object is returned 1`] = `"[Immer] minified error nr: 4. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false throws when the draft is modified and another object is returned 1`] = `"[Immer] minified error nr: 4. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (patch listener) map drafts revokes map proxies 1`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true map drafts revokes map proxies 1`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (patch listener) map drafts revokes map proxies 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true map drafts revokes map proxies 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (patch listener) recipe functions cannot return a modified child draft 1`] = `"[Immer] minified error nr: 4. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true recipe functions cannot return a modified child draft 1`] = `"[Immer] minified error nr: 4. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (patch listener) recipe functions cannot return an object that references itself 1`] = `"Maximum call stack size exceeded"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true recipe functions cannot return an object that references itself 1`] = `"Maximum call stack size exceeded"`; -exports[`base functionality - proxy (patch listener) set drafts revokes sets 1`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true set drafts revokes sets 1`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (patch listener) set drafts revokes sets 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true set drafts revokes sets 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (patch listener) throws when Object.defineProperty() is used on drafts 1`] = `"[Immer] minified error nr: 11. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true throws when Object.defineProperty() is used on drafts 1`] = `"[Immer] minified error nr: 11. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (patch listener) throws when Object.setPrototypeOf() is used on a draft 1`] = `"[Immer] minified error nr: 12. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true throws when Object.setPrototypeOf() is used on a draft 1`] = `"[Immer] minified error nr: 12. Find the full error at: https://bit.ly/3cXEKWf"`; -exports[`base functionality - proxy (patch listener) throws when the draft is modified and another object is returned 1`] = `"[Immer] minified error nr: 4. Find the full error at: https://bit.ly/3cXEKWf"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true throws when the draft is modified and another object is returned 1`] = `"[Immer] minified error nr: 4. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false map drafts revokes map proxies 1`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false map drafts revokes map proxies 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false recipe functions cannot return a modified child draft 1`] = `"[Immer] minified error nr: 4. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false recipe functions cannot return an object that references itself 1`] = `"Maximum call stack size exceeded"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false set drafts revokes sets 1`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false set drafts revokes sets 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false throws when Object.defineProperty() is used on drafts 1`] = `"[Immer] minified error nr: 11. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false throws when Object.setPrototypeOf() is used on a draft 1`] = `"[Immer] minified error nr: 12. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false throws when the draft is modified and another object is returned 1`] = `"[Immer] minified error nr: 4. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true map drafts revokes map proxies 1`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true map drafts revokes map proxies 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true recipe functions cannot return a modified child draft 1`] = `"[Immer] minified error nr: 4. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true recipe functions cannot return an object that references itself 1`] = `"Maximum call stack size exceeded"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true set drafts revokes sets 1`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true set drafts revokes sets 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true throws when Object.defineProperty() is used on drafts 1`] = `"[Immer] minified error nr: 11. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true throws when Object.setPrototypeOf() is used on a draft 1`] = `"[Immer] minified error nr: 12. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true throws when the draft is modified and another object is returned 1`] = `"[Immer] minified error nr: 4. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false map drafts revokes map proxies 1`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false map drafts revokes map proxies 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false recipe functions cannot return a modified child draft 1`] = `"[Immer] minified error nr: 4. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false recipe functions cannot return an object that references itself 1`] = `"Maximum call stack size exceeded"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false set drafts revokes sets 1`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false set drafts revokes sets 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false throws when Object.defineProperty() is used on drafts 1`] = `"[Immer] minified error nr: 11. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false throws when Object.setPrototypeOf() is used on a draft 1`] = `"[Immer] minified error nr: 12. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false throws when the draft is modified and another object is returned 1`] = `"[Immer] minified error nr: 4. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true map drafts revokes map proxies 1`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true map drafts revokes map proxies 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true recipe functions cannot return a modified child draft 1`] = `"[Immer] minified error nr: 4. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true recipe functions cannot return an object that references itself 1`] = `"Maximum call stack size exceeded"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true set drafts revokes sets 1`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true set drafts revokes sets 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true throws when Object.defineProperty() is used on drafts 1`] = `"[Immer] minified error nr: 11. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true throws when Object.setPrototypeOf() is used on a draft 1`] = `"[Immer] minified error nr: 12. Find the full error at: https://bit.ly/3cXEKWf"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true throws when the draft is modified and another object is returned 1`] = `"[Immer] minified error nr: 4. Find the full error at: https://bit.ly/3cXEKWf"`; exports[`complex nesting map / set / object modify deep object 1`] = ` Object { @@ -259,3 +331,191 @@ Array [ }, ] `; + +exports[`complex nesting map / set / object modify deep object 9`] = ` +Object { + "map": Map { + "set1" => Set { + Object { + "a": 2, + }, + Object { + "b": 2, + }, + }, + "set2" => Set { + Object { + "c": 3, + }, + }, + }, +} +`; + +exports[`complex nesting map / set / object modify deep object 10`] = ` +Array [ + Object { + "op": "remove", + "path": Array [ + "map", + "set1", + 0, + ], + "value": Object { + "a": 1, + }, + }, + Object { + "op": "add", + "path": Array [ + "map", + "set1", + 0, + ], + "value": Object { + "a": 2, + }, + }, +] +`; + +exports[`complex nesting map / set / object modify deep object 11`] = ` +Object { + "map": Map { + "set1" => Set { + Object { + "a": 2, + }, + Object { + "b": 2, + }, + }, + "set2" => Set { + Object { + "c": 3, + }, + }, + }, +} +`; + +exports[`complex nesting map / set / object modify deep object 12`] = ` +Array [ + Object { + "op": "remove", + "path": Array [ + "map", + "set1", + 0, + ], + "value": Object { + "a": 1, + }, + }, + Object { + "op": "add", + "path": Array [ + "map", + "set1", + 0, + ], + "value": Object { + "a": 2, + }, + }, +] +`; + +exports[`complex nesting map / set / object modify deep object 13`] = ` +Object { + "map": Map { + "set1" => Set { + Object { + "a": 2, + }, + Object { + "b": 2, + }, + }, + "set2" => Set { + Object { + "c": 3, + }, + }, + }, +} +`; + +exports[`complex nesting map / set / object modify deep object 14`] = ` +Array [ + Object { + "op": "remove", + "path": Array [ + "map", + "set1", + 0, + ], + "value": Object { + "a": 1, + }, + }, + Object { + "op": "add", + "path": Array [ + "map", + "set1", + 0, + ], + "value": Object { + "a": 2, + }, + }, +] +`; + +exports[`complex nesting map / set / object modify deep object 15`] = ` +Object { + "map": Map { + "set1" => Set { + Object { + "a": 2, + }, + Object { + "b": 2, + }, + }, + "set2" => Set { + Object { + "c": 3, + }, + }, + }, +} +`; + +exports[`complex nesting map / set / object modify deep object 16`] = ` +Array [ + Object { + "op": "remove", + "path": Array [ + "map", + "set1", + 0, + ], + "value": Object { + "a": 1, + }, + }, + Object { + "op": "add", + "path": Array [ + "map", + "set1", + 0, + ], + "value": Object { + "a": 2, + }, + }, +] +`; diff --git a/__tests__/__snapshots__/base.js.snap b/__tests__/__snapshots__/base.js.snap index 9e0b1ea0..e9144584 100644 --- a/__tests__/__snapshots__/base.js.snap +++ b/__tests__/__snapshots__/base.js.snap @@ -1,156 +1,308 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`base functionality - proxy (autofreeze) array drafts throws when a non-numeric property is added 1`] = `"[Immer] Immer only supports setting array indices and the 'length' property"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false array drafts throws when a non-numeric property is added 1`] = `"[Immer] Immer only supports setting array indices and the 'length' property"`; -exports[`base functionality - proxy (autofreeze) array drafts throws when a non-numeric property is deleted 1`] = `"[Immer] Immer only supports deleting array indices"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false array drafts throws when a non-numeric property is deleted 1`] = `"[Immer] Immer only supports deleting array indices"`; -exports[`base functionality - proxy (autofreeze) map drafts revokes map proxies 1`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false map drafts revokes map proxies 1`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; -exports[`base functionality - proxy (autofreeze) map drafts revokes map proxies 2`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false map drafts revokes map proxies 2`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; -exports[`base functionality - proxy (autofreeze) recipe functions cannot return a modified child draft 1`] = `"[Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft."`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false recipe functions cannot return a modified child draft 1`] = `"[Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft."`; -exports[`base functionality - proxy (autofreeze) recipe functions cannot return an object that references itself 1`] = `"[Immer] Immer forbids circular references"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false recipe functions cannot return an object that references itself 1`] = `"[Immer] Immer forbids circular references"`; -exports[`base functionality - proxy (autofreeze) revokes the draft once produce returns 1`] = `"Cannot perform 'get' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false revokes the draft once produce returns 1`] = `"Cannot perform 'get' on a proxy that has been revoked"`; -exports[`base functionality - proxy (autofreeze) revokes the draft once produce returns 2`] = `"Cannot perform 'set' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false revokes the draft once produce returns 2`] = `"Cannot perform 'set' on a proxy that has been revoked"`; -exports[`base functionality - proxy (autofreeze) revokes the draft once produce returns 3`] = `"Cannot perform 'get' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false revokes the draft once produce returns 3`] = `"Cannot perform 'get' on a proxy that has been revoked"`; -exports[`base functionality - proxy (autofreeze) revokes the draft once produce returns 4`] = `"Cannot perform 'set' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false revokes the draft once produce returns 4`] = `"Cannot perform 'set' on a proxy that has been revoked"`; -exports[`base functionality - proxy (autofreeze) revokes the draft once produce returns 5`] = `"Cannot perform 'get' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false revokes the draft once produce returns 5`] = `"Cannot perform 'get' on a proxy that has been revoked"`; -exports[`base functionality - proxy (autofreeze) revokes the draft once produce returns 6`] = `"Cannot perform 'set' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false revokes the draft once produce returns 6`] = `"Cannot perform 'set' on a proxy that has been revoked"`; -exports[`base functionality - proxy (autofreeze) revokes the draft once produce returns 7`] = `"Cannot perform 'get' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false revokes the draft once produce returns 7`] = `"Cannot perform 'get' on a proxy that has been revoked"`; -exports[`base functionality - proxy (autofreeze) revokes the draft once produce returns 8`] = `"Cannot perform 'set' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false revokes the draft once produce returns 8`] = `"Cannot perform 'set' on a proxy that has been revoked"`; -exports[`base functionality - proxy (autofreeze) set drafts revokes sets 1`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false set drafts revokes sets 1`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; -exports[`base functionality - proxy (autofreeze) set drafts revokes sets 2`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false set drafts revokes sets 2`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; -exports[`base functionality - proxy (autofreeze) throws when Object.defineProperty() is used on drafts 1`] = `"[Immer] Object.defineProperty() cannot be used on an Immer draft"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false throws when Object.defineProperty() is used on drafts 1`] = `"[Immer] Object.defineProperty() cannot be used on an Immer draft"`; -exports[`base functionality - proxy (autofreeze) throws when Object.setPrototypeOf() is used on a draft 1`] = `"[Immer] Object.setPrototypeOf() cannot be used on an Immer draft"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false throws when Object.setPrototypeOf() is used on a draft 1`] = `"[Immer] Object.setPrototypeOf() cannot be used on an Immer draft"`; -exports[`base functionality - proxy (autofreeze) throws when the draft is modified and another object is returned 1`] = `"[Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft."`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=false throws when the draft is modified and another object is returned 1`] = `"[Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft."`; -exports[`base functionality - proxy (autofreeze)(patch listener) array drafts throws when a non-numeric property is added 1`] = `"[Immer] Immer only supports setting array indices and the 'length' property"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true array drafts throws when a non-numeric property is added 1`] = `"[Immer] Immer only supports setting array indices and the 'length' property"`; -exports[`base functionality - proxy (autofreeze)(patch listener) array drafts throws when a non-numeric property is deleted 1`] = `"[Immer] Immer only supports deleting array indices"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true array drafts throws when a non-numeric property is deleted 1`] = `"[Immer] Immer only supports deleting array indices"`; -exports[`base functionality - proxy (autofreeze)(patch listener) map drafts revokes map proxies 1`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true map drafts revokes map proxies 1`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; -exports[`base functionality - proxy (autofreeze)(patch listener) map drafts revokes map proxies 2`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true map drafts revokes map proxies 2`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; -exports[`base functionality - proxy (autofreeze)(patch listener) recipe functions cannot return a modified child draft 1`] = `"[Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft."`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true recipe functions cannot return a modified child draft 1`] = `"[Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft."`; -exports[`base functionality - proxy (autofreeze)(patch listener) recipe functions cannot return an object that references itself 1`] = `"[Immer] Immer forbids circular references"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true recipe functions cannot return an object that references itself 1`] = `"[Immer] Immer forbids circular references"`; -exports[`base functionality - proxy (autofreeze)(patch listener) revokes the draft once produce returns 1`] = `"Cannot perform 'get' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true revokes the draft once produce returns 1`] = `"Cannot perform 'get' on a proxy that has been revoked"`; -exports[`base functionality - proxy (autofreeze)(patch listener) revokes the draft once produce returns 2`] = `"Cannot perform 'set' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true revokes the draft once produce returns 2`] = `"Cannot perform 'set' on a proxy that has been revoked"`; -exports[`base functionality - proxy (autofreeze)(patch listener) revokes the draft once produce returns 3`] = `"Cannot perform 'get' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true revokes the draft once produce returns 3`] = `"Cannot perform 'get' on a proxy that has been revoked"`; -exports[`base functionality - proxy (autofreeze)(patch listener) revokes the draft once produce returns 4`] = `"Cannot perform 'set' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true revokes the draft once produce returns 4`] = `"Cannot perform 'set' on a proxy that has been revoked"`; -exports[`base functionality - proxy (autofreeze)(patch listener) revokes the draft once produce returns 5`] = `"Cannot perform 'get' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true revokes the draft once produce returns 5`] = `"Cannot perform 'get' on a proxy that has been revoked"`; -exports[`base functionality - proxy (autofreeze)(patch listener) revokes the draft once produce returns 6`] = `"Cannot perform 'set' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true revokes the draft once produce returns 6`] = `"Cannot perform 'set' on a proxy that has been revoked"`; -exports[`base functionality - proxy (autofreeze)(patch listener) revokes the draft once produce returns 7`] = `"Cannot perform 'get' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true revokes the draft once produce returns 7`] = `"Cannot perform 'get' on a proxy that has been revoked"`; -exports[`base functionality - proxy (autofreeze)(patch listener) revokes the draft once produce returns 8`] = `"Cannot perform 'set' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true revokes the draft once produce returns 8`] = `"Cannot perform 'set' on a proxy that has been revoked"`; -exports[`base functionality - proxy (autofreeze)(patch listener) set drafts revokes sets 1`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true set drafts revokes sets 1`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; -exports[`base functionality - proxy (autofreeze)(patch listener) set drafts revokes sets 2`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true set drafts revokes sets 2`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; -exports[`base functionality - proxy (autofreeze)(patch listener) throws when Object.defineProperty() is used on drafts 1`] = `"[Immer] Object.defineProperty() cannot be used on an Immer draft"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true throws when Object.defineProperty() is used on drafts 1`] = `"[Immer] Object.defineProperty() cannot be used on an Immer draft"`; -exports[`base functionality - proxy (autofreeze)(patch listener) throws when Object.setPrototypeOf() is used on a draft 1`] = `"[Immer] Object.setPrototypeOf() cannot be used on an Immer draft"`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true throws when Object.setPrototypeOf() is used on a draft 1`] = `"[Immer] Object.setPrototypeOf() cannot be used on an Immer draft"`; -exports[`base functionality - proxy (autofreeze)(patch listener) throws when the draft is modified and another object is returned 1`] = `"[Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft."`; +exports[`base functionality - auto-freeze=false:shallow-copy=false:use-listener=true throws when the draft is modified and another object is returned 1`] = `"[Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft."`; -exports[`base functionality - proxy (no freeze) array drafts throws when a non-numeric property is added 1`] = `"[Immer] Immer only supports setting array indices and the 'length' property"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false array drafts throws when a non-numeric property is added 1`] = `"[Immer] Immer only supports setting array indices and the 'length' property"`; -exports[`base functionality - proxy (no freeze) array drafts throws when a non-numeric property is deleted 1`] = `"[Immer] Immer only supports deleting array indices"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false array drafts throws when a non-numeric property is deleted 1`] = `"[Immer] Immer only supports deleting array indices"`; -exports[`base functionality - proxy (no freeze) map drafts revokes map proxies 1`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false map drafts revokes map proxies 1`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; -exports[`base functionality - proxy (no freeze) map drafts revokes map proxies 2`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false map drafts revokes map proxies 2`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; -exports[`base functionality - proxy (no freeze) recipe functions cannot return a modified child draft 1`] = `"[Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft."`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false recipe functions cannot return a modified child draft 1`] = `"[Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft."`; -exports[`base functionality - proxy (no freeze) recipe functions cannot return an object that references itself 1`] = `"[Immer] Immer forbids circular references"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false recipe functions cannot return an object that references itself 1`] = `"[Immer] Immer forbids circular references"`; -exports[`base functionality - proxy (no freeze) revokes the draft once produce returns 1`] = `"Cannot perform 'get' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false revokes the draft once produce returns 1`] = `"Cannot perform 'get' on a proxy that has been revoked"`; -exports[`base functionality - proxy (no freeze) revokes the draft once produce returns 2`] = `"Cannot perform 'set' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false revokes the draft once produce returns 2`] = `"Cannot perform 'set' on a proxy that has been revoked"`; -exports[`base functionality - proxy (no freeze) revokes the draft once produce returns 3`] = `"Cannot perform 'get' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false revokes the draft once produce returns 3`] = `"Cannot perform 'get' on a proxy that has been revoked"`; -exports[`base functionality - proxy (no freeze) revokes the draft once produce returns 4`] = `"Cannot perform 'set' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false revokes the draft once produce returns 4`] = `"Cannot perform 'set' on a proxy that has been revoked"`; -exports[`base functionality - proxy (no freeze) revokes the draft once produce returns 5`] = `"Cannot perform 'get' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false revokes the draft once produce returns 5`] = `"Cannot perform 'get' on a proxy that has been revoked"`; -exports[`base functionality - proxy (no freeze) revokes the draft once produce returns 6`] = `"Cannot perform 'set' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false revokes the draft once produce returns 6`] = `"Cannot perform 'set' on a proxy that has been revoked"`; -exports[`base functionality - proxy (no freeze) revokes the draft once produce returns 7`] = `"Cannot perform 'get' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false revokes the draft once produce returns 7`] = `"Cannot perform 'get' on a proxy that has been revoked"`; -exports[`base functionality - proxy (no freeze) revokes the draft once produce returns 8`] = `"Cannot perform 'set' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false revokes the draft once produce returns 8`] = `"Cannot perform 'set' on a proxy that has been revoked"`; -exports[`base functionality - proxy (no freeze) set drafts revokes sets 1`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false set drafts revokes sets 1`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; -exports[`base functionality - proxy (no freeze) set drafts revokes sets 2`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false set drafts revokes sets 2`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; -exports[`base functionality - proxy (no freeze) throws when Object.defineProperty() is used on drafts 1`] = `"[Immer] Object.defineProperty() cannot be used on an Immer draft"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false throws when Object.defineProperty() is used on drafts 1`] = `"[Immer] Object.defineProperty() cannot be used on an Immer draft"`; -exports[`base functionality - proxy (no freeze) throws when Object.setPrototypeOf() is used on a draft 1`] = `"[Immer] Object.setPrototypeOf() cannot be used on an Immer draft"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false throws when Object.setPrototypeOf() is used on a draft 1`] = `"[Immer] Object.setPrototypeOf() cannot be used on an Immer draft"`; -exports[`base functionality - proxy (no freeze) throws when the draft is modified and another object is returned 1`] = `"[Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft."`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=false throws when the draft is modified and another object is returned 1`] = `"[Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft."`; -exports[`base functionality - proxy (patch listener) array drafts throws when a non-numeric property is added 1`] = `"[Immer] Immer only supports setting array indices and the 'length' property"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true array drafts throws when a non-numeric property is added 1`] = `"[Immer] Immer only supports setting array indices and the 'length' property"`; -exports[`base functionality - proxy (patch listener) array drafts throws when a non-numeric property is deleted 1`] = `"[Immer] Immer only supports deleting array indices"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true array drafts throws when a non-numeric property is deleted 1`] = `"[Immer] Immer only supports deleting array indices"`; -exports[`base functionality - proxy (patch listener) map drafts revokes map proxies 1`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true map drafts revokes map proxies 1`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; -exports[`base functionality - proxy (patch listener) map drafts revokes map proxies 2`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true map drafts revokes map proxies 2`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; -exports[`base functionality - proxy (patch listener) recipe functions cannot return a modified child draft 1`] = `"[Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft."`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true recipe functions cannot return a modified child draft 1`] = `"[Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft."`; -exports[`base functionality - proxy (patch listener) recipe functions cannot return an object that references itself 1`] = `"[Immer] Immer forbids circular references"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true recipe functions cannot return an object that references itself 1`] = `"[Immer] Immer forbids circular references"`; -exports[`base functionality - proxy (patch listener) revokes the draft once produce returns 1`] = `"Cannot perform 'get' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true revokes the draft once produce returns 1`] = `"Cannot perform 'get' on a proxy that has been revoked"`; -exports[`base functionality - proxy (patch listener) revokes the draft once produce returns 2`] = `"Cannot perform 'set' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true revokes the draft once produce returns 2`] = `"Cannot perform 'set' on a proxy that has been revoked"`; -exports[`base functionality - proxy (patch listener) revokes the draft once produce returns 3`] = `"Cannot perform 'get' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true revokes the draft once produce returns 3`] = `"Cannot perform 'get' on a proxy that has been revoked"`; -exports[`base functionality - proxy (patch listener) revokes the draft once produce returns 4`] = `"Cannot perform 'set' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true revokes the draft once produce returns 4`] = `"Cannot perform 'set' on a proxy that has been revoked"`; -exports[`base functionality - proxy (patch listener) revokes the draft once produce returns 5`] = `"Cannot perform 'get' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true revokes the draft once produce returns 5`] = `"Cannot perform 'get' on a proxy that has been revoked"`; -exports[`base functionality - proxy (patch listener) revokes the draft once produce returns 6`] = `"Cannot perform 'set' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true revokes the draft once produce returns 6`] = `"Cannot perform 'set' on a proxy that has been revoked"`; -exports[`base functionality - proxy (patch listener) revokes the draft once produce returns 7`] = `"Cannot perform 'get' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true revokes the draft once produce returns 7`] = `"Cannot perform 'get' on a proxy that has been revoked"`; -exports[`base functionality - proxy (patch listener) revokes the draft once produce returns 8`] = `"Cannot perform 'set' on a proxy that has been revoked"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true revokes the draft once produce returns 8`] = `"Cannot perform 'set' on a proxy that has been revoked"`; -exports[`base functionality - proxy (patch listener) set drafts revokes sets 1`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true set drafts revokes sets 1`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; -exports[`base functionality - proxy (patch listener) set drafts revokes sets 2`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true set drafts revokes sets 2`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; -exports[`base functionality - proxy (patch listener) throws when Object.defineProperty() is used on drafts 1`] = `"[Immer] Object.defineProperty() cannot be used on an Immer draft"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true throws when Object.defineProperty() is used on drafts 1`] = `"[Immer] Object.defineProperty() cannot be used on an Immer draft"`; -exports[`base functionality - proxy (patch listener) throws when Object.setPrototypeOf() is used on a draft 1`] = `"[Immer] Object.setPrototypeOf() cannot be used on an Immer draft"`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true throws when Object.setPrototypeOf() is used on a draft 1`] = `"[Immer] Object.setPrototypeOf() cannot be used on an Immer draft"`; -exports[`base functionality - proxy (patch listener) throws when the draft is modified and another object is returned 1`] = `"[Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft."`; +exports[`base functionality - auto-freeze=false:shallow-copy=true:use-listener=true throws when the draft is modified and another object is returned 1`] = `"[Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft."`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false array drafts throws when a non-numeric property is added 1`] = `"[Immer] Immer only supports setting array indices and the 'length' property"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false array drafts throws when a non-numeric property is deleted 1`] = `"[Immer] Immer only supports deleting array indices"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false map drafts revokes map proxies 1`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false map drafts revokes map proxies 2`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false recipe functions cannot return a modified child draft 1`] = `"[Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft."`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false recipe functions cannot return an object that references itself 1`] = `"[Immer] Immer forbids circular references"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false revokes the draft once produce returns 1`] = `"Cannot perform 'get' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false revokes the draft once produce returns 2`] = `"Cannot perform 'set' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false revokes the draft once produce returns 3`] = `"Cannot perform 'get' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false revokes the draft once produce returns 4`] = `"Cannot perform 'set' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false revokes the draft once produce returns 5`] = `"Cannot perform 'get' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false revokes the draft once produce returns 6`] = `"Cannot perform 'set' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false revokes the draft once produce returns 7`] = `"Cannot perform 'get' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false revokes the draft once produce returns 8`] = `"Cannot perform 'set' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false set drafts revokes sets 1`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false set drafts revokes sets 2`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false throws when Object.defineProperty() is used on drafts 1`] = `"[Immer] Object.defineProperty() cannot be used on an Immer draft"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false throws when Object.setPrototypeOf() is used on a draft 1`] = `"[Immer] Object.setPrototypeOf() cannot be used on an Immer draft"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=false throws when the draft is modified and another object is returned 1`] = `"[Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft."`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true array drafts throws when a non-numeric property is added 1`] = `"[Immer] Immer only supports setting array indices and the 'length' property"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true array drafts throws when a non-numeric property is deleted 1`] = `"[Immer] Immer only supports deleting array indices"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true map drafts revokes map proxies 1`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true map drafts revokes map proxies 2`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true recipe functions cannot return a modified child draft 1`] = `"[Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft."`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true recipe functions cannot return an object that references itself 1`] = `"[Immer] Immer forbids circular references"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true revokes the draft once produce returns 1`] = `"Cannot perform 'get' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true revokes the draft once produce returns 2`] = `"Cannot perform 'set' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true revokes the draft once produce returns 3`] = `"Cannot perform 'get' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true revokes the draft once produce returns 4`] = `"Cannot perform 'set' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true revokes the draft once produce returns 5`] = `"Cannot perform 'get' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true revokes the draft once produce returns 6`] = `"Cannot perform 'set' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true revokes the draft once produce returns 7`] = `"Cannot perform 'get' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true revokes the draft once produce returns 8`] = `"Cannot perform 'set' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true set drafts revokes sets 1`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true set drafts revokes sets 2`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true throws when Object.defineProperty() is used on drafts 1`] = `"[Immer] Object.defineProperty() cannot be used on an Immer draft"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true throws when Object.setPrototypeOf() is used on a draft 1`] = `"[Immer] Object.setPrototypeOf() cannot be used on an Immer draft"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=false:use-listener=true throws when the draft is modified and another object is returned 1`] = `"[Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft."`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false array drafts throws when a non-numeric property is added 1`] = `"[Immer] Immer only supports setting array indices and the 'length' property"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false array drafts throws when a non-numeric property is deleted 1`] = `"[Immer] Immer only supports deleting array indices"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false map drafts revokes map proxies 1`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false map drafts revokes map proxies 2`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false recipe functions cannot return a modified child draft 1`] = `"[Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft."`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false recipe functions cannot return an object that references itself 1`] = `"[Immer] Immer forbids circular references"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false revokes the draft once produce returns 1`] = `"Cannot perform 'get' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false revokes the draft once produce returns 2`] = `"Cannot perform 'set' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false revokes the draft once produce returns 3`] = `"Cannot perform 'get' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false revokes the draft once produce returns 4`] = `"Cannot perform 'set' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false revokes the draft once produce returns 5`] = `"Cannot perform 'get' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false revokes the draft once produce returns 6`] = `"Cannot perform 'set' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false revokes the draft once produce returns 7`] = `"Cannot perform 'get' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false revokes the draft once produce returns 8`] = `"Cannot perform 'set' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false set drafts revokes sets 1`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false set drafts revokes sets 2`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false throws when Object.defineProperty() is used on drafts 1`] = `"[Immer] Object.defineProperty() cannot be used on an Immer draft"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false throws when Object.setPrototypeOf() is used on a draft 1`] = `"[Immer] Object.setPrototypeOf() cannot be used on an Immer draft"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=false throws when the draft is modified and another object is returned 1`] = `"[Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft."`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true array drafts throws when a non-numeric property is added 1`] = `"[Immer] Immer only supports setting array indices and the 'length' property"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true array drafts throws when a non-numeric property is deleted 1`] = `"[Immer] Immer only supports deleting array indices"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true map drafts revokes map proxies 1`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true map drafts revokes map proxies 2`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true recipe functions cannot return a modified child draft 1`] = `"[Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft."`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true recipe functions cannot return an object that references itself 1`] = `"[Immer] Immer forbids circular references"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true revokes the draft once produce returns 1`] = `"Cannot perform 'get' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true revokes the draft once produce returns 2`] = `"Cannot perform 'set' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true revokes the draft once produce returns 3`] = `"Cannot perform 'get' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true revokes the draft once produce returns 4`] = `"Cannot perform 'set' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true revokes the draft once produce returns 5`] = `"Cannot perform 'get' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true revokes the draft once produce returns 6`] = `"Cannot perform 'set' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true revokes the draft once produce returns 7`] = `"Cannot perform 'get' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true revokes the draft once produce returns 8`] = `"Cannot perform 'set' on a proxy that has been revoked"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true set drafts revokes sets 1`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true set drafts revokes sets 2`] = `"[Immer] Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? {}"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true throws when Object.defineProperty() is used on drafts 1`] = `"[Immer] Object.defineProperty() cannot be used on an Immer draft"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true throws when Object.setPrototypeOf() is used on a draft 1`] = `"[Immer] Object.setPrototypeOf() cannot be used on an Immer draft"`; + +exports[`base functionality - auto-freeze=true:shallow-copy=true:use-listener=true throws when the draft is modified and another object is returned 1`] = `"[Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft."`; exports[`complex nesting map / set / object modify deep object 1`] = ` Object { @@ -339,3 +491,191 @@ Array [ }, ] `; + +exports[`complex nesting map / set / object modify deep object 9`] = ` +Object { + "map": Map { + "set1" => Set { + Object { + "a": 2, + }, + Object { + "b": 2, + }, + }, + "set2" => Set { + Object { + "c": 3, + }, + }, + }, +} +`; + +exports[`complex nesting map / set / object modify deep object 10`] = ` +Array [ + Object { + "op": "remove", + "path": Array [ + "map", + "set1", + 0, + ], + "value": Object { + "a": 1, + }, + }, + Object { + "op": "add", + "path": Array [ + "map", + "set1", + 0, + ], + "value": Object { + "a": 2, + }, + }, +] +`; + +exports[`complex nesting map / set / object modify deep object 11`] = ` +Object { + "map": Map { + "set1" => Set { + Object { + "a": 2, + }, + Object { + "b": 2, + }, + }, + "set2" => Set { + Object { + "c": 3, + }, + }, + }, +} +`; + +exports[`complex nesting map / set / object modify deep object 12`] = ` +Array [ + Object { + "op": "remove", + "path": Array [ + "map", + "set1", + 0, + ], + "value": Object { + "a": 1, + }, + }, + Object { + "op": "add", + "path": Array [ + "map", + "set1", + 0, + ], + "value": Object { + "a": 2, + }, + }, +] +`; + +exports[`complex nesting map / set / object modify deep object 13`] = ` +Object { + "map": Map { + "set1" => Set { + Object { + "a": 2, + }, + Object { + "b": 2, + }, + }, + "set2" => Set { + Object { + "c": 3, + }, + }, + }, +} +`; + +exports[`complex nesting map / set / object modify deep object 14`] = ` +Array [ + Object { + "op": "remove", + "path": Array [ + "map", + "set1", + 0, + ], + "value": Object { + "a": 1, + }, + }, + Object { + "op": "add", + "path": Array [ + "map", + "set1", + 0, + ], + "value": Object { + "a": 2, + }, + }, +] +`; + +exports[`complex nesting map / set / object modify deep object 15`] = ` +Object { + "map": Map { + "set1" => Set { + Object { + "a": 2, + }, + Object { + "b": 2, + }, + }, + "set2" => Set { + Object { + "c": 3, + }, + }, + }, +} +`; + +exports[`complex nesting map / set / object modify deep object 16`] = ` +Array [ + Object { + "op": "remove", + "path": Array [ + "map", + "set1", + 0, + ], + "value": Object { + "a": 1, + }, + }, + Object { + "op": "add", + "path": Array [ + "map", + "set1", + 0, + ], + "value": Object { + "a": 2, + }, + }, +] +`; diff --git a/__tests__/base.js b/__tests__/base.js index a3b94702..12341fb8 100644 --- a/__tests__/base.js +++ b/__tests__/base.js @@ -9,7 +9,6 @@ import { } from "../src/immer" import {each, shallowCopy, DRAFT_STATE} from "../src/internal" import deepFreeze from "deep-freeze" -import cloneDeep from "lodash.clonedeep" import * as lodash from "lodash" jest.setTimeout(1000) @@ -22,17 +21,24 @@ test("immer should have no dependencies", () => { expect(require("../package.json").dependencies).toBeUndefined() }) -runBaseTest("proxy (no freeze)", false) -runBaseTest("proxy (autofreeze)", true) -runBaseTest("proxy (patch listener)", false, true) -runBaseTest("proxy (autofreeze)(patch listener)", true, true) +for (const autoFreeze of [true, false]) { + for (const useStrictShallowCopy of [true, false]) { + for (const useListener of [true, false]) { + const name = `${autoFreeze ? "auto-freeze=true" : "auto-freeze=false"}:${ + useStrictShallowCopy ? "shallow-copy=true" : "shallow-copy=false" + }:${useListener ? "use-listener=true" : "use-listener=false"}` + runBaseTest(name, autoFreeze, useStrictShallowCopy, useListener) + } + } +} class Foo {} -function runBaseTest(name, autoFreeze, useListener) { +function runBaseTest(name, autoFreeze, useStrictShallowCopy, useListener) { const listener = useListener ? function() {} : undefined const {produce, produceWithPatches} = createPatchedImmer({ - autoFreeze + autoFreeze, + useStrictShallowCopy }) // When `useListener` is true, append a function to the arguments of every @@ -890,10 +896,16 @@ function runBaseTest(name, autoFreeze, useListener) { expect(s[test]).toBeTruthy() s.foo = true }) - expect(nextState).toEqual({ - [test]: true, - foo: true - }) + if (useStrictShallowCopy) { + expect(nextState).toEqual({ + [test]: true, + foo: true + }) + } else { + expect(nextState).toEqual({ + foo: true + }) + } }) if (!global.USES_BUILD) @@ -909,16 +921,26 @@ function runBaseTest(name, autoFreeze, useListener) { value: 1, enumerable: false }) + // Non-enumerable primitive property that won't modified. + Object.defineProperty(baseState, "baz", { + value: 1, + enumerable: false + }) + + // When using Proxy, even non-enumerable keys will be copied if it's changed. + const canReferNonEnumerableProperty = useStrictShallowCopy const nextState = produce(baseState, s => { - expect(s.foo).toBeTruthy() - expect(isEnumerable(s, "foo")).toBeFalsy() - s.bar++ - expect(isEnumerable(s, "foo")).toBeFalsy() - s.foo.a++ - expect(isEnumerable(s, "foo")).toBeFalsy() - }) - expect(nextState.foo).toBeTruthy() - expect(isEnumerable(nextState, "foo")).toBeFalsy() + if (canReferNonEnumerableProperty) expect(s.foo).toBeTruthy() + if (useStrictShallowCopy) expect(isEnumerable(s, "foo")).toBeFalsy() + if (canReferNonEnumerableProperty) s.bar++ + if (useStrictShallowCopy) expect(isEnumerable(s, "foo")).toBeFalsy() + if (canReferNonEnumerableProperty) s.foo.a++ + if (useStrictShallowCopy) expect(isEnumerable(s, "foo")).toBeFalsy() + }) + if (canReferNonEnumerableProperty) expect(nextState.foo).toBeTruthy() + if (useStrictShallowCopy) + expect(isEnumerable(nextState, "foo")).toBeFalsy() + if (useStrictShallowCopy) expect(nextState.baz).toBeTruthy() }) it("can work with own computed props", () => { diff --git a/__tests__/map-set.js b/__tests__/map-set.js index a99332d3..1d9d80ee 100644 --- a/__tests__/map-set.js +++ b/__tests__/map-set.js @@ -7,7 +7,7 @@ import { immerable, enablePatches } from "../src/immer" -import {each, shallowCopy, isEnumerable, DRAFT_STATE} from "../src/common" +import {each, shallowCopy, isEnumerable, DRAFT_STATE} from "../src/utils/common" enablePatches() diff --git a/__tests__/not-strict-copy.ts b/__tests__/not-strict-copy.ts new file mode 100644 index 00000000..474d6529 --- /dev/null +++ b/__tests__/not-strict-copy.ts @@ -0,0 +1,37 @@ +import {produce, setUseStrictShallowCopy} from "../src/immer" + +describe("setUseStrictShallowCopy(true)", () => { + test("keep descriptors", () => { + setUseStrictShallowCopy(true) + + const base: Record = {} + Object.defineProperty(base, "foo", { + value: "foo", + writable: false, + configurable: false + }) + const copy = produce(base, (draft: any) => { + draft.bar = "bar" + }) + expect(Object.getOwnPropertyDescriptor(copy, "foo")).toStrictEqual( + Object.getOwnPropertyDescriptor(base, "foo") + ) + }) +}) + +describe("setUseStrictShallowCopy(false)", () => { + test("ignore descriptors", () => { + setUseStrictShallowCopy(false) + + const base: Record = {} + Object.defineProperty(base, "foo", { + value: "foo", + writable: false, + configurable: false + }) + const copy = produce(base, (draft: any) => { + draft.bar = "bar" + }) + expect(Object.getOwnPropertyDescriptor(copy, "foo")).toBeUndefined() + }) +}) diff --git a/package.json b/package.json index 654ba098..2fb7ed5a 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "sideEffects": false, "scripts": { "test": "jest && yarn test:build && yarn test:flow", - "test:perf": "cd __performance_tests__ && babel-node add-data.js && babel-node todo.js && babel-node incremental.js", + "test:perf": "cd __performance_tests__ && babel-node add-data.js && babel-node todo.js && babel-node incremental.js && babel-node large-obj.js", "test:flow": "yarn flow check __tests__/flow", "test:build": "yarn build && NODE_ENV='production' yarn jest --config jest.config.build.js", "watch": "jest --watch", diff --git a/src/core/current.ts b/src/core/current.ts index 9008b34a..4ea4e4bf 100644 --- a/src/core/current.ts +++ b/src/core/current.ts @@ -28,10 +28,14 @@ function currentImpl(value: any): any { if (!state.modified_) return state.base_ // Optimization: avoid generating new drafts during copying state.finalized_ = true - copy = copyHelper(value, archType) + copy = copyHelper( + value, + archType, + state.scope_.immer_.useStrictShallowCopy_ + ) state.finalized_ = false } else { - copy = copyHelper(value, archType) + copy = copyHelper(value, archType, true) } each(copy, (key, childValue) => { @@ -42,7 +46,7 @@ function currentImpl(value: any): any { return archType === ArchType.Set ? new Set(copy) : copy } -function copyHelper(value: any, archType: number): any { +function copyHelper(value: any, archType: number, strict: boolean): any { // creates a shallow copy, even if it is a map or set switch (archType) { case ArchType.Map: @@ -51,5 +55,5 @@ function copyHelper(value: any, archType: number): any { // Set will be cloned as array temporarily, so that we can replace individual items return Array.from(value) } - return shallowCopy(value) + return shallowCopy(value, strict) } diff --git a/src/core/immerClass.ts b/src/core/immerClass.ts index b5e0c835..eaef8c3b 100644 --- a/src/core/immerClass.ts +++ b/src/core/immerClass.ts @@ -35,10 +35,13 @@ interface ProducersFns { export class Immer implements ProducersFns { autoFreeze_: boolean = true + useStrictShallowCopy_: boolean = false - constructor(config?: {autoFreeze?: boolean}) { + constructor(config?: {autoFreeze?: boolean; useStrictShallowCopy?: boolean}) { if (typeof config?.autoFreeze === "boolean") this.setAutoFreeze(config!.autoFreeze) + if (typeof config?.useStrictShallowCopy === "boolean") + this.setUseStrictShallowCopy(config!.useStrictShallowCopy) } /** @@ -158,6 +161,15 @@ export class Immer implements ProducersFns { this.autoFreeze_ = value } + /** + * Pass true to enable strict shallow copy. + * + * By default, immer does not copy the object descriptors such as getter, setter and non-enumrable properties. + */ + setUseStrictShallowCopy(value: boolean) { + this.useStrictShallowCopy_ = value + } + applyPatches(base: T, patches: Patch[]): T { // If a patch replaces the entire state, take that replacement as base // before applying patches diff --git a/src/core/proxy.ts b/src/core/proxy.ts index 36649a03..d3f76316 100644 --- a/src/core/proxy.ts +++ b/src/core/proxy.ts @@ -17,6 +17,7 @@ import { createProxy, ArchType } from "../internal" +import {ImmerScope} from "./scope" interface ProxyBaseState extends ImmerBaseState { assigned_: { @@ -269,8 +270,15 @@ export function markChanged(state: ImmerState) { } } -export function prepareCopy(state: {base_: any; copy_: any}) { +export function prepareCopy(state: { + base_: any + copy_: any + scope_: ImmerScope +}) { if (!state.copy_) { - state.copy_ = shallowCopy(state.base_) + state.copy_ = shallowCopy( + state.base_, + state.scope_.immer_.useStrictShallowCopy_ + ) } } diff --git a/src/immer.ts b/src/immer.ts index 95b9025b..c3cb7de7 100644 --- a/src/immer.ts +++ b/src/immer.ts @@ -58,6 +58,13 @@ export const produceWithPatches: IProduceWithPatches = immer.produceWithPatches. */ export const setAutoFreeze = immer.setAutoFreeze.bind(immer) +/** + * Pass true to enable strict shallow copy. + * + * By default, immer does not copy the object descriptors such as getter, setter and non-enumrable properties. + */ +export const setUseStrictShallowCopy = immer.setUseStrictShallowCopy.bind(immer) + /** * Apply an array of Immer patches to the first argument. * diff --git a/src/types/index.js.flow b/src/types/index.js.flow index 28fb45ff..0f705e82 100644 --- a/src/types/index.js.flow +++ b/src/types/index.js.flow @@ -83,6 +83,13 @@ declare export function setAutoFreeze(autoFreeze: boolean): void */ declare export function setUseProxies(useProxies: boolean): void +/** + * Pass false to disable strict shallow copy. + * + * By default, immer does not copy the object descriptors such as getter, setter and non-enumrable properties. + */ +declare export function setUseStrictShallowCopy(useStrictShallowCopy: boolean): void + declare export function applyPatches(state: S, patches: Patch[]): S declare export function original(value: S): S diff --git a/src/utils/common.ts b/src/utils/common.ts index 76bed7e7..c5ed65d9 100644 --- a/src/utils/common.ts +++ b/src/utils/common.ts @@ -139,8 +139,19 @@ export function latest(state: ImmerState): any { } /*#__PURE__*/ -export function shallowCopy(base: any) { +export function shallowCopy(base: any, strict: boolean) { if (Array.isArray(base)) return Array.prototype.slice.call(base) + + if (!strict && isPlainObject(base)) { + const keys = Object.keys(base) + const obj: any = Object.create(Object.getPrototypeOf(base)) + for (let i = 0; i < keys.length; i++) { + const key = keys[i] + obj[key] = base[key] + } + return obj + } + const descriptors = getOwnPropertyDescriptors(base) delete descriptors[DRAFT_STATE as any] let keys = ownKeys(descriptors) diff --git a/website/docs/api.md b/website/docs/api.md index 15d5aa39..9506ffb3 100644 --- a/website/docs/api.md +++ b/website/docs/api.md @@ -30,6 +30,7 @@ title: API overview | `produceWithPatches` | Works the same as `produce`, but instead of just returning the produced object, it returns a tuple, consisting of `[result, patches, inversePatches]`. | [Patches](./patches.mdx) | | `setAutoFreeze` | Enables / disables automatic freezing of the trees produces. By default enabled. | [Freezing](./freezing.mdx) | | `setUseProxies` | Can be used to disable or force the use of `Proxy` objects. Useful when filing bug reports. | | +| `setUseStrictShallowCopy` | Can be used to enable strict shallow copy. If enable, immer copies non-enumerable properties as much as possible. | [Classes](./complex-objects.md) | ## Importing immer diff --git a/website/docs/complex-objects.md b/website/docs/complex-objects.md index b338e3f9..ed242bc1 100644 --- a/website/docs/complex-objects.md +++ b/website/docs/complex-objects.md @@ -7,6 +7,8 @@ title: Classes
+By default, Immer does not strictly handle Plain object's non-eumerable properties such as getters/setters for performance reason. If you want this behavior to be strict, you can opt-in with `useStrictShallowCopy(true)`. + Plain objects (objects without a prototype), arrays, `Map`s and `Set`s are always drafted by Immer. Every other object must use the `immerable` symbol to mark itself as compatible with Immer. When one of these objects is mutated within a producer, its prototype is preserved between copies. ```js @@ -59,12 +61,12 @@ console.log(clock2 instanceof Clock) // true The semantics on how classes are drafted are as follows: 1. A draft of a class is a fresh object but with the same prototype as the original object. -2. When creating a draft, Immer will copy all _own_ properties from the base to the draft.This includes non-enumerable and symbolic properties. -3. _Own_ getters will be invoked during the copy process, just like `Object.assign` would. -4. Inherited getters and methods will remain as is and be inherited by the draft. -5. Immer will not invoke constructor functions. -6. The final instance will be constructed with the same mechanism as the draft was created. -7. Only getters that have a setter as well will be writable in the draft, as otherwise the value can't be copied back. +1. When creating a draft, Immer will copy all _own_ properties from the base to the draft.This includes non-enumerable and symbolic properties (if `useStrictShallowCopy(true)` was called). +1. _Own_ getters will be invoked during the copy process, just like `Object.assign` would. +1. Inherited getters and methods will remain as is and be inherited by the draft. +1. Immer will not invoke constructor functions. +1. The final instance will be constructed with the same mechanism as the draft was created. +1. Only getters that have a setter as well will be writable in the draft, as otherwise the value can't be copied back. Because Immer will dereference own getters of objects into normal properties, it is possible to use objects that use getter/setter traps on their fields, like MobX and Vue do.