patch-recorder 0.0.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/LICENSE +21 -0
- package/README.md +337 -0
- package/dist/arrays.d.ts +6 -0
- package/dist/arrays.d.ts.map +1 -0
- package/dist/arrays.js +143 -0
- package/dist/arrays.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -0
- package/dist/maps.d.ts +7 -0
- package/dist/maps.d.ts.map +1 -0
- package/dist/maps.js +96 -0
- package/dist/maps.js.map +1 -0
- package/dist/optimizer.d.ts +7 -0
- package/dist/optimizer.d.ts.map +1 -0
- package/dist/optimizer.js +123 -0
- package/dist/optimizer.js.map +1 -0
- package/dist/patches.d.ts +18 -0
- package/dist/patches.d.ts.map +1 -0
- package/dist/patches.js +46 -0
- package/dist/patches.js.map +1 -0
- package/dist/proxy.d.ts +3 -0
- package/dist/proxy.d.ts.map +1 -0
- package/dist/proxy.js +127 -0
- package/dist/proxy.js.map +1 -0
- package/dist/sets.d.ts +7 -0
- package/dist/sets.d.ts.map +1 -0
- package/dist/sets.js +78 -0
- package/dist/sets.js.map +1 -0
- package/dist/types.d.ts +55 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +33 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +132 -0
- package/dist/utils.js.map +1 -0
- package/package.json +60 -0
- package/src/arrays.ts +191 -0
- package/src/index.ts +71 -0
- package/src/maps.ts +120 -0
- package/src/optimizer.ts +136 -0
- package/src/patches.ts +67 -0
- package/src/proxy.ts +163 -0
- package/src/sets.ts +100 -0
- package/src/types.ts +67 -0
- package/src/utils.ts +150 -0
package/dist/maps.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { createProxy } from './proxy.js';
|
|
2
|
+
import { generateAddPatch, generateDeletePatch, generateReplacePatch } from './patches.js';
|
|
3
|
+
import { cloneIfNeeded, isMap, isArray } from './utils.js';
|
|
4
|
+
/**
|
|
5
|
+
* Handle property access on Map objects
|
|
6
|
+
* Wraps mutating methods (set, delete, clear) to generate patches
|
|
7
|
+
*/
|
|
8
|
+
export function handleMapGet(obj, prop, path, state) {
|
|
9
|
+
// Skip symbol properties
|
|
10
|
+
if (typeof prop === 'symbol') {
|
|
11
|
+
return obj[prop];
|
|
12
|
+
}
|
|
13
|
+
// Mutating methods
|
|
14
|
+
if (prop === 'set') {
|
|
15
|
+
return (key, value) => {
|
|
16
|
+
// Check if key existed BEFORE mutation
|
|
17
|
+
const existed = keyExistsInOriginal(state.original, path, key);
|
|
18
|
+
const oldValue = obj.get(key);
|
|
19
|
+
const result = obj.set(key, value);
|
|
20
|
+
// Generate patch
|
|
21
|
+
const itemPath = [...path, key];
|
|
22
|
+
if (existed) {
|
|
23
|
+
// Key exists - replace
|
|
24
|
+
generateReplacePatch(state, itemPath, cloneIfNeeded(value));
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
// Key doesn't exist - add
|
|
28
|
+
generateAddPatch(state, itemPath, cloneIfNeeded(value));
|
|
29
|
+
}
|
|
30
|
+
return result;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
if (prop === 'delete') {
|
|
34
|
+
return (key) => {
|
|
35
|
+
const oldValue = obj.get(key);
|
|
36
|
+
const result = obj.delete(key);
|
|
37
|
+
if (result) {
|
|
38
|
+
const itemPath = [...path, key];
|
|
39
|
+
generateDeletePatch(state, itemPath, cloneIfNeeded(oldValue));
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
if (prop === 'clear') {
|
|
45
|
+
return () => {
|
|
46
|
+
const entries = Array.from(obj.entries());
|
|
47
|
+
obj.clear();
|
|
48
|
+
// Generate remove patches for all items
|
|
49
|
+
entries.forEach(([key, value]) => {
|
|
50
|
+
const itemPath = [...path, key];
|
|
51
|
+
generateDeletePatch(state, itemPath, cloneIfNeeded(value));
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
// Non-mutating methods
|
|
56
|
+
if (prop === 'get') {
|
|
57
|
+
return (key) => {
|
|
58
|
+
const value = obj.get(key);
|
|
59
|
+
// If the value is a Map, Array, or object, return a proxy
|
|
60
|
+
if (value != null && typeof value === 'object') {
|
|
61
|
+
if (isMap(value) || isArray(value)) {
|
|
62
|
+
return createProxy(value, [...path, key], state);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return value;
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
const nonMutatingMethods = ['has', 'keys', 'values', 'entries', 'forEach'];
|
|
69
|
+
if (nonMutatingMethods.includes(prop)) {
|
|
70
|
+
return obj[prop].bind(obj);
|
|
71
|
+
}
|
|
72
|
+
// Size property
|
|
73
|
+
if (prop === 'size') {
|
|
74
|
+
return obj.size;
|
|
75
|
+
}
|
|
76
|
+
// Return any other property
|
|
77
|
+
return obj[prop];
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Navigate to the original Map at the given path and check if a key exists
|
|
81
|
+
* This is needed to check if a key existed before mutations
|
|
82
|
+
*/
|
|
83
|
+
function keyExistsInOriginal(original, path, key) {
|
|
84
|
+
let current = original;
|
|
85
|
+
for (const part of path) {
|
|
86
|
+
if (current == null)
|
|
87
|
+
return false;
|
|
88
|
+
current = current[part];
|
|
89
|
+
}
|
|
90
|
+
// If we reached a Map, check if the key exists
|
|
91
|
+
if (current instanceof Map) {
|
|
92
|
+
return current.has(key);
|
|
93
|
+
}
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=maps.js.map
|
package/dist/maps.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"maps.js","sourceRoot":"","sources":["../src/maps.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Patches } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Compress patches by merging redundant operations
|
|
4
|
+
* This handles both consecutive and interleaved operations on the same path
|
|
5
|
+
*/
|
|
6
|
+
export declare function compressPatches(patches: Patches<true>): Patches<true>;
|
|
7
|
+
//# sourceMappingURL=optimizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"optimizer.d.ts","sourceRoot":"","sources":["../src/optimizer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,YAAY,CAAC;AAExC;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAqCrE"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compress patches by merging redundant operations
|
|
3
|
+
* This handles both consecutive and interleaved operations on the same path
|
|
4
|
+
*/
|
|
5
|
+
export function compressPatches(patches) {
|
|
6
|
+
if (patches.length === 0) {
|
|
7
|
+
return patches;
|
|
8
|
+
}
|
|
9
|
+
// Use a Map to track the latest operation for each path
|
|
10
|
+
// Key: JSON stringified path, Value: the latest patch for that path
|
|
11
|
+
const pathMap = new Map();
|
|
12
|
+
for (const patch of patches) {
|
|
13
|
+
const pathKey = JSON.stringify(patch.path);
|
|
14
|
+
const existing = pathMap.get(pathKey);
|
|
15
|
+
if (!existing) {
|
|
16
|
+
// First operation on this path
|
|
17
|
+
pathMap.set(pathKey, patch);
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
// Merge with existing operation based on operation types
|
|
21
|
+
const merged = mergePatches(existing, patch);
|
|
22
|
+
if (merged) {
|
|
23
|
+
// Update with merged result (or null if they cancel out)
|
|
24
|
+
if (merged !== null) {
|
|
25
|
+
pathMap.set(pathKey, merged);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
// Operations canceled each other out
|
|
29
|
+
pathMap.delete(pathKey);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
// Can't merge, keep the new operation
|
|
34
|
+
pathMap.set(pathKey, patch);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// Convert Map back to array
|
|
38
|
+
return Array.from(pathMap.values());
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Merge two patches on the same path
|
|
42
|
+
* Returns the merged patch, or null if they cancel out, or undefined if they can't be merged
|
|
43
|
+
*/
|
|
44
|
+
function mergePatches(patch1, patch2) {
|
|
45
|
+
const op1 = patch1.op;
|
|
46
|
+
const op2 = patch2.op;
|
|
47
|
+
// Same operations - keep the latest one
|
|
48
|
+
if (op1 === op2) {
|
|
49
|
+
// For replace operations, keep the latest value
|
|
50
|
+
if (op1 === 'replace') {
|
|
51
|
+
// Skip if same value (no-op)
|
|
52
|
+
if (valuesEqual(patch1.value, patch2.value)) {
|
|
53
|
+
return patch1;
|
|
54
|
+
}
|
|
55
|
+
return patch2;
|
|
56
|
+
}
|
|
57
|
+
// For add operations, if adding the same value, it's a no-op
|
|
58
|
+
if (op1 === 'add' && valuesEqual(patch1.value, patch2.value)) {
|
|
59
|
+
return patch1;
|
|
60
|
+
}
|
|
61
|
+
// For remove operations, keep the latest
|
|
62
|
+
if (op1 === 'remove') {
|
|
63
|
+
return patch2;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// Different operations
|
|
67
|
+
if (op1 === 'add' && op2 === 'replace') {
|
|
68
|
+
// Add then replace - just keep the replace
|
|
69
|
+
return patch2;
|
|
70
|
+
}
|
|
71
|
+
if (op1 === 'replace' && op2 === 'replace') {
|
|
72
|
+
// Replace then replace - keep the latest
|
|
73
|
+
return patch2;
|
|
74
|
+
}
|
|
75
|
+
if (op1 === 'replace' && op2 === 'remove') {
|
|
76
|
+
// Replace then delete - just keep the delete
|
|
77
|
+
return patch2;
|
|
78
|
+
}
|
|
79
|
+
if (op1 === 'add' && op2 === 'remove') {
|
|
80
|
+
// Add then remove - they cancel out
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
if (op1 === 'remove' && op2 === 'add') {
|
|
84
|
+
// Remove then add - keep the add
|
|
85
|
+
return patch2;
|
|
86
|
+
}
|
|
87
|
+
// Can't merge these operations
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Check if two values are equal (deep comparison)
|
|
92
|
+
*/
|
|
93
|
+
function valuesEqual(val1, val2) {
|
|
94
|
+
if (val1 === val2)
|
|
95
|
+
return true;
|
|
96
|
+
// Handle null/undefined
|
|
97
|
+
if (val1 == null || val2 == null)
|
|
98
|
+
return val1 === val2;
|
|
99
|
+
// Handle arrays
|
|
100
|
+
if (Array.isArray(val1) && Array.isArray(val2)) {
|
|
101
|
+
if (val1.length !== val2.length)
|
|
102
|
+
return false;
|
|
103
|
+
for (let i = 0; i < val1.length; i++) {
|
|
104
|
+
if (!valuesEqual(val1[i], val2[i]))
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
// Handle objects
|
|
110
|
+
if (typeof val1 === 'object' && typeof val2 === 'object') {
|
|
111
|
+
const keys1 = Object.keys(val1);
|
|
112
|
+
const keys2 = Object.keys(val2);
|
|
113
|
+
if (keys1.length !== keys2.length)
|
|
114
|
+
return false;
|
|
115
|
+
for (const key of keys1) {
|
|
116
|
+
if (!valuesEqual(val1[key], val2[key]))
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=optimizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"optimizer.js","sourceRoot":"","sources":["../src/optimizer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { RecorderState } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Generate a replace patch for property changes
|
|
4
|
+
*/
|
|
5
|
+
export declare function generateSetPatch(state: RecorderState<any>, path: (string | number)[], oldValue: any, newValue: any): void;
|
|
6
|
+
/**
|
|
7
|
+
* Generate a remove patch for property deletions
|
|
8
|
+
*/
|
|
9
|
+
export declare function generateDeletePatch(state: RecorderState<any>, path: (string | number)[], oldValue: any): void;
|
|
10
|
+
/**
|
|
11
|
+
* Generate an add patch for new properties
|
|
12
|
+
*/
|
|
13
|
+
export declare function generateAddPatch(state: RecorderState<any>, path: (string | number)[], value: any): void;
|
|
14
|
+
/**
|
|
15
|
+
* Generate a replace patch for full object/array replacement
|
|
16
|
+
*/
|
|
17
|
+
export declare function generateReplacePatch(state: RecorderState<any>, path: (string | number)[], value: any): void;
|
|
18
|
+
//# sourceMappingURL=patches.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patches.d.ts","sourceRoot":"","sources":["../src/patches.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,YAAY,CAAC;AAI9C;;GAEG;AACH,wBAAgB,gBAAgB,CAC/B,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,EACzB,IAAI,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,EACzB,QAAQ,EAAE,GAAG,EACb,QAAQ,EAAE,GAAG,QASb;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAClC,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,EACzB,IAAI,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,EACzB,QAAQ,EAAE,GAAG,QAQb;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,GAAG,QAQhG;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CACnC,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,EACzB,IAAI,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,EACzB,KAAK,EAAE,GAAG,QASV"}
|
package/dist/patches.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Operation } from './types.js';
|
|
2
|
+
import { formatPath, cloneIfNeeded } from './utils.js';
|
|
3
|
+
/**
|
|
4
|
+
* Generate a replace patch for property changes
|
|
5
|
+
*/
|
|
6
|
+
export function generateSetPatch(state, path, oldValue, newValue) {
|
|
7
|
+
const patch = {
|
|
8
|
+
op: Operation.Replace,
|
|
9
|
+
path: formatPath(path, state.options),
|
|
10
|
+
value: cloneIfNeeded(newValue),
|
|
11
|
+
};
|
|
12
|
+
state.patches.push(patch);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Generate a remove patch for property deletions
|
|
16
|
+
*/
|
|
17
|
+
export function generateDeletePatch(state, path, oldValue) {
|
|
18
|
+
const patch = {
|
|
19
|
+
op: Operation.Remove,
|
|
20
|
+
path: formatPath(path, state.options),
|
|
21
|
+
};
|
|
22
|
+
state.patches.push(patch);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Generate an add patch for new properties
|
|
26
|
+
*/
|
|
27
|
+
export function generateAddPatch(state, path, value) {
|
|
28
|
+
const patch = {
|
|
29
|
+
op: Operation.Add,
|
|
30
|
+
path: formatPath(path, state.options),
|
|
31
|
+
value: cloneIfNeeded(value),
|
|
32
|
+
};
|
|
33
|
+
state.patches.push(patch);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Generate a replace patch for full object/array replacement
|
|
37
|
+
*/
|
|
38
|
+
export function generateReplacePatch(state, path, value) {
|
|
39
|
+
const patch = {
|
|
40
|
+
op: Operation.Replace,
|
|
41
|
+
path: formatPath(path, state.options),
|
|
42
|
+
value: cloneIfNeeded(value),
|
|
43
|
+
};
|
|
44
|
+
state.patches.push(patch);
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=patches.js.map
|
|
@@ -0,0 +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,UAAU,EAAE,aAAa,EAAC,MAAM,YAAY,CAAC;AAErD;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAC/B,KAAyB,EACzB,IAAyB,EACzB,QAAa,EACb,QAAa;IAEb,MAAM,KAAK,GAAG;QACb,EAAE,EAAE,SAAS,CAAC,OAAO;QACrB,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC;QACrC,KAAK,EAAE,aAAa,CAAC,QAAQ,CAAC;KAC9B,CAAC;IAEF,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAClC,KAAyB,EACzB,IAAyB,EACzB,QAAa;IAEb,MAAM,KAAK,GAAG;QACb,EAAE,EAAE,SAAS,CAAC,MAAM;QACpB,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC;KACrC,CAAC;IAEF,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAyB,EAAE,IAAyB,EAAE,KAAU;IAChG,MAAM,KAAK,GAAG;QACb,EAAE,EAAE,SAAS,CAAC,GAAG;QACjB,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC;QACrC,KAAK,EAAE,aAAa,CAAC,KAAK,CAAC;KAC3B,CAAC;IAEF,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CACnC,KAAyB,EACzB,IAAyB,EACzB,KAAU;IAEV,MAAM,KAAK,GAAG;QACb,EAAE,EAAE,SAAS,CAAC,OAAO;QACrB,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC;QACrC,KAAK,EAAE,aAAa,CAAC,KAAK,CAAC;KAC3B,CAAC;IAEF,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC"}
|
package/dist/proxy.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,YAAY,CAAC;AAO9C,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAC3C,MAAM,EAAE,CAAC,EACT,IAAI,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,EACzB,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,GACvB,CAAC,CAuJH"}
|
package/dist/proxy.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { generateSetPatch, generateDeletePatch, generateAddPatch } from './patches.js';
|
|
2
|
+
import { isArray, isMap, isSet } from './utils.js';
|
|
3
|
+
import { handleArrayGet } from './arrays.js';
|
|
4
|
+
import { handleMapGet } from './maps.js';
|
|
5
|
+
import { handleSetGet } from './sets.js';
|
|
6
|
+
export function createProxy(target, path, state) {
|
|
7
|
+
const isArrayType = isArray(target);
|
|
8
|
+
const isMapType = isMap(target);
|
|
9
|
+
const isSetType = isSet(target);
|
|
10
|
+
const handler = {
|
|
11
|
+
get(obj, prop) {
|
|
12
|
+
// Handle array methods
|
|
13
|
+
if (isArrayType && typeof prop === 'string') {
|
|
14
|
+
return handleArrayGet(obj, prop, path, state);
|
|
15
|
+
}
|
|
16
|
+
// Handle Map methods
|
|
17
|
+
if (isMapType) {
|
|
18
|
+
return handleMapGet(obj, prop, path, state);
|
|
19
|
+
}
|
|
20
|
+
// Handle Set methods
|
|
21
|
+
if (isSetType) {
|
|
22
|
+
return handleSetGet(obj, prop, path, state);
|
|
23
|
+
}
|
|
24
|
+
// Handle property access
|
|
25
|
+
const value = obj[prop];
|
|
26
|
+
// Skip creating proxies for primitive values and special cases
|
|
27
|
+
if (typeof value !== 'object' || value === null) {
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
// Create nested proxy for draftable values
|
|
31
|
+
// Only include string | number in path, skip symbols
|
|
32
|
+
if (typeof prop === 'string' || typeof prop === 'number') {
|
|
33
|
+
return createProxy(value, [...path, prop], state);
|
|
34
|
+
}
|
|
35
|
+
return value;
|
|
36
|
+
},
|
|
37
|
+
set(obj, prop, value) {
|
|
38
|
+
// Map and Set don't support direct property assignment
|
|
39
|
+
if (isMapType || isSetType) {
|
|
40
|
+
throw new Error('Map/Set draft does not support any property assignment.');
|
|
41
|
+
}
|
|
42
|
+
const oldValue = obj[prop];
|
|
43
|
+
// Only create path for string | number props, skip symbols
|
|
44
|
+
if (typeof prop !== 'string' && typeof prop !== 'number') {
|
|
45
|
+
obj[prop] = value;
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
// Convert numeric string props to numbers for array indices
|
|
49
|
+
const propForPath = typeof prop === 'string' && !isNaN(Number(prop)) ? Number(prop) : prop;
|
|
50
|
+
const propPath = [...path, propForPath];
|
|
51
|
+
// Skip if no actual change (handle undefined as a valid value)
|
|
52
|
+
if (oldValue === value &&
|
|
53
|
+
(value !== undefined || Object.prototype.hasOwnProperty.call(obj, prop))) {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
// Determine if this is an add or replace operation by checking the original state
|
|
57
|
+
let originalHasProperty = false;
|
|
58
|
+
let originalValue = undefined;
|
|
59
|
+
// Navigate to the original object at this path
|
|
60
|
+
let currentOriginal = state.original;
|
|
61
|
+
for (let i = 0; i < path.length; i++) {
|
|
62
|
+
currentOriginal = currentOriginal[path[i]];
|
|
63
|
+
if (currentOriginal === undefined || currentOriginal === null) {
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (currentOriginal && currentOriginal !== undefined && currentOriginal !== null) {
|
|
68
|
+
originalHasProperty = Object.prototype.hasOwnProperty.call(currentOriginal, prop);
|
|
69
|
+
originalValue = currentOriginal[prop];
|
|
70
|
+
}
|
|
71
|
+
// Mutate original immediately
|
|
72
|
+
obj[prop] = value;
|
|
73
|
+
// Generate patch
|
|
74
|
+
if (!originalHasProperty) {
|
|
75
|
+
generateAddPatch(state, propPath, value);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
generateSetPatch(state, propPath, originalValue, value);
|
|
79
|
+
}
|
|
80
|
+
return true;
|
|
81
|
+
},
|
|
82
|
+
deleteProperty(obj, prop) {
|
|
83
|
+
if (isArrayType) {
|
|
84
|
+
// For arrays, delete is equivalent to setting to undefined
|
|
85
|
+
return handler.set(obj, prop, undefined, obj);
|
|
86
|
+
}
|
|
87
|
+
// Map and Set don't support deleteProperty
|
|
88
|
+
if (isMapType || isSetType) {
|
|
89
|
+
throw new Error('Map/Set draft does not support deleteProperty.');
|
|
90
|
+
}
|
|
91
|
+
const oldValue = obj[prop];
|
|
92
|
+
// Only create path for string | number props, skip symbols
|
|
93
|
+
if (typeof prop !== 'string' && typeof prop !== 'number') {
|
|
94
|
+
delete obj[prop];
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
const propPath = [...path, prop];
|
|
98
|
+
if (oldValue !== undefined || Object.prototype.hasOwnProperty.call(obj, prop)) {
|
|
99
|
+
delete obj[prop];
|
|
100
|
+
// Generate patch
|
|
101
|
+
generateDeletePatch(state, propPath, oldValue);
|
|
102
|
+
}
|
|
103
|
+
return true;
|
|
104
|
+
},
|
|
105
|
+
has(obj, prop) {
|
|
106
|
+
return prop in obj;
|
|
107
|
+
},
|
|
108
|
+
ownKeys(obj) {
|
|
109
|
+
return Reflect.ownKeys(obj);
|
|
110
|
+
},
|
|
111
|
+
getOwnPropertyDescriptor(obj, prop) {
|
|
112
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(obj, prop);
|
|
113
|
+
if (!descriptor)
|
|
114
|
+
return descriptor;
|
|
115
|
+
return {
|
|
116
|
+
...descriptor,
|
|
117
|
+
writable: true,
|
|
118
|
+
configurable: true,
|
|
119
|
+
};
|
|
120
|
+
},
|
|
121
|
+
getPrototypeOf(obj) {
|
|
122
|
+
return Reflect.getPrototypeOf(obj);
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
return new Proxy(target, handler);
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"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"}
|
package/dist/sets.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RecorderState } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Handle property access on Set objects
|
|
4
|
+
* Wraps mutating methods (add, delete, clear) to generate patches
|
|
5
|
+
*/
|
|
6
|
+
export declare function handleSetGet<T = any>(obj: Set<T>, prop: string | symbol, path: (string | number)[], state: RecorderState<any>): any;
|
|
7
|
+
//# sourceMappingURL=sets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sets.d.ts","sourceRoot":"","sources":["../src/sets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,YAAY,CAAC;AAM9C;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,GAAG,GAAG,EACnC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,EACX,IAAI,EAAE,MAAM,GAAG,MAAM,EACrB,IAAI,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,EACzB,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,GACvB,GAAG,CAiEL"}
|
package/dist/sets.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { generateAddPatch, generateDeletePatch } from './patches.js';
|
|
2
|
+
import { cloneIfNeeded } from './utils.js';
|
|
3
|
+
/**
|
|
4
|
+
* Handle property access on Set objects
|
|
5
|
+
* Wraps mutating methods (add, delete, clear) to generate patches
|
|
6
|
+
*/
|
|
7
|
+
export function handleSetGet(obj, prop, path, state) {
|
|
8
|
+
// Skip symbol properties
|
|
9
|
+
if (typeof prop === 'symbol') {
|
|
10
|
+
return obj[prop];
|
|
11
|
+
}
|
|
12
|
+
// Mutating methods
|
|
13
|
+
if (prop === 'add') {
|
|
14
|
+
return (value) => {
|
|
15
|
+
// Check if value existed BEFORE mutation
|
|
16
|
+
const existed = valueExistsInOriginal(state.original, path, value);
|
|
17
|
+
const result = obj.add(value);
|
|
18
|
+
// Generate patch only if value didn't exist
|
|
19
|
+
if (!existed) {
|
|
20
|
+
const itemPath = [...path, value];
|
|
21
|
+
generateAddPatch(state, itemPath, cloneIfNeeded(value));
|
|
22
|
+
}
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
if (prop === 'delete') {
|
|
27
|
+
return (value) => {
|
|
28
|
+
const existed = obj.has(value);
|
|
29
|
+
const result = obj.delete(value);
|
|
30
|
+
// Generate patch only if value existed
|
|
31
|
+
if (existed) {
|
|
32
|
+
const itemPath = [...path, value];
|
|
33
|
+
generateDeletePatch(state, itemPath, cloneIfNeeded(value));
|
|
34
|
+
}
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
if (prop === 'clear') {
|
|
39
|
+
return () => {
|
|
40
|
+
const values = Array.from(obj.values());
|
|
41
|
+
obj.clear();
|
|
42
|
+
// Generate remove patches for all items
|
|
43
|
+
values.forEach((value) => {
|
|
44
|
+
const itemPath = [...path, value];
|
|
45
|
+
generateDeletePatch(state, itemPath, cloneIfNeeded(value));
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
// Non-mutating methods
|
|
50
|
+
const nonMutatingMethods = ['has', 'keys', 'values', 'entries', 'forEach'];
|
|
51
|
+
if (nonMutatingMethods.includes(prop)) {
|
|
52
|
+
return obj[prop].bind(obj);
|
|
53
|
+
}
|
|
54
|
+
// Size property
|
|
55
|
+
if (prop === 'size') {
|
|
56
|
+
return obj.size;
|
|
57
|
+
}
|
|
58
|
+
// Return any other property
|
|
59
|
+
return obj[prop];
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Navigate to the original Set at the given path and check if a value exists
|
|
63
|
+
* This is needed to check if a value existed before mutations
|
|
64
|
+
*/
|
|
65
|
+
function valueExistsInOriginal(original, path, value) {
|
|
66
|
+
let current = original;
|
|
67
|
+
for (const part of path) {
|
|
68
|
+
if (current == null)
|
|
69
|
+
return false;
|
|
70
|
+
current = current[part];
|
|
71
|
+
}
|
|
72
|
+
// If we reached a Set, check if the value exists
|
|
73
|
+
if (current instanceof Set) {
|
|
74
|
+
return current.has(value);
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=sets.js.map
|
package/dist/sets.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sets.js","sourceRoot":"","sources":["../src/sets.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,gBAAgB,EAAE,mBAAmB,EAAC,MAAM,cAAc,CAAC;AACnE,OAAO,EAAC,aAAa,EAAiB,MAAM,YAAY,CAAC;AAEzD;;;GAGG;AACH,MAAM,UAAU,YAAY,CAC3B,GAAW,EACX,IAAqB,EACrB,IAAyB,EACzB,KAAyB;IAEzB,yBAAyB;IACzB,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAQ,GAAW,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;IAED,mBAAmB;IACnB,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACpB,OAAO,CAAC,KAAQ,EAAE,EAAE;YACnB,yCAAyC;YACzC,MAAM,OAAO,GAAG,qBAAqB,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;YACnE,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAE9B,4CAA4C;YAC5C,IAAI,CAAC,OAAO,EAAE,CAAC;gBACd,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,EAAE,KAAY,CAAC,CAAC;gBACzC,gBAAgB,CAAC,KAAK,EAAE,QAAQ,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;YACzD,CAAC;YAED,OAAO,MAAM,CAAC;QACf,CAAC,CAAC;IACH,CAAC;IAED,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACvB,OAAO,CAAC,KAAQ,EAAE,EAAE;YACnB,MAAM,OAAO,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAC/B,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAEjC,uCAAuC;YACvC,IAAI,OAAO,EAAE,CAAC;gBACb,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,EAAE,KAAY,CAAC,CAAC;gBACzC,mBAAmB,CAAC,KAAK,EAAE,QAAQ,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;YAC5D,CAAC;YAED,OAAO,MAAM,CAAC;QACf,CAAC,CAAC;IACH,CAAC;IAED,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QACtB,OAAO,GAAG,EAAE;YACX,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;YACxC,GAAG,CAAC,KAAK,EAAE,CAAC;YAEZ,wCAAwC;YACxC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;gBACxB,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,EAAE,KAAY,CAAC,CAAC;gBACzC,mBAAmB,CAAC,KAAK,EAAE,QAAQ,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;YAC5D,CAAC,CAAC,CAAC;QACJ,CAAC,CAAC;IACH,CAAC;IAED,uBAAuB;IACvB,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IAE3E,IAAI,kBAAkB,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACvC,OAAQ,GAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACrC,CAAC;IAED,gBAAgB;IAChB,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACrB,OAAO,GAAG,CAAC,IAAI,CAAC;IACjB,CAAC;IAED,4BAA4B;IAC5B,OAAQ,GAAW,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED;;;GAGG;AACH,SAAS,qBAAqB,CAAC,QAAa,EAAE,IAAyB,EAAE,KAAU;IAClF,IAAI,OAAO,GAAG,QAAQ,CAAC;IACvB,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;QACzB,IAAI,OAAO,IAAI,IAAI;YAAE,OAAO,KAAK,CAAC;QAClC,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAED,iDAAiD;IACjD,IAAI,OAAO,YAAY,GAAG,EAAE,CAAC;QAC5B,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC;IAED,OAAO,KAAK,CAAC;AACd,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export declare const Operation: {
|
|
2
|
+
readonly Remove: "remove";
|
|
3
|
+
readonly Replace: "replace";
|
|
4
|
+
readonly Add: "add";
|
|
5
|
+
};
|
|
6
|
+
export type PatchOp = (typeof Operation)[keyof typeof Operation];
|
|
7
|
+
export type PatchesOptions = boolean | {
|
|
8
|
+
/**
|
|
9
|
+
* The default value is `true`. If it's `true`, the path will be an array, otherwise it is a string.
|
|
10
|
+
*/
|
|
11
|
+
pathAsArray?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* The default value is `true`. If it's `true`, the array length will be included in the patches, otherwise no include array length.
|
|
14
|
+
*/
|
|
15
|
+
arrayLengthAssignment?: boolean;
|
|
16
|
+
};
|
|
17
|
+
export interface IPatch {
|
|
18
|
+
op: PatchOp;
|
|
19
|
+
value?: any;
|
|
20
|
+
}
|
|
21
|
+
export type Patch<P extends PatchesOptions = any> = P extends {
|
|
22
|
+
pathAsArray: false;
|
|
23
|
+
} ? IPatch & {
|
|
24
|
+
path: string;
|
|
25
|
+
} : P extends true | object ? IPatch & {
|
|
26
|
+
path: (string | number)[];
|
|
27
|
+
} : IPatch & {
|
|
28
|
+
path: string | (string | number)[];
|
|
29
|
+
};
|
|
30
|
+
export type Patches<P extends PatchesOptions = any> = Patch<P>[];
|
|
31
|
+
export type NonPrimitive = object | Array<unknown>;
|
|
32
|
+
export interface RecordPatchesOptions {
|
|
33
|
+
/**
|
|
34
|
+
* Return paths as arrays (default: true) or strings
|
|
35
|
+
*/
|
|
36
|
+
pathAsArray?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Include array length in patches (default: true)
|
|
39
|
+
*/
|
|
40
|
+
arrayLengthAssignment?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Optimize patches by merging redundant operations (default: false)
|
|
43
|
+
*/
|
|
44
|
+
optimize?: boolean;
|
|
45
|
+
}
|
|
46
|
+
export type Draft<T> = T;
|
|
47
|
+
export interface RecorderState<T> {
|
|
48
|
+
original: T;
|
|
49
|
+
patches: Patches<any>;
|
|
50
|
+
basePath: (string | number)[];
|
|
51
|
+
options: RecordPatchesOptions & {
|
|
52
|
+
internalPatchesOptions: PatchesOptions;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +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,QAAQ,CAAC,EAAE,OAAO,CAAC;CACnB;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/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,SAAS,GAAG;IACxB,MAAM,EAAE,QAAQ;IAChB,OAAO,EAAE,SAAS;IAClB,GAAG,EAAE,KAAK;CACD,CAAC"}
|