From b1c059e0d26f235058212cb70d2f7f488d62e10e Mon Sep 17 00:00:00 2001 From: unadlib Date: Mon, 25 Mar 2024 01:26:07 +0800 Subject: [PATCH] feat(patches): implement merge patches when archive() --- src/index.ts | 14 +++-- test/index.test.ts | 124 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 130 insertions(+), 8 deletions(-) diff --git a/src/index.ts b/src/index.ts index 6848818..3f9c746 100644 --- a/src/index.ts +++ b/src/index.ts @@ -198,8 +198,16 @@ export const useTravel = ( } if (!tempPatches.patches.length) return; setAllPatches((allPatchesDraft) => { - allPatchesDraft.patches.push(tempPatches.patches.flat()); - allPatchesDraft.inversePatches.push(tempPatches.inversePatches.flat()); + // All patches will be merged, it helps to minimize the patch structure + const [, patches, inversePatches] = create( + state as object, + (draft) => apply(draft, tempPatches.inversePatches.flat().reverse()), + { + enablePatches: true, + } + ); + allPatchesDraft.patches.push(inversePatches); + allPatchesDraft.inversePatches.push(patches); if (maxHistory < allPatchesDraft.patches.length) { allPatchesDraft.patches = allPatchesDraft.patches.slice(-maxHistory); allPatchesDraft.inversePatches = allPatchesDraft.inversePatches.slice( @@ -290,7 +298,7 @@ export const useTravel = ( } return cachedHistory; }, - patches: allPatches, + patches: shouldArchive ? _allPatches : allPatches, back: (amount = 1) => { go(position - amount); }, diff --git a/test/index.test.ts b/test/index.test.ts index 8dbc257..8b4b1da 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -416,7 +416,9 @@ describe('useTravel', () => { //@ts-expect-error act(() => controls.archive()); [nextState, setState, controls] = result.current; - expect(fnWarning).toHaveBeenCalledWith(`Auto archive is enabled, no need to archive manually`); + expect(fnWarning).toHaveBeenCalledWith( + `Auto archive is enabled, no need to archive manually` + ); }); it('[useTravel] with normal init state and disable autoArchive', () => { @@ -450,7 +452,7 @@ describe('useTravel', () => { }, ], }); - expect(controls.patches.patches.length).toBe(0); + expect(controls.patches.patches.length).toBe(1); expect(controls.position).toBe(1); expect(controls.getHistory()).toEqual([ { todos: [] }, @@ -475,7 +477,7 @@ describe('useTravel', () => { ); [nextState, setState, controls] = result.current; - expect(controls.patches.patches.length).toBe(0); + expect(controls.patches.patches.length).toBe(1); expect(controls.position).toBe(1); expect(controls.getHistory()).toEqual([ { todos: [] }, @@ -1024,7 +1026,6 @@ describe('useTravel', () => { expect(controls.position).toEqual(2); expect(controls.getHistory()).toEqual([0, 1, 2]); - act(() => controls.archive()); [nextState, setState, controls] = result.current; expect(nextState).toEqual(2); @@ -1037,7 +1038,6 @@ describe('useTravel', () => { expect(controls.position).toEqual(3); expect(controls.getHistory()).toEqual([0, 1, 2, 3]); - act(() => controls.archive()); [nextState, setState, controls] = result.current; expect(nextState).toEqual(3); @@ -1169,6 +1169,57 @@ describe('useTravel', () => { expect(controls.canBack()).toBe(true); expect(controls.canForward()).toBe(true); + expect(controls.patches).toMatchInlineSnapshot(` + { + "inversePatches": [ + [ + { + "op": "replace", + "path": [], + "value": 3, + }, + ], + [ + { + "op": "replace", + "path": [], + "value": 4, + }, + ], + [ + { + "op": "replace", + "path": [], + "value": 5, + }, + ], + ], + "patches": [ + [ + { + "op": "replace", + "path": [], + "value": 4, + }, + ], + [ + { + "op": "replace", + "path": [], + "value": 5, + }, + ], + [ + { + "op": "replace", + "path": [], + "value": 6, + }, + ], + ], + } + `); + result = renderHook(() => useTravel(nextState, { maxHistory: 3, @@ -1205,5 +1256,68 @@ describe('useTravel', () => { expect(controls.getHistory()).toEqual([3, 4, 5, 7]); expect(controls.canBack()).toBe(true); expect(controls.canForward()).toBe(false); + + act(() => setState(() => 8)); + [nextState, setState, controls] = result.current; + + expect(nextState).toEqual(8); + expect(controls.position).toEqual(3); + expect(controls.getHistory()).toEqual([3, 4, 7, 8]); + expect(controls.canBack()).toBe(true); + expect(controls.canForward()).toBe(false); + + act(() => controls.archive()); + [nextState, setState, controls] = result.current; + + expect(controls.patches).toMatchInlineSnapshot(` + { + "inversePatches": [ + [ + { + "op": "replace", + "path": [], + "value": 3, + }, + ], + [ + { + "op": "replace", + "path": [], + "value": 4, + }, + ], + [ + { + "op": "replace", + "path": [], + "value": 5, + }, + ], + ], + "patches": [ + [ + { + "op": "replace", + "path": [], + "value": 4, + }, + ], + [ + { + "op": "replace", + "path": [], + "value": 5, + }, + ], + [ + { + "op": "replace", + "path": [], + "value": 8, + }, + ], + ], + } + `); }); });