patch-recorder 0.2.1 → 0.3.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
@@ -90,9 +90,9 @@ Records JSON patches from mutations applied to the state.
90
90
  #### Options
91
91
 
92
92
 
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.
93
+ - **`arrayLengthAssignment`** (boolean, default: `true`) - When `true`, includes length patches when array shrinks (pop, shift, splice delete). When `false`, omits length patches entirely. Must be `false` when using `getItemId`. Aligned with mutative's behavior.
94
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))
95
+ - **`getItemId`** (object, optional) - Configuration for extracting item IDs. **Requires `arrayLengthAssignment: false`**. (see [Item ID Tracking](#item-id-tracking))
96
96
 
97
97
 
98
98
  #### Returns
@@ -227,6 +227,10 @@ console.log(patches);
227
227
 
228
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.
229
229
 
230
+ **Important:** `getItemId` requires `arrayLengthAssignment: false` because length patches (e.g., `{ op: 'replace', path: ['arr', 'length'], value: 2 }`) cannot include individual item IDs. This is enforced at both compile time and runtime.
231
+
232
+ **Note:** When `arrayLengthAssignment: false`, direct array length assignment (`arr.length = N`) generates individual remove/add patches instead of a length patch, allowing proper item ID tracking.
233
+
230
234
  ```typescript
231
235
  const state = {
232
236
  users: [
@@ -239,6 +243,7 @@ const state = {
239
243
  const patches = recordPatches(state, (state) => {
240
244
  state.users.splice(1, 1); // Remove Bob
241
245
  }, {
246
+ arrayLengthAssignment: false, // Required when using getItemId
242
247
  getItemId: {
243
248
  users: (user) => user.id // Extract ID from each user
244
249
  }
@@ -255,6 +260,7 @@ The `getItemId` option is an object that mirrors your data structure:
255
260
 
256
261
  ```typescript
257
262
  recordPatches(state, mutate, {
263
+ arrayLengthAssignment: false, // Required when using getItemId
258
264
  getItemId: {
259
265
  // Top-level arrays
260
266
  items: (item) => item.id,
@@ -288,6 +294,7 @@ const state = {
288
294
  const patches = recordPatches(state, (state) => {
289
295
  state.entityMap.delete('key1');
290
296
  }, {
297
+ arrayLengthAssignment: false, // Required when using getItemId
291
298
  getItemId: {
292
299
  entityMap: (entity) => entity.internalId
293
300
  }
package/dist/arrays.js CHANGED
@@ -77,13 +77,16 @@ function generateArrayPatches(state, array, method, args, result, path, oldArray
77
77
  break;
78
78
  }
79
79
  case 'pop': {
80
- if (state.options.arrayLengthAssignment !== false) {
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);
80
+ // Only generate patch if length actually changed (pop on empty array does nothing)
81
+ if (array.length !== oldLength) {
82
+ if (state.options.arrayLengthAssignment !== false) {
83
+ // Generate length replace patch (mutative uses this instead of remove)
84
+ generateReplacePatch(state, [...path, 'length'], array.length, oldLength);
85
+ }
86
+ else {
87
+ // When arrayLengthAssignment is false, generate remove patch for last element
88
+ generateDeletePatch(state, [...path, oldLength - 1], result);
89
+ }
87
90
  }
88
91
  break;
89
92
  }
@@ -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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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,YAAY,EAAE,oBAAoB,EAAE,OAAO,EAAC,MAAM,YAAY,CAAC;AAE5E;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAC5B,CAAC,SAAS,YAAY,EACtB,aAAa,SAAS,oBAAoB,GAAG,EAAE,EAC9C,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAuBxE;AAGD,YAAY,EAAC,YAAY,EAAE,oBAAoB,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAC,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,YAAY,EAAE,oBAAoB,EAAE,OAAO,EAAC,MAAM,YAAY,CAAC;AAE5E;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAC5B,CAAC,SAAS,YAAY,EACtB,aAAa,SAAS,oBAAoB,GAAG,EAAE,EAC9C,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CA6BxE;AAGD,YAAY,EAAC,YAAY,EAAE,oBAAoB,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAC,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -18,13 +18,16 @@ import { compressPatches } from './optimizer.js';
18
18
  * console.log(patches); // [{ op: 'replace', path: ['user', 'name'], value: 'Jane' }]
19
19
  */
20
20
  export function recordPatches(state, mutate, options) {
21
+ // Runtime validation: getItemId requires arrayLengthAssignment: false
22
+ if (options?.getItemId && options?.arrayLengthAssignment !== false) {
23
+ throw new Error('getItemId requires arrayLengthAssignment: false. ' +
24
+ 'Length patches cannot include individual item IDs.');
25
+ }
21
26
  const recorderState = {
22
27
  state,
23
28
  patches: [],
24
29
  basePath: [],
25
- options: {
26
- ...options,
27
- },
30
+ options: options ?? {},
28
31
  proxyCache: new WeakMap(),
29
32
  };
30
33
  // Create proxy
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;AAG/C;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,aAAa,CAG3B,KAAQ,EAAE,MAA0B,EAAE,OAAuB;IAC9D,MAAM,aAAa,GAAG;QACrB,KAAK;QACL,OAAO,EAAE,EAAE;QACX,QAAQ,EAAE,EAAE;QACZ,OAAO,EAAE;YACR,GAAG,OAAO;SACV;QACD,UAAU,EAAE,IAAI,OAAO,EAAE;KACzB,CAAC;IAEF,eAAe;IACf,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,EAAE,EAAE,EAAE,aAAa,CAAM,CAAC;IAEzD,kBAAkB;IAClB,MAAM,CAAC,KAAK,CAAC,CAAC;IAEd,yCAAyC;IACzC,IAAI,OAAO,EAAE,eAAe,KAAK,KAAK,EAAE,CAAC;QACxC,OAAO,eAAe,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC/C,CAAC;IAED,OAAO,aAAa,CAAC,OAAkB,CAAC;AACzC,CAAC"}
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;AAG/C;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,aAAa,CAG3B,KAAQ,EAAE,MAA0B,EAAE,OAAuB;IAC9D,sEAAsE;IACtE,IAAI,OAAO,EAAE,SAAS,IAAI,OAAO,EAAE,qBAAqB,KAAK,KAAK,EAAE,CAAC;QACpE,MAAM,IAAI,KAAK,CACd,mDAAmD;YAClD,oDAAoD,CACrD,CAAC;IACH,CAAC;IAED,MAAM,aAAa,GAAG;QACrB,KAAK;QACL,OAAO,EAAE,EAAE;QACX,QAAQ,EAAE,EAAE;QACZ,OAAO,EAAE,OAAO,IAAI,EAAE;QACtB,UAAU,EAAE,IAAI,OAAO,EAAE;KACzB,CAAC;IAEF,eAAe;IACf,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,EAAE,EAAE,EAAE,aAAa,CAAM,CAAC;IAEzD,kBAAkB;IAClB,MAAM,CAAC,KAAK,CAAC,CAAC;IAEd,yCAAyC;IACzC,IAAI,OAAO,EAAE,eAAe,KAAK,KAAK,EAAE,CAAC;QACxC,OAAO,eAAe,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC/C,CAAC;IAED,OAAO,aAAa,CAAC,OAAkB,CAAC;AACzC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"patches.d.ts","sourceRoot":"","sources":["../src/patches.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,YAAY,EAAS,SAAS,EAAE,aAAa,EAAC,MAAM,YAAY,CAAC;AAI9E;;GAEG;AACH,wBAAgB,gBAAgB,CAC/B,KAAK,EAAE,aAAa,CAAC,YAAY,CAAC,EAClC,IAAI,EAAE,SAAS,EACf,QAAQ,EAAE,OAAO,EACjB,QAAQ,EAAE,OAAO,QAkBjB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAClC,KAAK,EAAE,aAAa,CAAC,YAAY,CAAC,EAClC,IAAI,EAAE,SAAS,EACf,QAAQ,EAAE,OAAO,QAiBjB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,QAOtF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CACnC,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,EACzB,IAAI,EAAE,SAAS,EACf,KAAK,EAAE,OAAO,EACd,QAAQ,CAAC,EAAE,OAAO,QAkBlB"}
1
+ {"version":3,"file":"patches.d.ts","sourceRoot":"","sources":["../src/patches.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,YAAY,EAAS,SAAS,EAAE,aAAa,EAAC,MAAM,YAAY,CAAC;AAI9E;;GAEG;AACH,wBAAgB,gBAAgB,CAC/B,KAAK,EAAE,aAAa,CAAC,YAAY,CAAC,EAClC,IAAI,EAAE,SAAS,EACf,QAAQ,EAAE,OAAO,EACjB,QAAQ,EAAE,OAAO,QAkBjB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAClC,KAAK,EAAE,aAAa,CAAC,YAAY,CAAC,EAClC,IAAI,EAAE,SAAS,EACf,QAAQ,EAAE,OAAO,QAiBjB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,QAOtF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CACnC,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,EACzB,IAAI,EAAE,SAAS,EACf,KAAK,EAAE,OAAO,EACd,QAAQ,CAAC,EAAE,OAAO,QAuBlB"}
package/dist/patches.js CHANGED
@@ -57,6 +57,10 @@ export function generateReplacePatch(state, path, value, oldValue) {
57
57
  path: path,
58
58
  value: cloneIfNeeded(value),
59
59
  };
60
+ // Include oldValue for array length changes to enable consumers to detect element removal
61
+ if (path.length > 0 && path[path.length - 1] === 'length' && oldValue !== undefined) {
62
+ patch.oldValue = oldValue;
63
+ }
60
64
  // Add id if getItemId is configured for this path
61
65
  const getItemIdFn = findGetItemIdFn(path, state.options.getItemId);
62
66
  if (getItemIdFn && oldValue !== undefined) {
@@ -1 +1 @@
1
- {"version":3,"file":"patches.js","sourceRoot":"","sources":["../src/patches.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,SAAS,EAAC,MAAM,YAAY,CAAC;AACrC,OAAO,EAAC,aAAa,EAAE,eAAe,EAAC,MAAM,YAAY,CAAC;AAE1D;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAC/B,KAAkC,EAClC,IAAe,EACf,QAAiB,EACjB,QAAiB;IAEjB,MAAM,KAAK,GAAQ;QAClB,EAAE,EAAE,SAAS,CAAC,OAAO;QACrB,IAAI;QACJ,KAAK,EAAE,aAAa,CAAC,QAAQ,CAAC;KAC9B,CAAC;IAEF,kDAAkD;IAClD,MAAM,WAAW,GAAG,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACnE,IAAI,WAAW,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3C,MAAM,EAAE,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;QACjC,IAAI,EAAE,KAAK,SAAS,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;YACrC,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC;QACf,CAAC;IACF,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAClC,KAAkC,EAClC,IAAe,EACf,QAAiB;IAEjB,MAAM,KAAK,GAAU;QACpB,EAAE,EAAE,SAAS,CAAC,MAAM;QACpB,IAAI,EAAE,IAAI;KACV,CAAC;IAEF,kDAAkD;IAClD,MAAM,WAAW,GAAG,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACnE,IAAI,WAAW,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3C,MAAM,EAAE,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;QACjC,IAAI,EAAE,KAAK,SAAS,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;YACrC,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC;QACf,CAAC;IACF,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAyB,EAAE,IAAe,EAAE,KAAU;IACtF,MAAM,KAAK,GAAU;QACpB,EAAE,EAAE,SAAS,CAAC,GAAG;QACjB,IAAI;QACJ,KAAK,EAAE,aAAa,CAAC,KAAK,CAAC;KAC3B,CAAC;IACF,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CACnC,KAAyB,EACzB,IAAe,EACf,KAAc,EACd,QAAkB;IAElB,MAAM,KAAK,GAAU;QACpB,EAAE,EAAE,SAAS,CAAC,OAAO;QACrB,IAAI,EAAE,IAAI;QACV,KAAK,EAAE,aAAa,CAAC,KAAK,CAAC;KAC3B,CAAC;IAEF,kDAAkD;IAClD,MAAM,WAAW,GAAG,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACnE,IAAI,WAAW,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3C,MAAM,EAAE,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;QACjC,IAAI,EAAE,KAAK,SAAS,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;YACrC,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC;QACf,CAAC;IACF,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC"}
1
+ {"version":3,"file":"patches.js","sourceRoot":"","sources":["../src/patches.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,SAAS,EAAE,aAAa,EAAC,MAAM,YAAY,CAAC;AAOzD,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAC3C,MAAM,EAAE,CAAC,EACT,IAAI,EAAE,SAAS,EACf,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,GACvB,CAAC,CAwIH"}
1
+ {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,SAAS,EAAE,aAAa,EAAC,MAAM,YAAY,CAAC;AAYzD,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAC3C,MAAM,EAAE,CAAC,EACT,IAAI,EAAE,SAAS,EACf,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,GACvB,CAAC,CA8KH"}
package/dist/proxy.js CHANGED
@@ -1,4 +1,4 @@
1
- import { generateSetPatch, generateDeletePatch, generateAddPatch } from './patches.js';
1
+ import { generateSetPatch, generateDeletePatch, generateAddPatch, generateReplacePatch, } from './patches.js';
2
2
  import { isArray, isMap, isSet } from './utils.js';
3
3
  import { handleArrayGet } from './arrays.js';
4
4
  import { handleMapGet } from './maps.js';
@@ -58,12 +58,51 @@ export function createProxy(target, path, state) {
58
58
  if (Object.is(oldValue, value) && (value !== undefined || actuallyHasProperty)) {
59
59
  return true;
60
60
  }
61
+ // Special handling for array length with arrayLengthAssignment: false
62
+ // Must capture removed items BEFORE mutation
63
+ let removedItems = null;
64
+ if (isArrayType && prop === 'length' && state.options.arrayLengthAssignment === false) {
65
+ const arr = obj;
66
+ const newLength = value;
67
+ if (newLength < oldValue) {
68
+ // Capture items that will be removed before mutation
69
+ removedItems = [];
70
+ for (let i = newLength; i < oldValue; i++) {
71
+ removedItems.push(arr[i]);
72
+ }
73
+ }
74
+ }
61
75
  // Mutate original immediately
62
76
  obj[prop] = value;
63
77
  // Generate patch - use pre-mutation property existence check
64
78
  if (!hadProperty) {
65
79
  generateAddPatch(state, propPath, value);
66
80
  }
81
+ else if (isArrayType && prop === 'length') {
82
+ if (state.options.arrayLengthAssignment === false) {
83
+ // When arrayLengthAssignment is false, generate individual remove patches
84
+ // for each removed item (in reverse order)
85
+ const newLength = value;
86
+ if (removedItems) {
87
+ // Array was shrinking - generate remove patches for removed items
88
+ // Iterate in reverse to generate patches from end to start
89
+ for (let i = removedItems.length - 1; i >= 0; i--) {
90
+ const index = newLength + i;
91
+ generateDeletePatch(state, [...path, index], removedItems[i]);
92
+ }
93
+ }
94
+ else if (newLength > oldValue) {
95
+ // Array is growing - generate add patches for new undefined slots
96
+ for (let i = oldValue; i < newLength; i++) {
97
+ generateAddPatch(state, [...path, i], undefined);
98
+ }
99
+ }
100
+ }
101
+ else {
102
+ // Use generateReplacePatch for array length to include oldValue
103
+ generateReplacePatch(state, propPath, value, oldValue);
104
+ }
105
+ }
67
106
  else {
68
107
  generateSetPatch(state, propPath, oldValue, value);
69
108
  }
package/dist/proxy.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -19,6 +19,11 @@ export type Patch = {
19
19
  path: PatchPath;
20
20
  op: PatchOp;
21
21
  value?: any;
22
+ /**
23
+ * Optional previous value for replace operations on array length.
24
+ * Enables consumers to detect how many elements were removed without pre-snapshotting state.
25
+ */
26
+ oldValue?: unknown;
22
27
  /**
23
28
  * Optional ID of the item being removed or replaced.
24
29
  * Populated when getItemId option is configured for the item's parent path.
@@ -27,15 +32,25 @@ export type Patch = {
27
32
  };
28
33
  export type Patches = Patch[];
29
34
  export type NonPrimitive = object | Array<unknown>;
30
- export interface RecordPatchesOptions {
31
- /**
32
- * Include array length in patches (default: true)
33
- */
34
- arrayLengthAssignment?: boolean;
35
+ /**
36
+ * Base options shared by all configurations
37
+ */
38
+ interface BaseRecordPatchesOptions {
35
39
  /**
36
40
  * Compress patches by merging redundant operations (default: true)
37
41
  */
38
42
  compressPatches?: boolean;
43
+ }
44
+ /**
45
+ * Options when using getItemId - requires arrayLengthAssignment to be false
46
+ * because length patches cannot include individual item IDs.
47
+ */
48
+ interface RecordPatchesOptionsWithItemId extends BaseRecordPatchesOptions {
49
+ /**
50
+ * Must be false when using getItemId.
51
+ * Length patches cannot include individual item IDs.
52
+ */
53
+ arrayLengthAssignment: false;
39
54
  /**
40
55
  * Configuration for extracting item IDs for remove/replace patches.
41
56
  * Maps paths to functions that extract IDs from item values.
@@ -43,6 +58,7 @@ export interface RecordPatchesOptions {
43
58
  * @example
44
59
  * ```typescript
45
60
  * recordPatches(state, mutate, {
61
+ * arrayLengthAssignment: false,
46
62
  * getItemId: {
47
63
  * items: (item) => item.id,
48
64
  * users: (user) => user.userId,
@@ -53,8 +69,29 @@ export interface RecordPatchesOptions {
53
69
  * });
54
70
  * ```
55
71
  */
56
- getItemId?: GetItemIdConfig;
72
+ getItemId: GetItemIdConfig;
73
+ }
74
+ /**
75
+ * Options when not using getItemId - arrayLengthAssignment can be any value
76
+ */
77
+ interface RecordPatchesOptionsWithoutItemId extends BaseRecordPatchesOptions {
78
+ /**
79
+ * Include array length in patches (default: true)
80
+ */
81
+ arrayLengthAssignment?: boolean;
82
+ /**
83
+ * Not available unless arrayLengthAssignment is false
84
+ */
85
+ getItemId?: undefined;
57
86
  }
87
+ /**
88
+ * Configuration options for recordPatches.
89
+ *
90
+ * Note: getItemId requires arrayLengthAssignment: false because length patches
91
+ * (e.g., { op: 'replace', path: ['arr', 'length'], value: 2, oldValue: 3 })
92
+ * cannot include the IDs of individual items that were removed.
93
+ */
94
+ export type RecordPatchesOptions = RecordPatchesOptionsWithItemId | RecordPatchesOptionsWithoutItemId;
58
95
  export interface RecorderState<T extends NonPrimitive> {
59
96
  state: T;
60
97
  patches: Patches;
@@ -65,4 +102,5 @@ export interface RecorderState<T extends NonPrimitive> {
65
102
  */
66
103
  proxyCache: WeakMap<object, any>;
67
104
  }
105
+ export {};
68
106
  //# sourceMappingURL=types.d.ts.map
@@ -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;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,EAAE,GAAG,KAAK,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;AAEnF;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC7B,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,GAAG,eAAe,CAAC;CACnD,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,CAAC,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;AAE9D,MAAM,MAAM,KAAK,GAAG;IACnB,IAAI,EAAE,SAAS,CAAC;IAChB,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ;;;OAGG;IACH,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG,KAAK,EAAE,CAAC;AAE9B,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;AAEnD,MAAM,WAAW,oBAAoB;IACpC;;OAEG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;;;;;;;;;;;;OAgBG;IACH,SAAS,CAAC,EAAE,eAAe,CAAC;CAC5B;AAED,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,YAAY;IACpD,KAAK,EAAE,CAAC,CAAC;IACT,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,SAAS,CAAC;IACpB,OAAO,EAAE,oBAAoB,CAAC;IAC9B;;OAEG;IACH,UAAU,EAAE,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CACjC"}
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;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,EAAE,GAAG,KAAK,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;AAEnF;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC7B,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,GAAG,eAAe,CAAC;CACnD,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,CAAC,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;AAE9D,MAAM,MAAM,KAAK,GAAG;IACnB,IAAI,EAAE,SAAS,CAAC;IAChB,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG,KAAK,EAAE,CAAC;AAE9B,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;AAEnD;;GAEG;AACH,UAAU,wBAAwB;IACjC;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;GAGG;AACH,UAAU,8BAA+B,SAAQ,wBAAwB;IACxE;;;OAGG;IACH,qBAAqB,EAAE,KAAK,CAAC;IAC7B;;;;;;;;;;;;;;;;;OAiBG;IACH,SAAS,EAAE,eAAe,CAAC;CAC3B;AAED;;GAEG;AACH,UAAU,iCAAkC,SAAQ,wBAAwB;IAC3E;;OAEG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC;;OAEG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,oBAAoB,GAC7B,8BAA8B,GAC9B,iCAAiC,CAAC;AAErC,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,YAAY;IACpD,KAAK,EAAE,CAAC,CAAC;IACT,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,SAAS,CAAC;IACpB,OAAO,EAAE,oBAAoB,CAAC;IAC9B;;OAEG;IACH,UAAU,EAAE,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CACjC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "patch-recorder",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
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",
package/src/arrays.ts CHANGED
@@ -106,12 +106,15 @@ function generateArrayPatches(
106
106
  }
107
107
 
108
108
  case 'pop': {
109
- if (state.options.arrayLengthAssignment !== false) {
110
- // Generate length replace patch (mutative uses this instead of remove)
111
- generateReplacePatch(state, [...path, 'length'], array.length, oldLength);
112
- } else {
113
- // When arrayLengthAssignment is false, generate remove patch for last element
114
- generateDeletePatch(state, [...path, oldLength - 1], result);
109
+ // Only generate patch if length actually changed (pop on empty array does nothing)
110
+ if (array.length !== oldLength) {
111
+ if (state.options.arrayLengthAssignment !== false) {
112
+ // Generate length replace patch (mutative uses this instead of remove)
113
+ generateReplacePatch(state, [...path, 'length'], array.length, oldLength);
114
+ } else {
115
+ // When arrayLengthAssignment is false, generate remove patch for last element
116
+ generateDeletePatch(state, [...path, oldLength - 1], result);
117
+ }
115
118
  }
116
119
  break;
117
120
  }
package/src/index.ts CHANGED
@@ -23,13 +23,19 @@ export function recordPatches<
23
23
  T extends NonPrimitive,
24
24
  PatchesOption extends RecordPatchesOptions = {},
25
25
  >(state: T, mutate: (state: T) => void, options?: PatchesOption): Patches {
26
+ // Runtime validation: getItemId requires arrayLengthAssignment: false
27
+ if (options?.getItemId && options?.arrayLengthAssignment !== false) {
28
+ throw new Error(
29
+ 'getItemId requires arrayLengthAssignment: false. ' +
30
+ 'Length patches cannot include individual item IDs.',
31
+ );
32
+ }
33
+
26
34
  const recorderState = {
27
35
  state,
28
36
  patches: [],
29
37
  basePath: [],
30
- options: {
31
- ...options,
32
- },
38
+ options: options ?? {},
33
39
  proxyCache: new WeakMap(),
34
40
  };
35
41
 
package/src/patches.ts CHANGED
@@ -81,6 +81,11 @@ export function generateReplacePatch(
81
81
  value: cloneIfNeeded(value),
82
82
  };
83
83
 
84
+ // Include oldValue for array length changes to enable consumers to detect element removal
85
+ if (path.length > 0 && path[path.length - 1] === 'length' && oldValue !== undefined) {
86
+ patch.oldValue = oldValue;
87
+ }
88
+
84
89
  // Add id if getItemId is configured for this path
85
90
  const getItemIdFn = findGetItemIdFn(path, state.options.getItemId);
86
91
  if (getItemIdFn && oldValue !== undefined) {
package/src/proxy.ts CHANGED
@@ -1,5 +1,10 @@
1
1
  import type {PatchPath, RecorderState} from './types.js';
2
- import {generateSetPatch, generateDeletePatch, generateAddPatch} from './patches.js';
2
+ import {
3
+ generateSetPatch,
4
+ generateDeletePatch,
5
+ generateAddPatch,
6
+ generateReplacePatch,
7
+ } from './patches.js';
3
8
  import {isArray, isMap, isSet} from './utils.js';
4
9
  import {handleArrayGet} from './arrays.js';
5
10
  import {handleMapGet} from './maps.js';
@@ -78,12 +83,50 @@ export function createProxy<T extends object>(
78
83
  return true;
79
84
  }
80
85
 
86
+ // Special handling for array length with arrayLengthAssignment: false
87
+ // Must capture removed items BEFORE mutation
88
+ let removedItems: any[] | null = null;
89
+ if (isArrayType && prop === 'length' && state.options.arrayLengthAssignment === false) {
90
+ const arr = obj as any[];
91
+ const newLength = value as number;
92
+ if (newLength < oldValue) {
93
+ // Capture items that will be removed before mutation
94
+ removedItems = [];
95
+ for (let i = newLength; i < oldValue; i++) {
96
+ removedItems.push(arr[i]);
97
+ }
98
+ }
99
+ }
100
+
81
101
  // Mutate original immediately
82
102
  (obj as any)[prop] = value;
83
103
 
84
104
  // Generate patch - use pre-mutation property existence check
85
105
  if (!hadProperty) {
86
106
  generateAddPatch(state, propPath, value);
107
+ } else if (isArrayType && prop === 'length') {
108
+ if (state.options.arrayLengthAssignment === false) {
109
+ // When arrayLengthAssignment is false, generate individual remove patches
110
+ // for each removed item (in reverse order)
111
+ const newLength = value as number;
112
+
113
+ if (removedItems) {
114
+ // Array was shrinking - generate remove patches for removed items
115
+ // Iterate in reverse to generate patches from end to start
116
+ for (let i = removedItems.length - 1; i >= 0; i--) {
117
+ const index = newLength + i;
118
+ generateDeletePatch(state, [...path, index], removedItems[i]);
119
+ }
120
+ } else if (newLength > oldValue) {
121
+ // Array is growing - generate add patches for new undefined slots
122
+ for (let i = oldValue; i < newLength; i++) {
123
+ generateAddPatch(state, [...path, i], undefined);
124
+ }
125
+ }
126
+ } else {
127
+ // Use generateReplacePatch for array length to include oldValue
128
+ generateReplacePatch(state, propPath, value, oldValue);
129
+ }
87
130
  } else {
88
131
  generateSetPatch(state, propPath, oldValue, value);
89
132
  }
package/src/types.ts CHANGED
@@ -24,6 +24,11 @@ export type Patch = {
24
24
  path: PatchPath;
25
25
  op: PatchOp;
26
26
  value?: any;
27
+ /**
28
+ * Optional previous value for replace operations on array length.
29
+ * Enables consumers to detect how many elements were removed without pre-snapshotting state.
30
+ */
31
+ oldValue?: unknown;
27
32
  /**
28
33
  * Optional ID of the item being removed or replaced.
29
34
  * Populated when getItemId option is configured for the item's parent path.
@@ -35,15 +40,26 @@ export type Patches = Patch[];
35
40
 
36
41
  export type NonPrimitive = object | Array<unknown>;
37
42
 
38
- export interface RecordPatchesOptions {
39
- /**
40
- * Include array length in patches (default: true)
41
- */
42
- arrayLengthAssignment?: boolean;
43
+ /**
44
+ * Base options shared by all configurations
45
+ */
46
+ interface BaseRecordPatchesOptions {
43
47
  /**
44
48
  * Compress patches by merging redundant operations (default: true)
45
49
  */
46
50
  compressPatches?: boolean;
51
+ }
52
+
53
+ /**
54
+ * Options when using getItemId - requires arrayLengthAssignment to be false
55
+ * because length patches cannot include individual item IDs.
56
+ */
57
+ interface RecordPatchesOptionsWithItemId extends BaseRecordPatchesOptions {
58
+ /**
59
+ * Must be false when using getItemId.
60
+ * Length patches cannot include individual item IDs.
61
+ */
62
+ arrayLengthAssignment: false;
47
63
  /**
48
64
  * Configuration for extracting item IDs for remove/replace patches.
49
65
  * Maps paths to functions that extract IDs from item values.
@@ -51,6 +67,7 @@ export interface RecordPatchesOptions {
51
67
  * @example
52
68
  * ```typescript
53
69
  * recordPatches(state, mutate, {
70
+ * arrayLengthAssignment: false,
54
71
  * getItemId: {
55
72
  * items: (item) => item.id,
56
73
  * users: (user) => user.userId,
@@ -61,9 +78,34 @@ export interface RecordPatchesOptions {
61
78
  * });
62
79
  * ```
63
80
  */
64
- getItemId?: GetItemIdConfig;
81
+ getItemId: GetItemIdConfig;
65
82
  }
66
83
 
84
+ /**
85
+ * Options when not using getItemId - arrayLengthAssignment can be any value
86
+ */
87
+ interface RecordPatchesOptionsWithoutItemId extends BaseRecordPatchesOptions {
88
+ /**
89
+ * Include array length in patches (default: true)
90
+ */
91
+ arrayLengthAssignment?: boolean;
92
+ /**
93
+ * Not available unless arrayLengthAssignment is false
94
+ */
95
+ getItemId?: undefined;
96
+ }
97
+
98
+ /**
99
+ * Configuration options for recordPatches.
100
+ *
101
+ * Note: getItemId requires arrayLengthAssignment: false because length patches
102
+ * (e.g., { op: 'replace', path: ['arr', 'length'], value: 2, oldValue: 3 })
103
+ * cannot include the IDs of individual items that were removed.
104
+ */
105
+ export type RecordPatchesOptions =
106
+ | RecordPatchesOptionsWithItemId
107
+ | RecordPatchesOptionsWithoutItemId;
108
+
67
109
  export interface RecorderState<T extends NonPrimitive> {
68
110
  state: T;
69
111
  patches: Patches;