patch-recorder 0.0.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -11,6 +11,7 @@
11
11
  - ✅ **Immediate patch generation** - Patches generated as mutations occur
12
12
  - ✅ **Optimization enabled by default** - Automatically compresses/merges redundant patches
13
13
  - ✅ **Full collection support** - Works with objects, arrays, Maps, and Sets
14
+ - ✅ **Item ID tracking** - Optionally include item IDs in remove/replace patches
14
15
 
15
16
  ## Installation
16
17
 
@@ -55,7 +56,7 @@ Unlike mutative or immer, **patch-recorder mutates the original object in place*
55
56
  - Perfect for scenarios where you need both mutation tracking AND direct object manipulation
56
57
 
57
58
  **Performance:**
58
- - Substantially faster than mutative (2x to 1,000x depending on operation)
59
+ - Substantially faster than mutative (1.1x to 650x depending on operation)
59
60
  - Especially dramatic speedups for array index and Map operations
60
61
  - Consistent performance improvements across all data types
61
62
 
@@ -76,10 +77,6 @@ const patches = recordPatches(state, (draft) => {
76
77
 
77
78
  Records JSON patches from mutations applied to the state.
78
79
 
79
- ### `create(state, mutate, options?)`
80
-
81
- Mutative-compatible API for easy switching between mutative and patch-recorder. Returns `[state, patches]` tuple like mutative does.
82
-
83
80
  **Key difference from mutative:** Unlike mutative which creates a new state copy, this mutates the original object in place. The returned `state` is the same reference as the input state.
84
81
 
85
82
  **Note:** The `enablePatches` option is forced to `true` by default for full mutative compatibility (patches are always returned).
@@ -92,19 +89,15 @@ Mutative-compatible API for easy switching between mutative and patch-recorder.
92
89
 
93
90
  #### Options
94
91
 
95
- For `recordPatches`:
96
92
 
97
- - **`pathAsArray`** (boolean, default: `true`) - Return paths as arrays or strings
98
- - **`arrayLengthAssignment`** (boolean, default: `true`) - Include array length in patches
93
+ - **`arrayLengthAssignment`** (boolean, default: `true`) - When `true`, includes length patches when array shrinks (pop, shift, splice delete). When `false`, omits length patches entirely. Aligned with mutative's behavior.
99
94
  - **`compressPatches`** (boolean, default: `true`) - Compress patches by merging redundant operations
95
+ - **`getItemId`** (object, optional) - Configuration for extracting item IDs (see [Item ID Tracking](#item-id-tracking))
100
96
 
101
- For `create` (additional options for mutative compatibility):
102
- - **`enablePatches`** (boolean, default: `true`) - Always true, patches are always returned
103
97
 
104
98
  #### Returns
105
99
 
106
- - **`recordPatches`**: Returns `Patches<true>` - Array of JSON patches
107
- - **`create`**: Returns `[T, Patches<true>]` - Tuple of mutated state and patches
100
+ - `Patches` - Array of JSON patches
108
101
 
109
102
  ## Usage Examples
110
103
 
@@ -168,11 +161,12 @@ console.log(patches);
168
161
  // { op: 'replace', path: ['items', 1], value: 10 },
169
162
  // { op: 'remove', path: ['items', 0] },
170
163
  // { op: 'replace', path: ['items', 0], value: 2 },
171
- // { op: 'replace', path: ['items', 1], value: 3 },
172
- // { op: 'replace', path: ['items', 'length'], value: 3 }
164
+ // { op: 'replace', path: ['items', 1], value: 3 }
173
165
  // ]
174
166
  ```
175
167
 
168
+ **Note:** Array length patches are included only when the array shrinks (pop, shift, splice delete operations) to optimize performance. This aligns with mutative's behavior. When the array grows (push, unshift, splice add operations), length patches are omitted as the length change is implied by the add operations themselves.
169
+
176
170
  ### Map Operations
177
171
 
178
172
  ```typescript
@@ -209,72 +203,110 @@ console.log(patches);
209
203
  // ]
210
204
  ```
211
205
 
212
- ### Using `create` (Mutative-compatible API)
206
+ ### Using Options
213
207
 
214
- The `create` function provides the same API as mutative for easy switching:
208
+ For `recordPatches`:
215
209
 
216
210
  ```typescript
217
- import {create} from 'patch-recorder';
211
+ const state = { value: 1 };
218
212
 
219
- const state = { user: { name: 'John' } };
220
213
 
221
- const [nextState, patches] = create(state, (draft) => {
222
- draft.user.name = 'Jane';
214
+ // Compress patches (merge redundant operations) - enabled by default
215
+ const patches = recordPatches(state, (draft) => {
216
+ draft.value = 4;
217
+ draft.value = 5;
218
+ draft.value = 5; // no-op
223
219
  });
224
-
225
- console.log(nextState.user.name); // 'Jane' (mutated in place!)
226
- console.log(nextState === state); // true (same reference - unlike mutative)
220
+ // To disable compression:
221
+ // const patches = recordPatches(state, (draft) => { ... }, { compressPatches: false });
227
222
  console.log(patches);
228
- // [{ op: 'replace', path: ['user', 'name'], value: 'Jane' }]
229
- ```
223
+ // [{ op: 'replace', path: ['value'], value: 5 }]
224
+
230
225
 
231
- #### Easy Migration from Mutative
226
+ ### Item ID Tracking
227
+
228
+ When working with arrays, the patch path only tells you the index, not which item was affected. The `getItemId` option allows you to include item IDs in `remove` and `replace` patches, making it easier to track which items changed.
232
229
 
233
230
  ```typescript
234
- // Before (with mutative)
235
- import {create} from 'mutative';
236
- const [newState, patches] = create(state, mutate, {enablePatches: true});
237
- // newState !== state (mutative creates a copy)
238
-
239
- // After (with patch-recorder) - EXACT SAME CODE!
240
- import {create} from 'patch-recorder';
241
- const [nextState, patches] = create(state, mutate, {enablePatches: true});
242
- // nextState === state (patch-recorder mutates in place)
243
- ```
231
+ const state = {
232
+ users: [
233
+ { id: 'user-1', name: 'Alice' },
234
+ { id: 'user-2', name: 'Bob' },
235
+ { id: 'user-3', name: 'Charlie' },
236
+ ]
237
+ };
244
238
 
245
- **No code changes needed** - just change the import! The `enablePatches` option is forced to `true` by default, so it's always enabled.
239
+ const patches = recordPatches(state, (draft) => {
240
+ draft.users.splice(1, 1); // Remove Bob
241
+ }, {
242
+ getItemId: {
243
+ users: (user) => user.id // Extract ID from each user
244
+ }
245
+ });
246
246
 
247
- ### Using Options
247
+ console.log(patches);
248
+ // [{ op: 'remove', path: ['users', 1], id: 'user-2' }]
249
+ // Without getItemId, you'd only know index 1 was removed, not that it was Bob
250
+ ```
248
251
 
249
- For `recordPatches`:
252
+ #### Configuration Structure
253
+
254
+ The `getItemId` option is an object that mirrors your data structure:
250
255
 
251
256
  ```typescript
252
- const state = { value: 1 };
257
+ recordPatches(state, mutate, {
258
+ getItemId: {
259
+ // Top-level arrays
260
+ items: (item) => item.id,
261
+ users: (user) => user.userId,
262
+
263
+ // Nested paths - use nested objects
264
+ app: {
265
+ data: {
266
+ todos: (todo) => todo._id
267
+ }
268
+ },
269
+
270
+ // Maps - same as arrays
271
+ entityMap: (entity) => entity.internalId
272
+ }
273
+ });
274
+ ```
253
275
 
254
- // Use string paths instead of arrays
255
- const patches = recordPatches(state, (draft) => {
256
- draft.value = 3;
257
- }, { pathAsArray: false });
258
- console.log(patches);
259
- // [{ op: 'replace', path: '/value', value: 3 }]
276
+ #### Works with Maps and Sets too
277
+
278
+ ```typescript
279
+ const state = {
280
+ entityMap: new Map([
281
+ ['key1', { internalId: 'entity-1', data: 'value1' }],
282
+ ]),
283
+ itemSet: new Set([
284
+ { id: 'set-item-1', value: 1 }
285
+ ])
286
+ };
260
287
 
261
- // Compress patches (merge redundant operations) - enabled by default
262
288
  const patches = recordPatches(state, (draft) => {
263
- draft.value = 4;
264
- draft.value = 5;
265
- draft.value = 5; // no-op
289
+ draft.entityMap.delete('key1');
290
+ }, {
291
+ getItemId: {
292
+ entityMap: (entity) => entity.internalId
293
+ }
266
294
  });
267
- // To disable compression:
268
- // const patches = recordPatches(state, (draft) => { ... }, { compressPatches: false });
269
- console.log(patches);
270
- // [{ op: 'replace', path: ['value'], value: 5 }]
271
295
 
272
- // For create function, you also have to pass enablePatches (it's always true)
273
- const [nextState, patches] = create(state, (draft) => {
274
- draft.value = 5;
275
- }, { enablePatches: true, pathAsArray: false, compressPatches: true });
296
+ console.log(patches);
297
+ // [{ op: 'remove', path: ['entityMap', 'key1'], id: 'entity-1' }]
276
298
  ```
277
299
 
300
+ #### When IDs are included
301
+
302
+ - **`remove`** patches always include `id` when configured
303
+ - **`replace`** patches include `id` (of the OLD value being replaced)
304
+ - **`add`** patches do NOT include `id` (the value already contains it)
305
+
306
+ #### ID can be undefined/null
307
+
308
+ If the `getItemId` function returns `undefined` or `null`, the `id` field is omitted from the patch. This is useful when some items might not have IDs.
309
+
278
310
  ## Comparison with Mutative
279
311
 
280
312
  | Feature | Mutative | patch-recorder |
@@ -283,27 +315,8 @@ const [nextState, patches] = create(state, (draft) => {
283
315
  | Memory overhead | ❌ Yes (copies) | ✅ No |
284
316
  | Patch accuracy | ✅ Excellent | ✅ Excellent |
285
317
  | Type safety | ✅ Excellent | ✅ Excellent |
286
- | API compatibility | - | ✅ `create()` function provides same API |
287
318
  | Use case | Immutable state | Mutable with tracking |
288
- | Performance | Fast | 2-1000x faster |
289
-
290
- ### Easy Migration
291
-
292
- ```typescript
293
- // Switching from mutative to patch-recorder is simple:
294
- // Just change the import - no other changes needed!
295
-
296
- // Before
297
- import {create} from 'mutative';
298
- const [nextState, patches] = create(state, mutate, {enablePatches: true});
299
-
300
- // After - EXACT SAME CODE!
301
- import {create} from 'patch-recorder';
302
- const [nextState, patches] = create(state, mutate, {enablePatches: true});
303
-
304
- // Note: patch-recorder mutates in place, so nextState === state
305
- // If you rely on immutability, you may need to clone before mutation
306
- ```
319
+ | Performance | Fast | 1.1-650x faster |
307
320
 
308
321
  ### When to Use patch-recorder
309
322
 
@@ -326,12 +339,12 @@ patch-recorder provides substantial performance improvements over mutative while
326
339
 
327
340
  | Operation | Mutative | patch-recorder | Speedup |
328
341
  |-----------|----------|----------------|---------|
329
- | Simple object mutation | 0.0272ms | 0.0110ms | **2.48x** |
330
- | Medium nested object | 0.0268ms | 0.0114ms | **2.35x** |
331
- | Large nested object | 0.0094ms | 0.0040ms | **2.38x** |
332
- | Array push (100k elements) | 3.277ms | 1.155ms | **2.84x** |
333
- | Array index (100k elements) | 2.966ms | 0.004ms | **826x** |
334
- | Map operations (100k entries) | 11.384ms | 0.011ms | **1,067x** |
342
+ | Simple object mutation | 0.0215ms | 0.0148ms | **1.45x** |
343
+ | Medium nested object | 0.0254ms | 0.0221ms | **1.15x** |
344
+ | Large nested object | 0.0088ms | 0.0078ms | **1.13x** |
345
+ | Array push (100k elements) | 3.0311ms | 0.6809ms | **4.45x** |
346
+ | Array index (100k elements) | 2.6097ms | 0.0069ms | **380x** |
347
+ | Map operations (100k entries) | 10.4033ms | 0.0160ms | **650x** |
335
348
 
336
349
  **Memory Usage:**
337
350
  - **Mutative**: Creates copies (memory overhead proportional to state size)
@@ -341,17 +354,17 @@ patch-recorder provides substantial performance improvements over mutative while
341
354
 
342
355
  The benchmark results reveal patch-recorder's massive advantage for operations that would require copying large data structures:
343
356
 
344
- - **Object mutations** (2.35-2.48x faster) - Consistent speedups due to simpler proxy overhead
345
- - **Array push** (2.84x faster) - Avoids copying entire arrays on mutation
346
- - **Array index assignment** (826x faster) - **Massive speedup** by not copying 100k-element arrays
347
- - **Map operations** (1,067x faster) - **Incredible speedup** by not copying 100k-entry Maps
357
+ - **Object mutations** (1.13-1.45x faster) - Consistent speedups due to simpler proxy overhead
358
+ - **Array push** (4.45x faster) - Avoids copying entire arrays on mutation
359
+ - **Array index assignment** (380x faster) - **Massive speedup** by not copying 100k-element arrays
360
+ - **Map operations** (650x faster) - **Incredible speedup** by not copying 100k-entry Maps
348
361
 
349
362
  **Why the dramatic differences?**
350
363
  - patch-recorder mutates in place, so array index assignment and Map operations don't require copying
351
364
  - mutative's copy-on-write approach is elegant but incurs significant overhead for large collections
352
365
  - The advantage scales with data size - the larger the collection, the bigger the speedup
353
366
 
354
- **Note on mutative's performance:** Mutative is impressively fast for object mutations and offers excellent immutability guarantees. Its speedups of 2-3x for objects are reasonable trade-offs for immutable state management.
367
+ **Note on mutative's performance:** Mutative is impressively fast for object mutations and offers excellent immutability guarantees. Its speedups of ~1.1-1.5x for objects are reasonable trade-offs for immutable state management.
355
368
 
356
369
  ### Run Benchmarks
357
370
 
package/dist/arrays.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import type { RecorderState } from './types.js';
1
+ import type { NonPrimitive, PatchPath, RecorderState } from './types.js';
2
2
  /**
3
3
  * Handle array method calls and property access
4
4
  */
5
- export declare function handleArrayGet(obj: any[], prop: string, path: (string | number)[], state: RecorderState<any>): any;
5
+ export declare function handleArrayGet(array: unknown[], prop: string, path: PatchPath, state: RecorderState<NonPrimitive>): any;
6
6
  //# sourceMappingURL=arrays.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"arrays.d.ts","sourceRoot":"","sources":["../src/arrays.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,YAAY,CAAC;AAK9C;;GAEG;AACH,wBAAgB,cAAc,CAC7B,GAAG,EAAE,GAAG,EAAE,EACV,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,EACzB,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,GACvB,GAAG,CA2DL"}
1
+ {"version":3,"file":"arrays.d.ts","sourceRoot":"","sources":["../src/arrays.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,YAAY,EAAE,SAAS,EAAE,aAAa,EAAC,MAAM,YAAY,CAAC;AA4BvE;;GAEG;AACH,wBAAgB,cAAc,CAC7B,KAAK,EAAE,OAAO,EAAE,EAChB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,SAAS,EACf,KAAK,EAAE,aAAa,CAAC,YAAY,CAAC,GAChC,GAAG,CA4CL"}
package/dist/arrays.js CHANGED
@@ -1,49 +1,56 @@
1
1
  import { generateAddPatch, generateDeletePatch, generateReplacePatch } from './patches.js';
2
2
  import { createProxy } from './proxy.js';
3
+ // Module-level Sets for O(1) lookup instead of O(n) array includes
4
+ const MUTATING_METHODS = new Set(['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse']);
5
+ const NON_MUTATING_METHODS = new Set([
6
+ 'map',
7
+ 'filter',
8
+ 'reduce',
9
+ 'reduceRight',
10
+ 'forEach',
11
+ 'find',
12
+ 'findIndex',
13
+ 'some',
14
+ 'every',
15
+ 'includes',
16
+ 'indexOf',
17
+ 'lastIndexOf',
18
+ 'slice',
19
+ 'concat',
20
+ 'join',
21
+ 'flat',
22
+ 'flatMap',
23
+ 'at',
24
+ ]);
3
25
  /**
4
26
  * Handle array method calls and property access
5
27
  */
6
- export function handleArrayGet(obj, prop, path, state) {
28
+ export function handleArrayGet(array, prop, path, state) {
7
29
  // Mutating methods
8
- const mutatingMethods = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'];
9
- if (mutatingMethods.includes(prop)) {
30
+ if (MUTATING_METHODS.has(prop)) {
10
31
  return (...args) => {
11
- const oldValue = [...obj]; // Snapshot before mutation
12
- const result = Array.prototype[prop].apply(obj, args);
32
+ // Optimized: only copy what's needed for each method
33
+ const oldLength = array.length;
34
+ let oldValue = null;
35
+ // Only create full copy for sort/reverse which need the entire old array
36
+ if (prop === 'sort' || prop === 'reverse') {
37
+ oldValue = [...array];
38
+ }
39
+ const result = Array.prototype[prop].apply(array, args);
13
40
  // Generate patches based on the method
14
- generateArrayPatches(state, obj, prop, args, result, path, oldValue);
41
+ generateArrayPatches(state, array, prop, args, result, path, oldValue, oldLength);
15
42
  return result;
16
43
  };
17
44
  }
18
45
  // Non-mutating methods - just return them bound to the array
19
- const nonMutatingMethods = [
20
- 'map',
21
- 'filter',
22
- 'reduce',
23
- 'reduceRight',
24
- 'forEach',
25
- 'find',
26
- 'findIndex',
27
- 'some',
28
- 'every',
29
- 'includes',
30
- 'indexOf',
31
- 'lastIndexOf',
32
- 'slice',
33
- 'concat',
34
- 'join',
35
- 'flat',
36
- 'flatMap',
37
- 'at',
38
- ];
39
- if (nonMutatingMethods.includes(prop)) {
40
- return Array.prototype[prop].bind(obj);
46
+ if (NON_MUTATING_METHODS.has(prop)) {
47
+ return Array.prototype[prop].bind(array);
41
48
  }
42
49
  // Property access
43
50
  if (prop === 'length') {
44
- return obj.length;
51
+ return array.length;
45
52
  }
46
- const value = obj[prop];
53
+ const value = array[prop];
47
54
  // For numeric properties (array indices), check if the value is an object/array
48
55
  // If so, return a proxy to enable nested mutation tracking
49
56
  if (!isNaN(Number(prop)) && typeof value === 'object' && value !== null) {
@@ -57,85 +64,70 @@ export function handleArrayGet(obj, prop, path, state) {
57
64
  /**
58
65
  * Generate patches for array mutations
59
66
  */
60
- function generateArrayPatches(state, obj, method, args, result, path, oldValue) {
67
+ function generateArrayPatches(state, array, method, args, result, path, oldArray, oldLength) {
61
68
  switch (method) {
62
69
  case 'push': {
63
70
  // Generate add patches for each new element
64
- const startIndex = oldValue.length;
71
+ // oldLength is the starting index before push
65
72
  args.forEach((value, i) => {
66
- const index = startIndex + i;
73
+ const index = oldLength + i;
67
74
  generateAddPatch(state, [...path, index], value);
68
75
  });
69
- // Generate length patch if option is enabled
70
- if (state.options.arrayLengthAssignment !== false) {
71
- generateReplacePatch(state, [...path, 'length'], obj.length);
72
- }
76
+ // No length patch when array grows (aligned with mutative)
73
77
  break;
74
78
  }
75
79
  case 'pop': {
76
- // Generate remove patch for the removed element
77
- const removedIndex = oldValue.length - 1;
78
- generateDeletePatch(state, [...path, removedIndex], result);
79
- // Generate length patch if option is enabled
80
80
  if (state.options.arrayLengthAssignment !== false) {
81
- generateReplacePatch(state, [...path, 'length'], obj.length);
81
+ // Generate length replace patch (mutative uses this instead of remove)
82
+ generateReplacePatch(state, [...path, 'length'], array.length, oldLength);
83
+ }
84
+ else {
85
+ // When arrayLengthAssignment is false, generate remove patch for last element
86
+ generateDeletePatch(state, [...path, oldLength - 1], result);
82
87
  }
83
88
  break;
84
89
  }
85
90
  case 'shift': {
86
- // Generate remove patch for the removed element
91
+ // Remove first element (shifted elements are handled automatically by JSON Patch spec)
92
+ // We don't have oldValue here, but the result of shift() is the removed element
87
93
  generateDeletePatch(state, [...path, 0], result);
88
- // Shift is complex - we need to update all remaining elements
89
- // Update all shifted elements (after the shift, each element moves to index - 1)
90
- for (let i = 0; i < obj.length; i++) {
91
- generateReplacePatch(state, [...path, i], oldValue[i + 1]);
92
- }
93
- // Generate length patch if option is enabled
94
- if (state.options.arrayLengthAssignment !== false) {
95
- generateReplacePatch(state, [...path, 'length'], obj.length);
96
- }
97
94
  break;
98
95
  }
99
96
  case 'unshift': {
100
- // Add new elements at the beginning
97
+ // Add new elements at the beginning (shifted elements are handled automatically by JSON Patch spec)
101
98
  args.forEach((value, i) => {
102
99
  generateAddPatch(state, [...path, i], value);
103
100
  });
104
- // Update all existing elements
105
- for (let i = 0; i < oldValue.length; i++) {
106
- generateReplacePatch(state, [...path, i + args.length], oldValue[i]);
107
- }
108
- // Generate length patch if option is enabled
109
- if (state.options.arrayLengthAssignment !== false) {
110
- generateReplacePatch(state, [...path, 'length'], obj.length);
111
- }
112
101
  break;
113
102
  }
114
103
  case 'splice': {
115
- const [start, deleteCount, ...addItems] = args;
116
- // Generate remove patches for deleted items
117
- for (let i = 0; i < deleteCount; i++) {
118
- generateDeletePatch(state, [...path, start], oldValue[start]);
104
+ const [start, deleteCount = 0, ...addItems] = args;
105
+ const actualStart = start < 0 ? Math.max(oldLength + start, 0) : Math.min(start, oldLength);
106
+ const actualDeleteCount = Math.min(deleteCount, oldLength - actualStart);
107
+ const minCount = Math.min(actualDeleteCount, addItems.length);
108
+ // For splice, we need the old values for delete operations
109
+ // Since we don't have oldValue, we need to track what was deleted
110
+ // The result of splice() is the array of deleted elements
111
+ const deletedElements = result;
112
+ // First minCount elements: replace (overlap between add and delete)
113
+ for (let i = 0; i < minCount; i++) {
114
+ generateReplacePatch(state, [...path, actualStart + i], addItems[i], deletedElements[i]);
119
115
  }
120
- // Generate add patches for new items
121
- addItems.forEach((item, i) => {
122
- generateAddPatch(state, [...path, start + i], item);
123
- });
124
- // If there are both deletions and additions, update the shifted elements
125
- const itemsToShift = oldValue.length - start - deleteCount;
126
- for (let i = 0; i < itemsToShift; i++) {
127
- generateReplacePatch(state, [...path, start + addItems.length + i], oldValue[start + deleteCount + i]);
116
+ // Remaining add items: add
117
+ for (let i = minCount; i < addItems.length; i++) {
118
+ generateAddPatch(state, [...path, actualStart + i], addItems[i]);
128
119
  }
129
- // Generate length patch if option is enabled
130
- if (state.options.arrayLengthAssignment !== false) {
131
- generateReplacePatch(state, [...path, 'length'], obj.length);
120
+ // Remaining delete items: remove (generate in reverse order)
121
+ for (let i = actualDeleteCount - 1; i >= minCount; i--) {
122
+ generateDeletePatch(state, [...path, actualStart + i], deletedElements[i]);
132
123
  }
133
124
  break;
134
125
  }
135
126
  case 'sort':
136
127
  case 'reverse': {
137
128
  // These reorder the entire array - generate full replace
138
- generateReplacePatch(state, path, [...obj]);
129
+ // oldValue contains the array before the mutation
130
+ generateReplacePatch(state, path, array, oldArray);
139
131
  break;
140
132
  }
141
133
  }
@@ -1 +1 @@
1
- {"version":3,"file":"arrays.js","sourceRoot":"","sources":["../src/arrays.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"arrays.js","sourceRoot":"","sources":["../src/arrays.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -16,29 +16,6 @@ import type { NonPrimitive, Draft, RecordPatchesOptions, Patches } from './types
16
16
  * console.log(state.user.name); // 'Jane' (mutated in place!)
17
17
  * console.log(patches); // [{ op: 'replace', path: ['user', 'name'], value: 'Jane' }]
18
18
  */
19
- export declare function recordPatches<T extends NonPrimitive>(state: T, mutate: (state: Draft<T>) => void, options?: RecordPatchesOptions): Patches<true>;
20
- /**
21
- * Mutative-compatible API for easy switching between mutative and patch-recorder.
22
- * Returns [state, patches] tuple like mutative does.
23
- *
24
- * Unlike mutative, this mutates the original object in place (state === originalState).
25
- * The returned state is the same reference as the input state for API compatibility.
26
- *
27
- * @param state - The state to mutate and record patches from
28
- * @param mutate - A function that receives a draft of the state and applies mutations
29
- * @param options - Configuration options (enablePatches is forced but ignored - patches are always returned)
30
- * @returns Tuple [state, patches] where state is the mutated state (same reference as input)
31
- *
32
- * @example
33
- * const state = { user: { name: 'John' } };
34
- * const [nextState, patches] = create(state, (draft) => {
35
- * draft.user.name = 'Jane';
36
- * }, {enabledPatches: true});
37
- * console.log(nextState === state); // true (mutated in place!)
38
- * console.log(patches); // [{ op: 'replace', path: ['user', 'name'], value: 'Jane' }]
39
- */
40
- export declare function create<T extends NonPrimitive>(state: T, mutate: (state: Draft<T>) => void, options?: RecordPatchesOptions & {
41
- enablePatches: true;
42
- }): [T, Patches<true>];
19
+ export declare function recordPatches<T extends NonPrimitive, PatchesOption extends RecordPatchesOptions = {}>(state: T, mutate: (state: Draft<T>) => void, options?: PatchesOption): Patches;
43
20
  export type { NonPrimitive, Draft, RecordPatchesOptions, Patches, Patch, Operation, } from './types.js';
44
21
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACX,YAAY,EACZ,KAAK,EACL,oBAAoB,EACpB,OAAO,EAGP,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,YAAY,EACnD,KAAK,EAAE,CAAC,EACR,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,EACjC,OAAO,GAAE,oBAAyB,GAChC,OAAO,CAAC,IAAI,CAAC,CA4Bf;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,YAAY,EAC5C,KAAK,EAAE,CAAC,EACR,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,EACjC,OAAO,GAAE,oBAAoB,GAAG;IAAC,aAAa,EAAE,IAAI,CAAA;CAAyB,GAC3E,CAAC,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAKpB;AAGD,YAAY,EACX,YAAY,EACZ,KAAK,EACL,oBAAoB,EACpB,OAAO,EACP,KAAK,EACL,SAAS,GACT,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,YAAY,EAAE,KAAK,EAAE,oBAAoB,EAAE,OAAO,EAAC,MAAM,YAAY,CAAC;AAEnF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAC5B,CAAC,SAAS,YAAY,EACtB,aAAa,SAAS,oBAAoB,GAAG,EAAE,EAC9C,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAuB/E;AAGD,YAAY,EACX,YAAY,EACZ,KAAK,EACL,oBAAoB,EACpB,OAAO,EACP,KAAK,EACL,SAAS,GACT,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -17,54 +17,24 @@ import { compressPatches } from './optimizer.js';
17
17
  * console.log(state.user.name); // 'Jane' (mutated in place!)
18
18
  * console.log(patches); // [{ op: 'replace', path: ['user', 'name'], value: 'Jane' }]
19
19
  */
20
- export function recordPatches(state, mutate, options = {}) {
21
- const internalPatchesOptions = {
22
- pathAsArray: options.pathAsArray ?? true,
23
- arrayLengthAssignment: options.arrayLengthAssignment ?? true,
24
- };
20
+ export function recordPatches(state, mutate, options) {
25
21
  const recorderState = {
26
- original: state,
22
+ state,
27
23
  patches: [],
28
24
  basePath: [],
29
25
  options: {
30
26
  ...options,
31
- internalPatchesOptions,
32
27
  },
28
+ proxyCache: new WeakMap(),
33
29
  };
34
30
  // Create proxy
35
31
  const proxy = createProxy(state, [], recorderState);
36
32
  // Apply mutations
37
33
  mutate(proxy);
38
34
  // Return patches (optionally compressed)
39
- if (options.compressPatches !== false) {
35
+ if (options?.compressPatches !== false) {
40
36
  return compressPatches(recorderState.patches);
41
37
  }
42
38
  return recorderState.patches;
43
39
  }
44
- /**
45
- * Mutative-compatible API for easy switching between mutative and patch-recorder.
46
- * Returns [state, patches] tuple like mutative does.
47
- *
48
- * Unlike mutative, this mutates the original object in place (state === originalState).
49
- * The returned state is the same reference as the input state for API compatibility.
50
- *
51
- * @param state - The state to mutate and record patches from
52
- * @param mutate - A function that receives a draft of the state and applies mutations
53
- * @param options - Configuration options (enablePatches is forced but ignored - patches are always returned)
54
- * @returns Tuple [state, patches] where state is the mutated state (same reference as input)
55
- *
56
- * @example
57
- * const state = { user: { name: 'John' } };
58
- * const [nextState, patches] = create(state, (draft) => {
59
- * draft.user.name = 'Jane';
60
- * }, {enabledPatches: true});
61
- * console.log(nextState === state); // true (mutated in place!)
62
- * console.log(patches); // [{ op: 'replace', path: ['user', 'name'], value: 'Jane' }]
63
- */
64
- export function create(state, mutate, options = { enablePatches: true }) {
65
- // Extract enablePatches but ignore it (patches are always returned)
66
- const { enablePatches, ...recordPatchesOptions } = options;
67
- const patches = recordPatches(state, mutate, recordPatchesOptions);
68
- return [state, patches];
69
- }
70
40
  //# sourceMappingURL=index.js.map