patch-recorder 0.0.0 → 0.0.1
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 +97 -33
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +28 -2
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +33 -2
- package/src/types.ts +2 -2
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
- ✅ **Accurate patches** - JSON Patch (RFC 6902) compliant
|
|
10
10
|
- ✅ **Type safety** - Full TypeScript support
|
|
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
14
|
|
|
15
15
|
## Installation
|
|
@@ -55,9 +55,9 @@ Unlike mutative or immer, **patch-recorder mutates the original object in place*
|
|
|
55
55
|
- Perfect for scenarios where you need both mutation tracking AND direct object manipulation
|
|
56
56
|
|
|
57
57
|
**Performance:**
|
|
58
|
-
-
|
|
59
|
-
-
|
|
60
|
-
-
|
|
58
|
+
- Substantially faster than mutative (2x to 1,000x depending on operation)
|
|
59
|
+
- Especially dramatic speedups for array index and Map operations
|
|
60
|
+
- Consistent performance improvements across all data types
|
|
61
61
|
|
|
62
62
|
```typescript
|
|
63
63
|
// With patch-recorder
|
|
@@ -76,7 +76,15 @@ const patches = recordPatches(state, (draft) => {
|
|
|
76
76
|
|
|
77
77
|
Records JSON patches from mutations applied to the state.
|
|
78
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
|
+
**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
|
+
|
|
85
|
+
**Note:** The `enablePatches` option is forced to `true` by default for full mutative compatibility (patches are always returned).
|
|
86
|
+
|
|
87
|
+
#### Parameters (both functions)
|
|
80
88
|
|
|
81
89
|
- **`state`** (`T extends NonPrimitive`): The state object to mutate and record patches from
|
|
82
90
|
- **`mutate`** `(state: Draft<T>) => void`: Callback function that performs mutations on the draft
|
|
@@ -84,32 +92,25 @@ Records JSON patches from mutations applied to the state.
|
|
|
84
92
|
|
|
85
93
|
#### Options
|
|
86
94
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
* Include array length in patches (default: true)
|
|
96
|
-
*/
|
|
97
|
-
arrayLengthAssignment?: boolean;
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Optimize patches by merging redundant operations (default: false)
|
|
101
|
-
*/
|
|
102
|
-
optimize?: boolean;
|
|
103
|
-
}
|
|
104
|
-
```
|
|
95
|
+
For `recordPatches`:
|
|
96
|
+
|
|
97
|
+
- **`pathAsArray`** (boolean, default: `true`) - Return paths as arrays or strings
|
|
98
|
+
- **`arrayLengthAssignment`** (boolean, default: `true`) - Include array length in patches
|
|
99
|
+
- **`compressPatches`** (boolean, default: `true`) - Compress patches by merging redundant operations
|
|
100
|
+
|
|
101
|
+
For `create` (additional options for mutative compatibility):
|
|
102
|
+
- **`enablePatches`** (boolean, default: `true`) - Always true, patches are always returned
|
|
105
103
|
|
|
106
104
|
#### Returns
|
|
107
105
|
|
|
108
|
-
`Patches<true>` - Array of JSON patches
|
|
106
|
+
- **`recordPatches`**: Returns `Patches<true>` - Array of JSON patches
|
|
107
|
+
- **`create`**: Returns `[T, Patches<true>]` - Tuple of mutated state and patches
|
|
109
108
|
|
|
110
109
|
## Usage Examples
|
|
111
110
|
|
|
112
|
-
###
|
|
111
|
+
### Using `recordPatches`
|
|
112
|
+
|
|
113
|
+
#### Basic Object Mutations
|
|
113
114
|
|
|
114
115
|
```typescript
|
|
115
116
|
const state = { count: 0, name: 'test' };
|
|
@@ -208,26 +209,70 @@ console.log(patches);
|
|
|
208
209
|
// ]
|
|
209
210
|
```
|
|
210
211
|
|
|
212
|
+
### Using `create` (Mutative-compatible API)
|
|
213
|
+
|
|
214
|
+
The `create` function provides the same API as mutative for easy switching:
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
import {create} from 'patch-recorder';
|
|
218
|
+
|
|
219
|
+
const state = { user: { name: 'John' } };
|
|
220
|
+
|
|
221
|
+
const [nextState, patches] = create(state, (draft) => {
|
|
222
|
+
draft.user.name = 'Jane';
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
console.log(nextState.user.name); // 'Jane' (mutated in place!)
|
|
226
|
+
console.log(nextState === state); // true (same reference - unlike mutative)
|
|
227
|
+
console.log(patches);
|
|
228
|
+
// [{ op: 'replace', path: ['user', 'name'], value: 'Jane' }]
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
#### Easy Migration from Mutative
|
|
232
|
+
|
|
233
|
+
```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
|
+
```
|
|
244
|
+
|
|
245
|
+
**No code changes needed** - just change the import! The `enablePatches` option is forced to `true` by default, so it's always enabled.
|
|
246
|
+
|
|
211
247
|
### Using Options
|
|
212
248
|
|
|
249
|
+
For `recordPatches`:
|
|
250
|
+
|
|
213
251
|
```typescript
|
|
214
252
|
const state = { value: 1 };
|
|
215
253
|
|
|
216
254
|
// Use string paths instead of arrays
|
|
217
|
-
const
|
|
255
|
+
const patches = recordPatches(state, (draft) => {
|
|
218
256
|
draft.value = 3;
|
|
219
257
|
}, { pathAsArray: false });
|
|
220
|
-
console.log(
|
|
258
|
+
console.log(patches);
|
|
221
259
|
// [{ op: 'replace', path: '/value', value: 3 }]
|
|
222
260
|
|
|
223
|
-
//
|
|
224
|
-
const
|
|
261
|
+
// Compress patches (merge redundant operations) - enabled by default
|
|
262
|
+
const patches = recordPatches(state, (draft) => {
|
|
225
263
|
draft.value = 4;
|
|
226
264
|
draft.value = 5;
|
|
227
265
|
draft.value = 5; // no-op
|
|
228
|
-
}
|
|
229
|
-
|
|
266
|
+
});
|
|
267
|
+
// To disable compression:
|
|
268
|
+
// const patches = recordPatches(state, (draft) => { ... }, { compressPatches: false });
|
|
269
|
+
console.log(patches);
|
|
230
270
|
// [{ op: 'replace', path: ['value'], value: 5 }]
|
|
271
|
+
|
|
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 });
|
|
231
276
|
```
|
|
232
277
|
|
|
233
278
|
## Comparison with Mutative
|
|
@@ -238,8 +283,27 @@ console.log(patches3);
|
|
|
238
283
|
| Memory overhead | ❌ Yes (copies) | ✅ No |
|
|
239
284
|
| Patch accuracy | ✅ Excellent | ✅ Excellent |
|
|
240
285
|
| Type safety | ✅ Excellent | ✅ Excellent |
|
|
241
|
-
| API
|
|
286
|
+
| API compatibility | - | ✅ `create()` function provides same API |
|
|
242
287
|
| 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
|
+
```
|
|
243
307
|
|
|
244
308
|
### When to Use patch-recorder
|
|
245
309
|
|
|
@@ -326,7 +390,7 @@ npm run benchmark
|
|
|
326
390
|
### Optimization Tips
|
|
327
391
|
|
|
328
392
|
1. **Lazy proxy creation**: Only creates proxies for accessed properties
|
|
329
|
-
2. **Patch compression**: Reduces redundant patches via `
|
|
393
|
+
2. **Patch compression**: Reduces redundant patches via `compressPatches` option
|
|
330
394
|
|
|
331
395
|
## License
|
|
332
396
|
|
package/dist/index.d.ts
CHANGED
|
@@ -17,5 +17,28 @@ import type { NonPrimitive, Draft, RecordPatchesOptions, Patches } from './types
|
|
|
17
17
|
* console.log(patches); // [{ op: 'replace', path: ['user', 'name'], value: 'Jane' }]
|
|
18
18
|
*/
|
|
19
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>];
|
|
20
43
|
export type { NonPrimitive, Draft, RecordPatchesOptions, Patches, Patch, Operation, } from './types.js';
|
|
21
44
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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;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,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"}
|
package/dist/index.js
CHANGED
|
@@ -35,10 +35,36 @@ export function recordPatches(state, mutate, options = {}) {
|
|
|
35
35
|
const proxy = createProxy(state, [], recorderState);
|
|
36
36
|
// Apply mutations
|
|
37
37
|
mutate(proxy);
|
|
38
|
-
// Return patches (optionally
|
|
39
|
-
if (options.
|
|
38
|
+
// Return patches (optionally compressed)
|
|
39
|
+
if (options.compressPatches !== false) {
|
|
40
40
|
return compressPatches(recorderState.patches);
|
|
41
41
|
}
|
|
42
42
|
return recorderState.patches;
|
|
43
43
|
}
|
|
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
|
+
}
|
|
44
70
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,WAAW,EAAC,MAAM,YAAY,CAAC;AACvC,OAAO,EAAC,eAAe,EAAC,MAAM,gBAAgB,CAAC;AAU/C;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,aAAa,CAC5B,KAAQ,EACR,MAAiC,EACjC,UAAgC,EAAE;IAElC,MAAM,sBAAsB,GAAG;QAC9B,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,IAAI;QACxC,qBAAqB,EAAE,OAAO,CAAC,qBAAqB,IAAI,IAAI;KAC5D,CAAC;IAEF,MAAM,aAAa,GAAG;QACrB,QAAQ,EAAE,KAAK;QACf,OAAO,EAAE,EAAE;QACX,QAAQ,EAAE,EAAE;QACZ,OAAO,EAAE;YACR,GAAG,OAAO;YACV,sBAAsB;SACtB;KACD,CAAC;IAEF,eAAe;IACf,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,EAAE,EAAE,EAAE,aAAa,CAAa,CAAC;IAEhE,kBAAkB;IAClB,MAAM,CAAC,KAAK,CAAC,CAAC;IAEd,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,WAAW,EAAC,MAAM,YAAY,CAAC;AACvC,OAAO,EAAC,eAAe,EAAC,MAAM,gBAAgB,CAAC;AAU/C;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,aAAa,CAC5B,KAAQ,EACR,MAAiC,EACjC,UAAgC,EAAE;IAElC,MAAM,sBAAsB,GAAG;QAC9B,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,IAAI;QACxC,qBAAqB,EAAE,OAAO,CAAC,qBAAqB,IAAI,IAAI;KAC5D,CAAC;IAEF,MAAM,aAAa,GAAG;QACrB,QAAQ,EAAE,KAAK;QACf,OAAO,EAAE,EAAE;QACX,QAAQ,EAAE,EAAE;QACZ,OAAO,EAAE;YACR,GAAG,OAAO;YACV,sBAAsB;SACtB;KACD,CAAC;IAEF,eAAe;IACf,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,EAAE,EAAE,EAAE,aAAa,CAAa,CAAC;IAEhE,kBAAkB;IAClB,MAAM,CAAC,KAAK,CAAC,CAAC;IAEd,yCAAyC;IACzC,IAAI,OAAO,CAAC,eAAe,KAAK,KAAK,EAAE,CAAC;QACvC,OAAO,eAAe,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC/C,CAAC;IAED,OAAO,aAAa,CAAC,OAAwB,CAAC;AAC/C,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,MAAM,CACrB,KAAQ,EACR,MAAiC,EACjC,UAAwD,EAAC,aAAa,EAAE,IAAI,EAAC;IAE7E,oEAAoE;IACpE,MAAM,EAAC,aAAa,EAAE,GAAG,oBAAoB,EAAC,GAAG,OAAO,CAAC;IACzD,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,oBAAoB,CAAC,CAAC;IACnE,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;AACzB,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -39,9 +39,9 @@ export interface RecordPatchesOptions {
|
|
|
39
39
|
*/
|
|
40
40
|
arrayLengthAssignment?: boolean;
|
|
41
41
|
/**
|
|
42
|
-
*
|
|
42
|
+
* Compress patches by merging redundant operations (default: true)
|
|
43
43
|
*/
|
|
44
|
-
|
|
44
|
+
compressPatches?: boolean;
|
|
45
45
|
}
|
|
46
46
|
export type Draft<T> = T;
|
|
47
47
|
export interface RecorderState<T> {
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS;;;;CAIZ,CAAC;AAEX,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,OAAO,SAAS,CAAC,CAAC;AAEjE,MAAM,MAAM,cAAc,GACvB,OAAO,GACP;IACA;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;OAEG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;CAC/B,CAAC;AAEL,MAAM,WAAW,MAAM;IACtB,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,CAAC,EAAE,GAAG,CAAC;CACZ;AAED,MAAM,MAAM,KAAK,CAAC,CAAC,SAAS,cAAc,GAAG,GAAG,IAAI,CAAC,SAAS;IAC7D,WAAW,EAAE,KAAK,CAAC;CACnB,GACE,MAAM,GAAG;IACT,IAAI,EAAE,MAAM,CAAC;CACb,GACA,CAAC,SAAS,IAAI,GAAG,MAAM,GACtB,MAAM,GAAG;IACT,IAAI,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;CAC1B,GACA,MAAM,GAAG;IACT,IAAI,EAAE,MAAM,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;CACnC,CAAC;AAEL,MAAM,MAAM,OAAO,CAAC,CAAC,SAAS,cAAc,GAAG,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAEjE,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;AAEnD,MAAM,WAAW,oBAAoB;IACpC;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;OAEG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC;;OAEG;IACH,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS;;;;CAIZ,CAAC;AAEX,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,OAAO,SAAS,CAAC,CAAC;AAEjE,MAAM,MAAM,cAAc,GACvB,OAAO,GACP;IACA;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;OAEG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;CAC/B,CAAC;AAEL,MAAM,WAAW,MAAM;IACtB,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,CAAC,EAAE,GAAG,CAAC;CACZ;AAED,MAAM,MAAM,KAAK,CAAC,CAAC,SAAS,cAAc,GAAG,GAAG,IAAI,CAAC,SAAS;IAC7D,WAAW,EAAE,KAAK,CAAC;CACnB,GACE,MAAM,GAAG;IACT,IAAI,EAAE,MAAM,CAAC;CACb,GACA,CAAC,SAAS,IAAI,GAAG,MAAM,GACtB,MAAM,GAAG;IACT,IAAI,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;CAC1B,GACA,MAAM,GAAG;IACT,IAAI,EAAE,MAAM,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;CACnC,CAAC;AAEL,MAAM,MAAM,OAAO,CAAC,CAAC,SAAS,cAAc,GAAG,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAEjE,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;AAEnD,MAAM,WAAW,oBAAoB;IACpC;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;OAEG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,MAAM,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC;AAEzB,MAAM,WAAW,aAAa,CAAC,CAAC;IAC/B,QAAQ,EAAE,CAAC,CAAC;IACZ,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IACtB,QAAQ,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IAC9B,OAAO,EAAE,oBAAoB,GAAG;QAAC,sBAAsB,EAAE,cAAc,CAAA;KAAC,CAAC;CACzE"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "patch-recorder",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "Record JSON patches (RFC 6902) from mutations applied to objects, arrays, Maps, and Sets via a proxy interface.
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Record JSON patches (RFC 6902) from mutations applied to objects, arrays, Maps, and Sets via a proxy interface.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"patch",
|
|
7
7
|
"mutable",
|
package/src/index.ts
CHANGED
|
@@ -52,14 +52,45 @@ export function recordPatches<T extends NonPrimitive>(
|
|
|
52
52
|
// Apply mutations
|
|
53
53
|
mutate(proxy);
|
|
54
54
|
|
|
55
|
-
// Return patches (optionally
|
|
56
|
-
if (options.
|
|
55
|
+
// Return patches (optionally compressed)
|
|
56
|
+
if (options.compressPatches !== false) {
|
|
57
57
|
return compressPatches(recorderState.patches);
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
return recorderState.patches as Patches<true>;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Mutative-compatible API for easy switching between mutative and patch-recorder.
|
|
65
|
+
* Returns [state, patches] tuple like mutative does.
|
|
66
|
+
*
|
|
67
|
+
* Unlike mutative, this mutates the original object in place (state === originalState).
|
|
68
|
+
* The returned state is the same reference as the input state for API compatibility.
|
|
69
|
+
*
|
|
70
|
+
* @param state - The state to mutate and record patches from
|
|
71
|
+
* @param mutate - A function that receives a draft of the state and applies mutations
|
|
72
|
+
* @param options - Configuration options (enablePatches is forced but ignored - patches are always returned)
|
|
73
|
+
* @returns Tuple [state, patches] where state is the mutated state (same reference as input)
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* const state = { user: { name: 'John' } };
|
|
77
|
+
* const [nextState, patches] = create(state, (draft) => {
|
|
78
|
+
* draft.user.name = 'Jane';
|
|
79
|
+
* }, {enabledPatches: true});
|
|
80
|
+
* console.log(nextState === state); // true (mutated in place!)
|
|
81
|
+
* console.log(patches); // [{ op: 'replace', path: ['user', 'name'], value: 'Jane' }]
|
|
82
|
+
*/
|
|
83
|
+
export function create<T extends NonPrimitive>(
|
|
84
|
+
state: T,
|
|
85
|
+
mutate: (state: Draft<T>) => void,
|
|
86
|
+
options: RecordPatchesOptions & {enablePatches: true} = {enablePatches: true},
|
|
87
|
+
): [T, Patches<true>] {
|
|
88
|
+
// Extract enablePatches but ignore it (patches are always returned)
|
|
89
|
+
const {enablePatches, ...recordPatchesOptions} = options;
|
|
90
|
+
const patches = recordPatches(state, mutate, recordPatchesOptions);
|
|
91
|
+
return [state, patches];
|
|
92
|
+
}
|
|
93
|
+
|
|
63
94
|
// Re-export types
|
|
64
95
|
export type {
|
|
65
96
|
NonPrimitive,
|
package/src/types.ts
CHANGED
|
@@ -52,9 +52,9 @@ export interface RecordPatchesOptions {
|
|
|
52
52
|
*/
|
|
53
53
|
arrayLengthAssignment?: boolean;
|
|
54
54
|
/**
|
|
55
|
-
*
|
|
55
|
+
* Compress patches by merging redundant operations (default: true)
|
|
56
56
|
*/
|
|
57
|
-
|
|
57
|
+
compressPatches?: boolean;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
export type Draft<T> = T;
|