From 5a5617af1ed891f6bff15fac7a866c1d27f95de7 Mon Sep 17 00:00:00 2001 From: unadlib Date: Sat, 25 Nov 2023 00:46:20 +0800 Subject: [PATCH 1/2] fix(patch): filter no-referenced patches --- src/utils/draft.ts | 10 ++++-- src/utils/finalize.ts | 4 ++- test/immer-non-support.test.ts | 6 ++-- test/index.test.ts | 51 +++++++++++++++++++++++++++++- test/json-patch/duplexSpec.test.ts | 1 + 5 files changed, 65 insertions(+), 7 deletions(-) diff --git a/src/utils/draft.ts b/src/utils/draft.ts index 1a16b3fe..565ce35a 100644 --- a/src/utils/draft.ts +++ b/src/utils/draft.ts @@ -42,13 +42,19 @@ export function isDraftable(value: any, options?: { mark?: Mark }) { export function getPath( target: ProxyDraft, path: any[] = [] -): (string | number | object)[] { - if (Object.hasOwnProperty.call(target, 'key')) +): (string | number | object)[] | null { + if (Object.hasOwnProperty.call(target, 'key')) { + // check if the parent is a draft and the original value is not equal to the current value + const proxyDraft = getProxyDraft(get(target.parent!.copy, target.key!)); + if (proxyDraft !== null && proxyDraft?.original !== target.original) { + return null; + } path.push( target.parent!.type === DraftType.Set ? Array.from(target.parent!.setMap!.keys()).indexOf(target.key) : target.key ); + } if (target.parent) { return getPath(target.parent, path); } diff --git a/src/utils/finalize.ts b/src/utils/finalize.ts index 2b094486..1e512654 100644 --- a/src/utils/finalize.ts +++ b/src/utils/finalize.ts @@ -91,7 +91,9 @@ export function finalizePatches( if (shouldFinalize) { if (patches && inversePatches) { const basePath = getPath(target); - generatePatches(target, basePath, patches, inversePatches); + if (basePath) { + generatePatches(target, basePath, patches, inversePatches); + } } target.finalized = true; } diff --git a/test/immer-non-support.test.ts b/test/immer-non-support.test.ts index 975ef03f..b48275a4 100644 --- a/test/immer-non-support.test.ts +++ b/test/immer-non-support.test.ts @@ -345,7 +345,7 @@ test('#18 - set: assigning a non-draft with the same key', () => { // @ts-ignore expect(Array.from(created[0].array[0].one)[0].three).toBe(2); expect(apply(baseState, created[1])).toEqual(created[0]); - // expect(apply(created[0], created[2])).toEqual(baseState); + expect(apply(created[0], created[2])).toEqual(baseState); enablePatches(); // @ts-ignore @@ -369,7 +369,7 @@ test('#18 - set: assigning a non-draft with the same key', () => { }).toThrowError(); // @ts-ignore - // expect(applyPatches(baseState, produced[1])).toEqual(produced[0]); + expect(() => applyPatches(baseState, produced[1])).toThrowError(); // @ts-ignore - // expect(applyPatches(produced[0], produced[2])).toEqual(baseState); + expect(applyPatches(produced[0], produced[2])).toEqual(baseState); }); diff --git a/test/index.test.ts b/test/index.test.ts index e964d86b..4c037753 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -3059,7 +3059,56 @@ test('#18 - set: assigning a non-draft with the same key - deep6', () => { // @ts-ignore expect(apply(baseState, created[1])).toEqual(created[0]); // @ts-ignore - // expect(apply(created[0], created[2])).toEqual(baseState); + expect(apply(created[0], created[2])).toEqual(baseState); + expect(created).toMatchInlineSnapshot(` + [ + { + "array": [ + { + "one": Set { + { + "three": 2, + }, + }, + }, + ], + }, + [ + { + "op": "replace", + "path": [ + "array", + ], + "value": [ + { + "one": Set { + { + "three": 2, + }, + }, + }, + ], + }, + ], + [ + { + "op": "replace", + "path": [ + "array", + ], + "value": [ + { + "one": { + "two": { + "three": 3, + }, + }, + }, + ], + }, + ], + ] + `); }); test('#18 - set: assigning a non-draft with the same key - deep3', () => { diff --git a/test/json-patch/duplexSpec.test.ts b/test/json-patch/duplexSpec.test.ts index de2aa4b9..ec4ba3cc 100644 --- a/test/json-patch/duplexSpec.test.ts +++ b/test/json-patch/duplexSpec.test.ts @@ -1,3 +1,4 @@ +/* eslint-disable prefer-arrow-callback */ // @ts-nocheck import { create, apply } from '../../src'; From ce9aa0d42bbed9489fce4001d6db1c1bb5073c48 Mon Sep 17 00:00:00 2001 From: unadlib Date: Sat, 25 Nov 2023 14:21:42 +0800 Subject: [PATCH 2/2] fix(test): add test case --- test/immer-non-support.test.ts | 35 +++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/test/immer-non-support.test.ts b/test/immer-non-support.test.ts index b48275a4..5a8474dd 100644 --- a/test/immer-non-support.test.ts +++ b/test/immer-non-support.test.ts @@ -312,7 +312,7 @@ test('circular reference', () => { } }); -test('#18 - set: assigning a non-draft with the same key', () => { +test('#18 - set: assigning a non-draft with the same key - 1', () => { const baseState = { array: [ { @@ -373,3 +373,36 @@ test('#18 - set: assigning a non-draft with the same key', () => { // @ts-ignore expect(applyPatches(produced[0], produced[2])).toEqual(baseState); }); + +test('#18 - set: assigning a non-draft with the same key - 2', () => { + const baseState = { c: [{ a: 1 }, { a: 1 }] }; + enablePatches(); + // @ts-ignore + const produced = produceWithPatches(baseState, (draft) => { + const f = draft.c.pop(); + // @ts-ignore + f.a = 2; + // @ts-ignore + draft.c = new Set([draft.c[0], f]); + }); + // @ts-ignore + expect(() => applyPatches(baseState, produced[1])).toThrowError(); + // @ts-ignore + expect(applyPatches(produced[0], produced[2])).toEqual(baseState); + + const created = create( + baseState, + (draft) => { + const f = draft.c.pop(); + // @ts-ignore + f.a = 2; + // @ts-ignore + draft.c = new Set([draft.c[0], f]); + }, + { + enablePatches: true, + } + ); + expect(apply(baseState, created[1])).toEqual(created[0]); + expect(apply(created[0], created[2])).toEqual(baseState); +});