Repository: immerjs/immer (js)

Issue:
Appending to array using patch inserts element at beginning of array instead of the end
## 🐛 Bug Report

When using the `applyPatches` feature of immer with a patch that should append an element to the end of an array, the element is instead inserted at the beginning of the array.

## Link to repro

Using the [example from the JSON Patch RFC](https://datatracker.ietf.org/doc/html/rfc6902/#appendix-A.16):

>    An example target JSON document:
> 
>    { "foo": ["bar"] }
> 
>    A JSON Patch document:
> 
>    [
>      { "op": "add", "path": "/foo/-", "value": ["abc", "def"] }
>    ]
> 
>    The resulting JSON document:
> 
>    { "foo": ["bar", ["abc", "def"]] }

Doing so with immer instead creates the state:

```
//  { "foo": [ ["abc", "def"], "bar"]}
```

See https://codesandbox.io/s/immer-patch-append-ordering-repro-xi4d6 for a running version.

## Expected behavior

The element should be at the end of the array, not the beginning.

## Environment

- **Immer version:** 9.0.6
- [x] I filed this report against the _latest_ version of Immer
- [ ] Occurs with `setUseProxies(true)` n/a
- [ ] Occurs with `setUseProxies(false)` (ES5 only) n/a


Pull request:
Append to array when key is "-"
Closes #871

It's actually amazing '-' was doing anything at all! Definitely a JS quirk that the first argument to `splice` is coerced to a number, effectively becoming 0 if the parameter can't be parsed.

I also dropped an unnecessary `any` cast, and added a check for avoiding an unnecessary copy of the patch array.

Patch:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 9930e08..ebdefc4 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -15,7 +15,7 @@ jobs:
       - uses: actions/checkout@v2
       - uses: actions/setup-node@v2
         with:
-          node-version: 14
+          node-version: 16
       - name: install
         run: yarn
       - name: test
diff --git a/src/core/immerClass.ts b/src/core/immerClass.ts
index 6975225..074e90f 100644
--- a/src/core/immerClass.ts
+++ b/src/core/immerClass.ts
@@ -196,16 +196,21 @@ export class Immer implements ProducersFns {
 				break
 			}
 		}
+		// If there was a patch that replaced the entire state, start from the
+		// patch after that.
+		if (i > -1) {
+			patches = patches.slice(i + 1)
+		}
 
 		const applyPatchesImpl = getPlugin("Patches").applyPatches_
 		if (isDraft(base)) {
 			// N.B: never hits if some patch a replacement, patches are never drafts
-			return applyPatchesImpl(base, patches) as any
+			return applyPatchesImpl(base, patches)
 		}
 		// Otherwise, produce a copy of the base state.
 		return this.produce(base, (draft: Drafted) =>
-			applyPatchesImpl(draft, patches.slice(i + 1))
-		) as any
+			applyPatchesImpl(draft, patches)
+		)
 	}
 }
 
diff --git a/src/plugins/patches.ts b/src/plugins/patches.ts
index c4a7b4a..bd3e3d9 100644
--- a/src/plugins/patches.ts
+++ b/src/plugins/patches.ts
@@ -240,7 +240,9 @@ export function enablePatches() {
 				case ADD:
 					switch (type) {
 						case Archtype.Array:
-							return base.splice(key as any, 0, value)
+							return key === "-"
+								? base.push(value)
+								: base.splice(key as any, 0, value)
 						case Archtype.Map:
 							return base.set(key, value)
 						case Archtype.Set:
diff --git a/website/docs/update-patterns.md b/website/docs/update-patterns.md
index abb450d..f30de5a 100644
--- a/website/docs/update-patterns.md
+++ b/website/docs/update-patterns.md
@@ -136,7 +136,7 @@ const nextStore = produce(store, draft => {
 const nextStore = produce(store, draft => {
 	const user = draft.users.get("17")
 	// when filtering, creating a fresh collection is simpler than
-	// removing irrelvant items
+	// removing irrelevant items
 	user.todos = user.todos.filter(todo => todo.done)
 })
 ```
diff --git a/website/yarn.lock b/website/yarn.lock
index 8e931e5..5544a6a 100644
--- a/website/yarn.lock
+++ b/website/yarn.lock
@@ -2026,11 +2026,11 @@ autoprefixer@^9.4.7, autoprefixer@^9.6.1:
     postcss-value-parser "^4.1.0"
 
 axios@^0.21.1:
-  version "0.21.1"
-  resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
-  integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
+  version "0.21.4"
+  resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575"
+  integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==
   dependencies:
-    follow-redirects "^1.10.0"
+    follow-redirects "^1.14.0"
 
 babel-code-frame@^6.22.0:
   version "6.26.0"
@@ -4190,10 +4190,10 @@ flush-write-stream@^1.0.0:
     inherits "^2.0.3"
     readable-stream "^2.3.6"
 
-follow-redirects@^1.0.0, follow-redirects@^1.10.0:
-  version "1.13.2"
-  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.2.tgz#dd73c8effc12728ba5cf4259d760ea5fb83e3147"
-  integrity sha512-6mPTgLxYm3r6Bkkg0vNM0HTjfGrOEtsfbhagQvbxDEsEkpNhw582upBaoRZylzen6krEmxXJgt9Ju6HiI4O7BA==
+follow-redirects@^1.0.0, follow-redirects@^1.14.0:
+  version "1.14.5"
+  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.5.tgz#f09a5848981d3c772b5392309778523f8d85c381"
+  integrity sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==
 
 for-in@^1.0.2:
   version "1.0.2"


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index b63e5ec..d9c8f70 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -10,7 +10,7 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        node-version: [12.x, 14.x, 16.x]
+        node-version: [16.x]
         # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
     steps:
       - uses: actions/checkout@v2
diff --git a/__tests__/__prod_snapshots__/base.js.snap b/__tests__/__prod_snapshots__/base.js.snap
index 4ffc6b6..80aaa01 100644
--- a/__tests__/__prod_snapshots__/base.js.snap
+++ b/__tests__/__prod_snapshots__/base.js.snap
@@ -1,7 +1,5 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`base functionality - es5 (autofreeze) async recipe function works with rejected promises 1`] = `"[Immer] minified error nr: 3 {\\"a\\":0,\\"b\\":1}. Find the full error at: https://bit.ly/3cXEKWf"`;
-
 exports[`base functionality - es5 (autofreeze) map drafts revokes map proxies 1`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`;
 
 exports[`base functionality - es5 (autofreeze) map drafts revokes map proxies 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`;
@@ -10,22 +8,12 @@ exports[`base functionality - es5 (autofreeze) recipe functions cannot return a
 
 exports[`base functionality - es5 (autofreeze) recipe functions cannot return an object that references itself 1`] = `"Maximum call stack size exceeded"`;
 
-exports[`base functionality - es5 (autofreeze) revokes the draft once produce returns 1`] = `"[Immer] minified error nr: 3 {\\"a\\":1}. Find the full error at: https://bit.ly/3cXEKWf"`;
-
-exports[`base functionality - es5 (autofreeze) revokes the draft once produce returns 2`] = `"[Immer] minified error nr: 3 {\\"a\\":1}. Find the full error at: https://bit.ly/3cXEKWf"`;
-
-exports[`base functionality - es5 (autofreeze) revokes the draft once produce returns 3`] = `"[Immer] minified error nr: 3 [1]. Find the full error at: https://bit.ly/3cXEKWf"`;
-
-exports[`base functionality - es5 (autofreeze) revokes the draft once produce returns 4`] = `"[Immer] minified error nr: 3 [1]. Find the full error at: https://bit.ly/3cXEKWf"`;
-
 exports[`base functionality - es5 (autofreeze) set drafts revokes sets 1`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`;
 
 exports[`base functionality - es5 (autofreeze) set drafts revokes sets 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`;
 
 exports[`base functionality - es5 (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 - es5 (autofreeze)(patch listener) async recipe function works with rejected promises 1`] = `"[Immer] minified error nr: 3 {\\"a\\":0,\\"b\\":1}. Find the full error at: https://bit.ly/3cXEKWf"`;
-
 exports[`base functionality - es5 (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 - es5 (autofreeze)(patch listener) map drafts revokes map proxies 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`;
@@ -34,22 +22,12 @@ exports[`base functionality - es5 (autofreeze)(patch listener) recipe functions
 
 exports[`base functionality - es5 (autofreeze)(patch listener) recipe functions cannot return an object that references itself 1`] = `"Maximum call stack size exceeded"`;
 
-exports[`base functionality - es5 (autofreeze)(patch listener) revokes the draft once produce returns 1`] = `"[Immer] minified error nr: 3 {\\"a\\":1}. Find the full error at: https://bit.ly/3cXEKWf"`;
-
-exports[`base functionality - es5 (autofreeze)(patch listener) revokes the draft once produce returns 2`] = `"[Immer] minified error nr: 3 {\\"a\\":1}. Find the full error at: https://bit.ly/3cXEKWf"`;
-
-exports[`base functionality - es5 (autofreeze)(patch listener) revokes the draft once produce returns 3`] = `"[Immer] minified error nr: 3 [1]. Find the full error at: https://bit.ly/3cXEKWf"`;
-
-exports[`base functionality - es5 (autofreeze)(patch listener) revokes the draft once produce returns 4`] = `"[Immer] minified error nr: 3 [1]. Find the full error at: https://bit.ly/3cXEKWf"`;
-
 exports[`base functionality - es5 (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 - es5 (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 - es5 (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 - es5 (no freeze) async recipe function works with rejected promises 1`] = `"[Immer] minified error nr: 3 {\\"a\\":0,\\"b\\":1}. Find the full error at: https://bit.ly/3cXEKWf"`;
-
 exports[`base functionality - es5 (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 - es5 (no freeze) map drafts revokes map proxies 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`;
@@ -58,22 +36,12 @@ exports[`base functionality - es5 (no freeze) recipe functions cannot return a m
 
 exports[`base functionality - es5 (no freeze) recipe functions cannot return an object that references itself 1`] = `"Maximum call stack size exceeded"`;
 
-exports[`base functionality - es5 (no freeze) revokes the draft once produce returns 1`] = `"[Immer] minified error nr: 3 {\\"a\\":1}. Find the full error at: https://bit.ly/3cXEKWf"`;
-
-exports[`base functionality - es5 (no freeze) revokes the draft once produce returns 2`] = `"[Immer] minified error nr: 3 {\\"a\\":1}. Find the full error at: https://bit.ly/3cXEKWf"`;
-
-exports[`base functionality - es5 (no freeze) revokes the draft once produce returns 3`] = `"[Immer] minified error nr: 3 [1]. Find the full error at: https://bit.ly/3cXEKWf"`;
-
-exports[`base functionality - es5 (no freeze) revokes the draft once produce returns 4`] = `"[Immer] minified error nr: 3 [1]. Find the full error at: https://bit.ly/3cXEKWf"`;
-
 exports[`base functionality - es5 (no freeze) set drafts revokes sets 1`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`;
 
 exports[`base functionality - es5 (no freeze) set drafts revokes sets 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`;
 
 exports[`base functionality - es5 (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 - es5 (patch listener) async recipe function works with rejected promises 1`] = `"[Immer] minified error nr: 3 {\\"a\\":0,\\"b\\":1}. Find the full error at: https://bit.ly/3cXEKWf"`;
-
 exports[`base functionality - es5 (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 - es5 (patch listener) map drafts revokes map proxies 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`;
@@ -82,22 +50,12 @@ exports[`base functionality - es5 (patch listener) recipe functions cannot retur
 
 exports[`base functionality - es5 (patch listener) recipe functions cannot return an object that references itself 1`] = `"Maximum call stack size exceeded"`;
 
-exports[`base functionality - es5 (patch listener) revokes the draft once produce returns 1`] = `"[Immer] minified error nr: 3 {\\"a\\":1}. Find the full error at: https://bit.ly/3cXEKWf"`;
-
-exports[`base functionality - es5 (patch listener) revokes the draft once produce returns 2`] = `"[Immer] minified error nr: 3 {\\"a\\":1}. Find the full error at: https://bit.ly/3cXEKWf"`;
-
-exports[`base functionality - es5 (patch listener) revokes the draft once produce returns 3`] = `"[Immer] minified error nr: 3 [1]. Find the full error at: https://bit.ly/3cXEKWf"`;
-
-exports[`base functionality - es5 (patch listener) revokes the draft once produce returns 4`] = `"[Immer] minified error nr: 3 [1]. Find the full error at: https://bit.ly/3cXEKWf"`;
-
 exports[`base functionality - es5 (patch listener) set drafts revokes sets 1`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`;
 
 exports[`base functionality - es5 (patch listener) set drafts revokes sets 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`;
 
 exports[`base functionality - es5 (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 - proxy (autofreeze) async recipe function works with rejected promises 1`] = `"Cannot perform 'get' on a proxy that has been revoked"`;
-
 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 - proxy (autofreeze) map drafts revokes map proxies 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`;
@@ -106,22 +64,6 @@ exports[`base functionality - proxy (autofreeze) recipe functions cannot return
 
 exports[`base functionality - proxy (autofreeze) recipe functions cannot return an object that references itself 1`] = `"Maximum call stack size exceeded"`;
 
-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 - proxy (autofreeze) 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 - proxy (autofreeze) 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 - proxy (autofreeze) 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 - proxy (autofreeze) 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] 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"`;
@@ -132,8 +74,6 @@ exports[`base functionality - proxy (autofreeze) throws when Object.setPrototype
 
 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 - proxy (autofreeze)(patch listener) async recipe function works with rejected promises 1`] = `"Cannot perform 'get' on a proxy that has been revoked"`;
-
 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 - proxy (autofreeze)(patch listener) map drafts revokes map proxies 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`;
@@ -142,22 +82,6 @@ exports[`base functionality - proxy (autofreeze)(patch listener) recipe function
 
 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 - proxy (autofreeze)(patch listener) 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 - proxy (autofreeze)(patch listener) 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 - proxy (autofreeze)(patch listener) 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 - proxy (autofreeze)(patch listener) 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 - 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 - proxy (autofreeze)(patch listener) set drafts revokes sets 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`;
@@ -168,8 +92,6 @@ exports[`base functionality - proxy (autofreeze)(patch listener) throws when Obj
 
 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 - proxy (no freeze) async recipe function works with rejected promises 1`] = `"Cannot perform 'get' on a proxy that has been revoked"`;
-
 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 - proxy (no freeze) map drafts revokes map proxies 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`;
@@ -178,22 +100,6 @@ exports[`base functionality - proxy (no freeze) recipe functions cannot return a
 
 exports[`base functionality - proxy (no freeze) recipe functions cannot return an object that references itself 1`] = `"Maximum call stack size exceeded"`;
 
-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 - proxy (no freeze) 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 - proxy (no freeze) 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 - proxy (no freeze) 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 - proxy (no freeze) 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] 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"`;
@@ -204,8 +110,6 @@ exports[`base functionality - proxy (no freeze) throws when Object.setPrototypeO
 
 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 - proxy (patch listener) async recipe function works with rejected promises 1`] = `"Cannot perform 'get' on a proxy that has been revoked"`;
-
 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 - proxy (patch listener) map drafts revokes map proxies 2`] = `"[Immer] minified error nr: 3 '{}'. Find the full error at: https://bit.ly/3cXEKWf"`;
@@ -214,22 +118,6 @@ exports[`base functionality - proxy (patch listener) recipe functions cannot ret
 
 exports[`base functionality - proxy (patch listener) recipe functions cannot return an object that references itself 1`] = `"Maximum call stack size exceeded"`;
 
-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 - proxy (patch listener) 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 - proxy (patch listener) 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 - proxy (patch listener) 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 - proxy (patch listener) 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] 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"`;
diff --git a/__tests__/__prod_snapshots__/manual.js.snap b/__tests__/__prod_snapshots__/manual.js.snap
index 54f21ae..be440b4 100644
--- a/__tests__/__prod_snapshots__/manual.js.snap
+++ b/__tests__/__prod_snapshots__/manual.js.snap
@@ -1,14 +1,12 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`manual - es5 cannot modify after finish 1`] = `"[Immer] minified error nr: 3 {\\"a\\":2}. Find the full error at: https://bit.ly/3cXEKWf"`;
-
 exports[`manual - es5 should check arguments 1`] = `"[Immer] minified error nr: 8. Find the full error at: https://bit.ly/3cXEKWf"`;
 
 exports[`manual - es5 should check arguments 2`] = `"[Immer] minified error nr: 8. Find the full error at: https://bit.ly/3cXEKWf"`;
 
-exports[`manual - es5 should check arguments 3`] = `"Cannot read property 'A' of undefined"`;
+exports[`manual - es5 should check arguments 3`] = `"Cannot read properties of undefined (reading 'A')"`;
 
-exports[`manual - es5 should not finish twice 1`] = `"Cannot read property 'length' of null"`;
+exports[`manual - es5 should not finish twice 1`] = `"Cannot read properties of null (reading 'length')"`;
 
 exports[`manual - es5 should support patches drafts 1`] = `
 Array [
@@ -48,13 +46,11 @@ Array [
 ]
 `;
 
-exports[`manual - proxy cannot modify after finish 1`] = `"Cannot perform 'set' on a proxy that has been revoked"`;
-
 exports[`manual - proxy should check arguments 1`] = `"[Immer] minified error nr: 8. Find the full error at: https://bit.ly/3cXEKWf"`;
 
 exports[`manual - proxy should check arguments 2`] = `"[Immer] minified error nr: 8. Find the full error at: https://bit.ly/3cXEKWf"`;
 
-exports[`manual - proxy should check arguments 3`] = `"Cannot read property 'A' of undefined"`;
+exports[`manual - proxy should check arguments 3`] = `"Cannot read properties of undefined (reading 'A')"`;
 
 exports[`manual - proxy should not finish twice 1`] = `"Cannot perform 'get' on a proxy that has been revoked"`;
 
diff --git a/__tests__/patch.js b/__tests__/patch.js
index 8bacae1..7097d54 100644
--- a/__tests__/patch.js
+++ b/__tests__/patch.js
@@ -720,6 +720,22 @@ describe("arrays - delete", () => {
 	)
 })
 
+describe("arrays - append", () => {
+	test("appends to array when last part of path is '-'", () => {
+		const state = {
+			list: [1, 2, 3]
+		}
+		const patch = {
+			op: "add",
+			value: 4,
+			path: ["list", "-"]
+		}
+		expect(applyPatches(state, [patch])).toEqual({
+			list: [1, 2, 3, 4]
+		})
+	})
+})
+
 describe("sets - add - 1", () => {
 	runPatchTest(
 		new Set([1]),