patch-recorder 0.1.0 → 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 +1 -75
- package/dist/arrays.d.ts +2 -2
- package/dist/arrays.d.ts.map +1 -1
- package/dist/arrays.js +12 -20
- package/dist/arrays.js.map +1 -1
- package/dist/index.d.ts +1 -24
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -34
- package/dist/index.js.map +1 -1
- package/dist/maps.d.ts +2 -2
- package/dist/maps.d.ts.map +1 -1
- package/dist/maps.js +4 -20
- package/dist/maps.js.map +1 -1
- package/dist/optimizer.d.ts +16 -1
- package/dist/optimizer.d.ts.map +1 -1
- package/dist/optimizer.js +114 -15
- package/dist/optimizer.js.map +1 -1
- package/dist/patches.d.ts +5 -5
- package/dist/patches.d.ts.map +1 -1
- package/dist/patches.js +5 -5
- package/dist/patches.js.map +1 -1
- package/dist/proxy.d.ts +2 -2
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +24 -52
- package/dist/proxy.js.map +1 -1
- package/dist/sets.d.ts +2 -2
- package/dist/sets.d.ts.map +1 -1
- package/dist/sets.js +4 -20
- package/dist/sets.js.map +1 -1
- package/dist/types.d.ts +14 -33
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +28 -13
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +76 -20
- package/dist/utils.js.map +1 -1
- package/package.json +2 -1
- package/src/arrays.ts +22 -30
- package/src/index.ts +9 -54
- package/src/maps.ts +12 -30
- package/src/optimizer.ts +146 -28
- package/src/patches.ts +20 -21
- package/src/proxy.ts +31 -60
- package/src/sets.ts +11 -30
- package/src/types.ts +16 -40
- package/src/utils.ts +81 -28
package/dist/optimizer.js
CHANGED
|
@@ -1,16 +1,100 @@
|
|
|
1
|
+
import { pathToKey } from './utils.js';
|
|
1
2
|
/**
|
|
2
|
-
*
|
|
3
|
-
|
|
3
|
+
* Navigate to a node in the path tree, creating nodes along the way
|
|
4
|
+
*/
|
|
5
|
+
function getOrCreateNode(root, path) {
|
|
6
|
+
let current = root;
|
|
7
|
+
for (const key of path) {
|
|
8
|
+
if (!current.children) {
|
|
9
|
+
current.children = new Map();
|
|
10
|
+
}
|
|
11
|
+
let child = current.children.get(key);
|
|
12
|
+
if (!child) {
|
|
13
|
+
child = {};
|
|
14
|
+
current.children.set(key, child);
|
|
15
|
+
}
|
|
16
|
+
current = child;
|
|
17
|
+
}
|
|
18
|
+
return current;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Collect all patches from the path tree
|
|
22
|
+
*/
|
|
23
|
+
function collectPatches(node, patches = []) {
|
|
24
|
+
if (node.patch) {
|
|
25
|
+
patches.push(node.patch);
|
|
26
|
+
}
|
|
27
|
+
if (node.children) {
|
|
28
|
+
for (const child of node.children.values()) {
|
|
29
|
+
collectPatches(child, patches);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return patches;
|
|
33
|
+
}
|
|
34
|
+
// ==================== V2: Nested Map optimizer (faster) ====================
|
|
35
|
+
/**
|
|
36
|
+
* Compress patches by merging redundant operations using nested Maps
|
|
37
|
+
* This is faster than the string-key version because:
|
|
38
|
+
* - No string allocation for path keys
|
|
39
|
+
* - Preserves symbol and object identity
|
|
40
|
+
* - 2.5-5x faster in benchmarks
|
|
4
41
|
*/
|
|
5
|
-
export function
|
|
42
|
+
export function compressPatchesWithNestedMaps(patches) {
|
|
43
|
+
if (patches.length === 0) {
|
|
44
|
+
return patches;
|
|
45
|
+
}
|
|
46
|
+
// Use a nested Map tree to track the latest operation for each path
|
|
47
|
+
const root = {};
|
|
48
|
+
for (const patch of patches) {
|
|
49
|
+
const node = getOrCreateNode(root, patch.path);
|
|
50
|
+
const existing = node.patch;
|
|
51
|
+
if (!existing) {
|
|
52
|
+
// First operation on this path
|
|
53
|
+
node.patch = patch;
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
// Merge with existing operation based on operation types
|
|
57
|
+
const merged = mergePatches(existing, patch);
|
|
58
|
+
// Check for undefined specifically (null means canceled, which is a valid result)
|
|
59
|
+
if (merged !== undefined) {
|
|
60
|
+
// Update with merged result (or null if they cancel out)
|
|
61
|
+
if (merged !== null) {
|
|
62
|
+
node.patch = merged;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
// Operations canceled each other out
|
|
66
|
+
delete node.patch;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
// Can't merge, keep the new operation
|
|
71
|
+
node.patch = patch;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Collect all patches from tree
|
|
76
|
+
let finalPatches = collectPatches(root);
|
|
77
|
+
// Handle array push + pop cancellation
|
|
78
|
+
// Only cancel when push is at the last index and pop reduces length
|
|
79
|
+
finalPatches = cancelArrayPushPop(finalPatches);
|
|
80
|
+
// Cancel patches that are beyond array bounds after final length update
|
|
81
|
+
finalPatches = cancelOutOfBoundsPatches(finalPatches);
|
|
82
|
+
return finalPatches;
|
|
83
|
+
}
|
|
84
|
+
// ==================== V1: String key optimizer (original) ====================
|
|
85
|
+
/**
|
|
86
|
+
* Compress patches by merging redundant operations using string keys
|
|
87
|
+
* This is the original implementation that uses pathToKey for path lookup.
|
|
88
|
+
*/
|
|
89
|
+
export function compressPatchesWithStringKeys(patches) {
|
|
6
90
|
if (patches.length === 0) {
|
|
7
91
|
return patches;
|
|
8
92
|
}
|
|
9
93
|
// Use a Map to track the latest operation for each path
|
|
10
|
-
// Key:
|
|
94
|
+
// Key: optimized path string (using pathToKey), Value: the latest patch for that path
|
|
11
95
|
const pathMap = new Map();
|
|
12
96
|
for (const patch of patches) {
|
|
13
|
-
const pathKey =
|
|
97
|
+
const pathKey = pathToKey(patch.path);
|
|
14
98
|
const existing = pathMap.get(pathKey);
|
|
15
99
|
if (!existing) {
|
|
16
100
|
// First operation on this path
|
|
@@ -45,9 +129,21 @@ export function compressPatches(patches) {
|
|
|
45
129
|
finalPatches = cancelOutOfBoundsPatches(finalPatches);
|
|
46
130
|
return finalPatches;
|
|
47
131
|
}
|
|
132
|
+
// ==================== Default export ====================
|
|
133
|
+
/**
|
|
134
|
+
* Compress patches by merging redundant operations
|
|
135
|
+
* This handles both consecutive and interleaved operations on the same path
|
|
136
|
+
*
|
|
137
|
+
* Uses the nested Map implementation for better performance (2.5-5x faster)
|
|
138
|
+
*/
|
|
139
|
+
export const compressPatches = compressPatchesWithNestedMaps;
|
|
140
|
+
// ==================== Post-processing functions (shared) ====================
|
|
48
141
|
/**
|
|
49
142
|
* Cancel array push + pop operations
|
|
50
143
|
* Only cancels when push is at the last index and pop reduces length
|
|
144
|
+
*
|
|
145
|
+
* Note: Uses pathToKey for grouping since this works on already-compressed patches
|
|
146
|
+
* (smaller set) and the performance benefit of nested Maps is less significant here.
|
|
51
147
|
*/
|
|
52
148
|
function cancelArrayPushPop(patches) {
|
|
53
149
|
// Group patches by parent array path
|
|
@@ -57,13 +153,14 @@ function cancelArrayPushPop(patches) {
|
|
|
57
153
|
continue;
|
|
58
154
|
}
|
|
59
155
|
const parentPath = patch.path.slice(0, -1);
|
|
60
|
-
const parentKey =
|
|
156
|
+
const parentKey = pathToKey(parentPath);
|
|
61
157
|
if (!arrayGroups.has(parentKey)) {
|
|
62
158
|
arrayGroups.set(parentKey, []);
|
|
63
159
|
}
|
|
64
160
|
arrayGroups.get(parentKey).push(patch);
|
|
65
161
|
}
|
|
66
|
-
|
|
162
|
+
// Use WeakSet to track cancelable patches by reference (no string allocation)
|
|
163
|
+
const cancelablePatches = new WeakSet();
|
|
67
164
|
for (const [, groupPatches] of arrayGroups.entries()) {
|
|
68
165
|
// Find push patches (add at highest indices)
|
|
69
166
|
const pushPatches = groupPatches
|
|
@@ -82,12 +179,12 @@ function cancelArrayPushPop(patches) {
|
|
|
82
179
|
// If push added at index pushIndex and pop reduced to popLength, they cancel
|
|
83
180
|
// This is a heuristic: push adds at end, pop removes from end
|
|
84
181
|
if (pushIndex >= popLength) {
|
|
85
|
-
cancelablePatches.add(
|
|
86
|
-
cancelablePatches.add(
|
|
182
|
+
cancelablePatches.add(pushPatch);
|
|
183
|
+
cancelablePatches.add(popPatch);
|
|
87
184
|
}
|
|
88
185
|
}
|
|
89
186
|
}
|
|
90
|
-
return patches.filter((patch) => !cancelablePatches.has(
|
|
187
|
+
return patches.filter((patch) => !cancelablePatches.has(patch));
|
|
91
188
|
}
|
|
92
189
|
/**
|
|
93
190
|
* Cancel patches that are beyond array bounds after final length update
|
|
@@ -95,31 +192,33 @@ function cancelArrayPushPop(patches) {
|
|
|
95
192
|
function cancelOutOfBoundsPatches(patches) {
|
|
96
193
|
// Find the final length for each array
|
|
97
194
|
const arrayLengths = new Map();
|
|
98
|
-
const canceledPatches = new Set();
|
|
99
195
|
for (const patch of patches) {
|
|
100
196
|
if (Array.isArray(patch.path) &&
|
|
101
197
|
patch.path.length >= 2 &&
|
|
102
198
|
patch.path[patch.path.length - 1] === 'length') {
|
|
103
|
-
const parentPath =
|
|
199
|
+
const parentPath = pathToKey(patch.path.slice(0, -1));
|
|
104
200
|
arrayLengths.set(parentPath, patch.value);
|
|
105
201
|
}
|
|
106
202
|
}
|
|
203
|
+
// Use WeakSet to track canceled patches by reference (no string allocation)
|
|
204
|
+
const canceledPatches = new WeakSet();
|
|
107
205
|
// Cancel patches at indices >= final length
|
|
108
206
|
for (const patch of patches) {
|
|
109
207
|
if (!Array.isArray(patch.path) || patch.path.length < 2) {
|
|
110
208
|
continue;
|
|
111
209
|
}
|
|
112
210
|
const lastPath = patch.path[patch.path.length - 1];
|
|
113
|
-
const parentPath =
|
|
211
|
+
const parentPath = pathToKey(patch.path.slice(0, -1));
|
|
114
212
|
if (typeof lastPath === 'number' && arrayLengths.has(parentPath)) {
|
|
115
213
|
const length = arrayLengths.get(parentPath);
|
|
116
214
|
if (lastPath >= length) {
|
|
117
|
-
canceledPatches.add(
|
|
215
|
+
canceledPatches.add(patch);
|
|
118
216
|
}
|
|
119
217
|
}
|
|
120
218
|
}
|
|
121
|
-
return patches.filter((patch) => !canceledPatches.has(
|
|
219
|
+
return patches.filter((patch) => !canceledPatches.has(patch));
|
|
122
220
|
}
|
|
221
|
+
// ==================== Patch merging logic (shared) ====================
|
|
123
222
|
/**
|
|
124
223
|
* Merge two patches on the same path
|
|
125
224
|
* Returns the merged patch, or null if they cancel out, or undefined if they can't be merged
|
package/dist/optimizer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"optimizer.js","sourceRoot":"","sources":["../src/optimizer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"optimizer.js","sourceRoot":"","sources":["../src/optimizer.ts"],"names":[],"mappings":"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"}
|
package/dist/patches.d.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import type { RecorderState } from './types.js';
|
|
1
|
+
import type { NonPrimitive, PatchPath, RecorderState } from './types.js';
|
|
2
2
|
/**
|
|
3
3
|
* Generate a replace patch for property changes
|
|
4
4
|
*/
|
|
5
|
-
export declare function generateSetPatch(state: RecorderState<
|
|
5
|
+
export declare function generateSetPatch(state: RecorderState<NonPrimitive>, path: PatchPath, oldValue: unknown, newValue: unknown): void;
|
|
6
6
|
/**
|
|
7
7
|
* Generate a remove patch for property deletions
|
|
8
8
|
*/
|
|
9
|
-
export declare function generateDeletePatch(state: RecorderState<
|
|
9
|
+
export declare function generateDeletePatch(state: RecorderState<NonPrimitive>, path: PatchPath, oldValue: unknown): void;
|
|
10
10
|
/**
|
|
11
11
|
* Generate an add patch for new properties
|
|
12
12
|
*/
|
|
13
|
-
export declare function generateAddPatch(state: RecorderState<any>, path:
|
|
13
|
+
export declare function generateAddPatch(state: RecorderState<any>, path: PatchPath, value: any): void;
|
|
14
14
|
/**
|
|
15
15
|
* Generate a replace patch for full object/array replacement
|
|
16
16
|
*/
|
|
17
|
-
export declare function generateReplacePatch(state: RecorderState<any>, path:
|
|
17
|
+
export declare function generateReplacePatch(state: RecorderState<any>, path: PatchPath, value: unknown, oldValue?: unknown): void;
|
|
18
18
|
//# sourceMappingURL=patches.d.ts.map
|
package/dist/patches.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"patches.d.ts","sourceRoot":"","sources":["../src/patches.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,YAAY,CAAC;
|
|
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"}
|
package/dist/patches.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Operation } from './types.js';
|
|
2
|
-
import {
|
|
2
|
+
import { cloneIfNeeded, findGetItemIdFn } from './utils.js';
|
|
3
3
|
/**
|
|
4
4
|
* Generate a replace patch for property changes
|
|
5
5
|
*/
|
|
6
6
|
export function generateSetPatch(state, path, oldValue, newValue) {
|
|
7
7
|
const patch = {
|
|
8
8
|
op: Operation.Replace,
|
|
9
|
-
path
|
|
9
|
+
path,
|
|
10
10
|
value: cloneIfNeeded(newValue),
|
|
11
11
|
};
|
|
12
12
|
// Add id if getItemId is configured for this path
|
|
@@ -25,7 +25,7 @@ export function generateSetPatch(state, path, oldValue, newValue) {
|
|
|
25
25
|
export function generateDeletePatch(state, path, oldValue) {
|
|
26
26
|
const patch = {
|
|
27
27
|
op: Operation.Remove,
|
|
28
|
-
path:
|
|
28
|
+
path: path,
|
|
29
29
|
};
|
|
30
30
|
// Add id if getItemId is configured for this path
|
|
31
31
|
const getItemIdFn = findGetItemIdFn(path, state.options.getItemId);
|
|
@@ -43,7 +43,7 @@ export function generateDeletePatch(state, path, oldValue) {
|
|
|
43
43
|
export function generateAddPatch(state, path, value) {
|
|
44
44
|
const patch = {
|
|
45
45
|
op: Operation.Add,
|
|
46
|
-
path
|
|
46
|
+
path,
|
|
47
47
|
value: cloneIfNeeded(value),
|
|
48
48
|
};
|
|
49
49
|
state.patches.push(patch);
|
|
@@ -54,7 +54,7 @@ export function generateAddPatch(state, path, value) {
|
|
|
54
54
|
export function generateReplacePatch(state, path, value, oldValue) {
|
|
55
55
|
const patch = {
|
|
56
56
|
op: Operation.Replace,
|
|
57
|
-
path:
|
|
57
|
+
path: path,
|
|
58
58
|
value: cloneIfNeeded(value),
|
|
59
59
|
};
|
|
60
60
|
// Add id if getItemId is configured for this path
|
package/dist/patches.js.map
CHANGED
|
@@ -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,
|
|
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"}
|
package/dist/proxy.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { RecorderState } from './types.js';
|
|
2
|
-
export declare function createProxy<T extends object>(target: T, path:
|
|
1
|
+
import type { PatchPath, RecorderState } from './types.js';
|
|
2
|
+
export declare function createProxy<T extends object>(target: T, path: PatchPath, state: RecorderState<any>): T;
|
|
3
3
|
//# sourceMappingURL=proxy.d.ts.map
|
package/dist/proxy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,YAAY,CAAC;
|
|
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"}
|
package/dist/proxy.js
CHANGED
|
@@ -4,6 +4,11 @@ import { handleArrayGet } from './arrays.js';
|
|
|
4
4
|
import { handleMapGet } from './maps.js';
|
|
5
5
|
import { handleSetGet } from './sets.js';
|
|
6
6
|
export function createProxy(target, path, state) {
|
|
7
|
+
// Check cache first
|
|
8
|
+
const cached = state.proxyCache.get(target);
|
|
9
|
+
if (cached) {
|
|
10
|
+
return cached;
|
|
11
|
+
}
|
|
7
12
|
const isArrayType = isArray(target);
|
|
8
13
|
const isMapType = isMap(target);
|
|
9
14
|
const isSetType = isSet(target);
|
|
@@ -27,12 +32,8 @@ export function createProxy(target, path, state) {
|
|
|
27
32
|
if (typeof value !== 'object' || value === null) {
|
|
28
33
|
return value;
|
|
29
34
|
}
|
|
30
|
-
// Create nested proxy for draftable values
|
|
31
|
-
|
|
32
|
-
if (typeof prop === 'string' || typeof prop === 'number') {
|
|
33
|
-
return createProxy(value, [...path, prop], state);
|
|
34
|
-
}
|
|
35
|
-
return value;
|
|
35
|
+
// Create nested proxy for all draftable values
|
|
36
|
+
return createProxy(value, [...path, prop], state);
|
|
36
37
|
},
|
|
37
38
|
set(obj, prop, value) {
|
|
38
39
|
// Map and Set don't support direct property assignment
|
|
@@ -40,58 +41,31 @@ export function createProxy(target, path, state) {
|
|
|
40
41
|
throw new Error('Map/Set draft does not support any property assignment.');
|
|
41
42
|
}
|
|
42
43
|
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
44
|
// Convert numeric string props to numbers for array indices
|
|
49
45
|
const propForPath = typeof prop === 'string' && !isNaN(Number(prop)) ? Number(prop) : prop;
|
|
50
46
|
const propPath = [...path, propForPath];
|
|
47
|
+
// Check if property actually exists (for no-op detection)
|
|
48
|
+
const actuallyHasProperty = Object.prototype.hasOwnProperty.call(obj, prop);
|
|
49
|
+
// For add vs replace distinction: check array bounds for arrays
|
|
50
|
+
// Index within bounds = replace, out of bounds = add
|
|
51
|
+
let hadProperty = actuallyHasProperty;
|
|
52
|
+
if (isArrayType && typeof propForPath === 'number') {
|
|
53
|
+
hadProperty = propForPath >= 0 && propForPath < obj.length;
|
|
54
|
+
}
|
|
51
55
|
// Skip if no actual change (handle undefined as a valid value)
|
|
52
56
|
// Use Object.is to correctly handle NaN (NaN !== NaN, but Object.is(NaN, NaN) === true)
|
|
53
|
-
|
|
54
|
-
|
|
57
|
+
// Use actuallyHasProperty for no-op detection (sparse array hole is different from undefined)
|
|
58
|
+
if (Object.is(oldValue, value) && (value !== undefined || actuallyHasProperty)) {
|
|
55
59
|
return true;
|
|
56
60
|
}
|
|
57
|
-
// Determine if this is an add or replace operation by checking the original state
|
|
58
|
-
let originalHasProperty = false;
|
|
59
|
-
let originalValue = undefined;
|
|
60
|
-
// Navigate to the original object at this path
|
|
61
|
-
let currentOriginal = state.original;
|
|
62
|
-
for (let i = 0; i < path.length; i++) {
|
|
63
|
-
currentOriginal = currentOriginal[path[i]];
|
|
64
|
-
if (currentOriginal === undefined || currentOriginal === null) {
|
|
65
|
-
break;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
if (currentOriginal && currentOriginal !== undefined && currentOriginal !== null) {
|
|
69
|
-
// For arrays, check if the index is within the array length (handles sparse arrays correctly)
|
|
70
|
-
if (Array.isArray(currentOriginal)) {
|
|
71
|
-
// Convert prop to number if it's a numeric string
|
|
72
|
-
const index = typeof prop === 'string' && !isNaN(Number(prop)) ? Number(prop) : prop;
|
|
73
|
-
if (typeof index === 'number') {
|
|
74
|
-
originalHasProperty = index >= 0 && index < currentOriginal.length;
|
|
75
|
-
originalValue = currentOriginal[index];
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
originalHasProperty = Object.prototype.hasOwnProperty.call(currentOriginal, prop);
|
|
79
|
-
originalValue = currentOriginal[prop];
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
originalHasProperty = Object.prototype.hasOwnProperty.call(currentOriginal, prop);
|
|
84
|
-
originalValue = currentOriginal[prop];
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
61
|
// Mutate original immediately
|
|
88
62
|
obj[prop] = value;
|
|
89
|
-
// Generate patch
|
|
90
|
-
if (!
|
|
63
|
+
// Generate patch - use pre-mutation property existence check
|
|
64
|
+
if (!hadProperty) {
|
|
91
65
|
generateAddPatch(state, propPath, value);
|
|
92
66
|
}
|
|
93
67
|
else {
|
|
94
|
-
generateSetPatch(state, propPath,
|
|
68
|
+
generateSetPatch(state, propPath, oldValue, value);
|
|
95
69
|
}
|
|
96
70
|
return true;
|
|
97
71
|
},
|
|
@@ -105,11 +79,6 @@ export function createProxy(target, path, state) {
|
|
|
105
79
|
throw new Error('Map/Set draft does not support deleteProperty.');
|
|
106
80
|
}
|
|
107
81
|
const oldValue = obj[prop];
|
|
108
|
-
// Only create path for string | number props, skip symbols
|
|
109
|
-
if (typeof prop !== 'string' && typeof prop !== 'number') {
|
|
110
|
-
delete obj[prop];
|
|
111
|
-
return true;
|
|
112
|
-
}
|
|
113
82
|
const propPath = [...path, prop];
|
|
114
83
|
if (oldValue !== undefined || Object.prototype.hasOwnProperty.call(obj, prop)) {
|
|
115
84
|
delete obj[prop];
|
|
@@ -138,6 +107,9 @@ export function createProxy(target, path, state) {
|
|
|
138
107
|
return Reflect.getPrototypeOf(obj);
|
|
139
108
|
},
|
|
140
109
|
};
|
|
141
|
-
|
|
110
|
+
const proxy = new Proxy(target, handler);
|
|
111
|
+
// Store in cache
|
|
112
|
+
state.proxyCache.set(target, proxy);
|
|
113
|
+
return proxy;
|
|
142
114
|
}
|
|
143
115
|
//# sourceMappingURL=proxy.js.map
|
package/dist/proxy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,gBAAgB,EAAE,mBAAmB,EAAE,gBAAgB,EAAC,MAAM,cAAc,CAAC;AACrF,OAAO,EAAC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAC,MAAM,YAAY,CAAC;AACjD,OAAO,EAAC,cAAc,EAAC,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAC,YAAY,EAAC,MAAM,WAAW,CAAC;AACvC,OAAO,EAAC,YAAY,EAAC,MAAM,WAAW,CAAC;AAEvC,MAAM,UAAU,WAAW,CAC1B,MAAS,EACT,
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"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"}
|
package/dist/sets.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { RecorderState } from './types.js';
|
|
1
|
+
import type { PatchPath, RecorderState } from './types.js';
|
|
2
2
|
/**
|
|
3
3
|
* Handle property access on Set objects
|
|
4
4
|
* Wraps mutating methods (add, delete, clear) to generate patches
|
|
5
5
|
*/
|
|
6
|
-
export declare function handleSetGet
|
|
6
|
+
export declare function handleSetGet(obj: Set<any>, prop: string | symbol, path: PatchPath, state: RecorderState<any>): any;
|
|
7
7
|
//# sourceMappingURL=sets.d.ts.map
|
package/dist/sets.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sets.d.ts","sourceRoot":"","sources":["../src/sets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"sets.d.ts","sourceRoot":"","sources":["../src/sets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,SAAS,EAAE,aAAa,EAAC,MAAM,YAAY,CAAC;AAIzD;;;GAGG;AACH,wBAAgB,YAAY,CAC3B,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,EACb,IAAI,EAAE,MAAM,GAAG,MAAM,EACrB,IAAI,EAAE,SAAS,EACf,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,GACvB,GAAG,CAkEL"}
|
package/dist/sets.js
CHANGED
|
@@ -5,15 +5,16 @@ import { cloneIfNeeded } from './utils.js';
|
|
|
5
5
|
* Wraps mutating methods (add, delete, clear) to generate patches
|
|
6
6
|
*/
|
|
7
7
|
export function handleSetGet(obj, prop, path, state) {
|
|
8
|
-
//
|
|
8
|
+
// Handle symbol properties - return the property value directly
|
|
9
|
+
// Symbol methods like Symbol.iterator should work normally
|
|
9
10
|
if (typeof prop === 'symbol') {
|
|
10
11
|
return obj[prop];
|
|
11
12
|
}
|
|
12
13
|
// Mutating methods
|
|
13
14
|
if (prop === 'add') {
|
|
14
15
|
return (value) => {
|
|
15
|
-
// Check if value
|
|
16
|
-
const existed =
|
|
16
|
+
// Check if value exists BEFORE mutation (current state, not original)
|
|
17
|
+
const existed = obj.has(value);
|
|
17
18
|
const result = obj.add(value);
|
|
18
19
|
// Generate patch only if value didn't exist
|
|
19
20
|
if (!existed) {
|
|
@@ -58,21 +59,4 @@ export function handleSetGet(obj, prop, path, state) {
|
|
|
58
59
|
// Return any other property
|
|
59
60
|
return obj[prop];
|
|
60
61
|
}
|
|
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
62
|
//# sourceMappingURL=sets.js.map
|
package/dist/sets.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sets.js","sourceRoot":"","sources":["../src/sets.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sets.js","sourceRoot":"","sources":["../src/sets.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,gBAAgB,EAAE,mBAAmB,EAAC,MAAM,cAAc,CAAC;AACnE,OAAO,EAAC,aAAa,EAAC,MAAM,YAAY,CAAC;AAEzC;;;GAGG;AACH,MAAM,UAAU,YAAY,CAC3B,GAAa,EACb,IAAqB,EACrB,IAAe,EACf,KAAyB;IAEzB,gEAAgE;IAChE,2DAA2D;IAC3D,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,KAAU,EAAE,EAAE;YACrB,sEAAsE;YACtE,MAAM,OAAO,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAC/B,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,KAAU,EAAE,EAAE;YACrB,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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -4,16 +4,6 @@ export declare const Operation: {
|
|
|
4
4
|
readonly Add: "add";
|
|
5
5
|
};
|
|
6
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
7
|
/**
|
|
18
8
|
* Function that extracts an ID from an item value
|
|
19
9
|
*/
|
|
@@ -24,7 +14,9 @@ export type GetItemIdFunction = (value: any) => string | number | undefined | nu
|
|
|
24
14
|
export type GetItemIdConfig = {
|
|
25
15
|
[key: string]: GetItemIdFunction | GetItemIdConfig;
|
|
26
16
|
};
|
|
27
|
-
export
|
|
17
|
+
export type PatchPath = (string | number | symbol | object)[];
|
|
18
|
+
export type Patch = {
|
|
19
|
+
path: PatchPath;
|
|
28
20
|
op: PatchOp;
|
|
29
21
|
value?: any;
|
|
30
22
|
/**
|
|
@@ -32,23 +24,10 @@ export interface IPatch {
|
|
|
32
24
|
* Populated when getItemId option is configured for the item's parent path.
|
|
33
25
|
*/
|
|
34
26
|
id?: string | number;
|
|
35
|
-
}
|
|
36
|
-
export type Patch<P extends PatchesOptions = true> = P extends {
|
|
37
|
-
pathAsArray: false;
|
|
38
|
-
} ? IPatch & {
|
|
39
|
-
path: string;
|
|
40
|
-
} : P extends true | object ? IPatch & {
|
|
41
|
-
path: (string | number)[];
|
|
42
|
-
} : IPatch & {
|
|
43
|
-
path: string | (string | number)[];
|
|
44
27
|
};
|
|
45
|
-
export type Patches
|
|
28
|
+
export type Patches = Patch[];
|
|
46
29
|
export type NonPrimitive = object | Array<unknown>;
|
|
47
30
|
export interface RecordPatchesOptions {
|
|
48
|
-
/**
|
|
49
|
-
* Return paths as arrays (default: true) or strings
|
|
50
|
-
*/
|
|
51
|
-
pathAsArray?: boolean;
|
|
52
31
|
/**
|
|
53
32
|
* Include array length in patches (default: true)
|
|
54
33
|
*/
|
|
@@ -76,13 +55,15 @@ export interface RecordPatchesOptions {
|
|
|
76
55
|
*/
|
|
77
56
|
getItemId?: GetItemIdConfig;
|
|
78
57
|
}
|
|
79
|
-
export type Draft<T> = T;
|
|
80
|
-
export interface RecorderState<T> {
|
|
81
|
-
|
|
82
|
-
patches: Patches
|
|
83
|
-
basePath:
|
|
84
|
-
options: RecordPatchesOptions
|
|
85
|
-
|
|
86
|
-
|
|
58
|
+
export type Draft<T extends NonPrimitive> = T;
|
|
59
|
+
export interface RecorderState<T extends NonPrimitive> {
|
|
60
|
+
state: T;
|
|
61
|
+
patches: Patches;
|
|
62
|
+
basePath: PatchPath;
|
|
63
|
+
options: RecordPatchesOptions;
|
|
64
|
+
/**
|
|
65
|
+
* Cache for proxies to avoid creating new ones on repeated property access
|
|
66
|
+
*/
|
|
67
|
+
proxyCache: WeakMap<object, any>;
|
|
87
68
|
}
|
|
88
69
|
//# sourceMappingURL=types.d.ts.map
|