j-templates 8.1.2 → 8.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/SYNTAX_PRIMER.md +3 -4
- package/Store/Diff/diffTree.d.ts +65 -34
- package/Store/Diff/diffTree.js +528 -417
- package/Store/Diff/diffTree.types.d.ts +5 -79
- package/Store/Diff/diffTree.types.js +1 -3
- package/Store/Diff/diffTreeWorker.d.ts +4 -0
- package/Store/Diff/diffTreeWorker.js +17 -39
- package/Store/Diff/diffTreeWriter.d.ts +27 -38
- package/Store/Diff/diffTreeWriter.js +44 -95
- package/Store/Diff/index.d.ts +1 -0
- package/Store/Diff/index.js +1 -0
- package/Store/Diff/utils/diffTree.types.d.ts +108 -0
- package/Store/Diff/utils/diffTree.types.js +1 -0
- package/Store/Diff/utils/diffTree.utils.d.ts +79 -0
- package/Store/Diff/utils/diffTree.utils.js +398 -0
- package/Store/Store/pushStore.d.ts +1 -5
- package/Store/Store/pushStore.js +3 -22
- package/Store/Store/store.d.ts +2 -4
- package/Store/Store/store.js +12 -11
- package/Store/Store/storeAsync.d.ts +4 -5
- package/Store/Store/storeAsync.js +12 -30
- package/Store/Store/storeSync.d.ts +14 -9
- package/Store/Store/storeSync.js +24 -19
- package/Store/Tree/observableNode.d.ts +2 -23
- package/Store/Tree/observableNode.js +41 -181
- package/Store/Tree/snapshot.d.ts +70 -0
- package/Store/Tree/snapshot.js +141 -0
- package/Utils/json.d.ts +37 -7
- package/Utils/json.js +151 -13
- package/package.json +1 -1
- package/Store/Diff/diffSync.d.ts +0 -36
- package/Store/Diff/diffSync.js +0 -43
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { JsonType } from "../../Utils/json";
|
|
2
|
+
function CreateSnapshotLink(state, child, parent) {
|
|
3
|
+
let parents = state.hierarchy.get(child);
|
|
4
|
+
if (!parents)
|
|
5
|
+
state.hierarchy.set(child, (parents = new Set()));
|
|
6
|
+
parents.add(parent);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Clears the cached snapshot for a raw value that was just written to, and climbs to
|
|
10
|
+
* every parent whose own cached snapshot embedded it, so a write to a deeply nested value
|
|
11
|
+
* invalidates every cached ancestor that still holds a snapshot.
|
|
12
|
+
*/
|
|
13
|
+
function InvalidateValue(state, value) {
|
|
14
|
+
state.rawToSnapshotCache.delete(value);
|
|
15
|
+
const parents = state.hierarchy.get(value);
|
|
16
|
+
if (parents === undefined)
|
|
17
|
+
return;
|
|
18
|
+
state.hierarchy.delete(value);
|
|
19
|
+
for (const parent of parents)
|
|
20
|
+
if (state.rawToSnapshotCache.has(parent))
|
|
21
|
+
InvalidateValue(state, parent);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* An immutable snapshot of a raw value (arrays and plain objects; other values are
|
|
25
|
+
* returned as they are). A snapshot is cached per raw value and returned as-is until a
|
|
26
|
+
* write invalidates it. A rebuild makes new containers but reuses the cached snapshots of
|
|
27
|
+
* unchanged children, so a snapshot handed out never changes and unchanged parts are
|
|
28
|
+
* shared between snapshots. Keyed children are read through their root.
|
|
29
|
+
*/
|
|
30
|
+
function CreateSnapshot(state, resolve, value, path) {
|
|
31
|
+
if (JsonType(value) === "value")
|
|
32
|
+
return value;
|
|
33
|
+
const cached = state.rawToSnapshotCache.get(value);
|
|
34
|
+
if (cached !== undefined)
|
|
35
|
+
return cached;
|
|
36
|
+
let snapshot;
|
|
37
|
+
if (Array.isArray(value)) {
|
|
38
|
+
snapshot = new Array(value.length);
|
|
39
|
+
for (let x = 0; x < value.length; x++)
|
|
40
|
+
snapshot[x] = ChildSnapshot(state, resolve, value, x, path);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
snapshot = {};
|
|
44
|
+
const keys = Object.keys(value);
|
|
45
|
+
for (let x = 0; x < keys.length; x++)
|
|
46
|
+
snapshot[keys[x]] = ChildSnapshot(state, resolve, value, keys[x], path);
|
|
47
|
+
}
|
|
48
|
+
state.rawToSnapshotCache.set(value, snapshot);
|
|
49
|
+
return snapshot;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* A child's snapshot, linking the child to its parent so a write to the child
|
|
53
|
+
* invalidates the parent. A keyed child's snapshot comes from its root, so the root is
|
|
54
|
+
* linked too; the parent's own embedded copy stays linked because a positional write
|
|
55
|
+
* (one that changes which entity a slot holds) mutates that copy in place.
|
|
56
|
+
*/
|
|
57
|
+
function ChildSnapshot(state, resolve, parent, key, path) {
|
|
58
|
+
const child = parent[key];
|
|
59
|
+
if (JsonType(child) === "value")
|
|
60
|
+
return child;
|
|
61
|
+
CreateSnapshotLink(state, child, parent);
|
|
62
|
+
path.push(key);
|
|
63
|
+
try {
|
|
64
|
+
const resolved = resolve?.(child, path);
|
|
65
|
+
if (resolved !== undefined && resolved.value !== child) {
|
|
66
|
+
CreateSnapshotLink(state, resolved.value, parent);
|
|
67
|
+
return CreateSnapshot(state, resolve, resolved.value, resolved.path);
|
|
68
|
+
}
|
|
69
|
+
return CreateSnapshot(state, resolve, child, path);
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
path.pop();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function RegisterSnapshot(state, snapshot) {
|
|
76
|
+
if (JsonType(snapshot) !== 'value')
|
|
77
|
+
state.rawToSnapshotCache.set(snapshot, snapshot);
|
|
78
|
+
}
|
|
79
|
+
export var Snapshot;
|
|
80
|
+
(function (Snapshot) {
|
|
81
|
+
/**
|
|
82
|
+
* Creates a new, empty snapshot cache.
|
|
83
|
+
* @param resolve Optional default resolver for keyed children.
|
|
84
|
+
* @returns A new snapshot state.
|
|
85
|
+
*/
|
|
86
|
+
function Create(resolve) {
|
|
87
|
+
return {
|
|
88
|
+
rawToSnapshotCache: new WeakMap(),
|
|
89
|
+
hierarchy: new WeakMap(),
|
|
90
|
+
resolve,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
Snapshot.Create = Create;
|
|
94
|
+
/**
|
|
95
|
+
* Returns an immutable, cached snapshot of a raw value. The same snapshot is returned
|
|
96
|
+
* until a write invalidates it, and unchanged nested parts are shared between snapshots,
|
|
97
|
+
* so `===` holds for any part that hasn't changed.
|
|
98
|
+
* @param state The snapshot cache to read from and populate.
|
|
99
|
+
* @param value The raw value to snapshot.
|
|
100
|
+
* @param resolve Resolver for keyed children; defaults to the state's resolver.
|
|
101
|
+
* @param path The value's own path. Snapshots are cached per raw value, so a value must
|
|
102
|
+
* always be seeded with the same path or a resolver may see a different one.
|
|
103
|
+
* @returns The snapshot.
|
|
104
|
+
*/
|
|
105
|
+
function Get(state, value, resolve = state.resolve, path = []) {
|
|
106
|
+
return CreateSnapshot(state, resolve, value, path.slice());
|
|
107
|
+
}
|
|
108
|
+
Snapshot.Get = Get;
|
|
109
|
+
/**
|
|
110
|
+
* Invalidates the cached snapshot of a raw value that was just written to, along with
|
|
111
|
+
* every cached ancestor that embedded it.
|
|
112
|
+
* @param state The snapshot cache to invalidate.
|
|
113
|
+
* @param value The raw value that was written to.
|
|
114
|
+
*/
|
|
115
|
+
function Invalidate(state, value) {
|
|
116
|
+
InvalidateValue(state, value);
|
|
117
|
+
}
|
|
118
|
+
Snapshot.Invalidate = Invalidate;
|
|
119
|
+
/**
|
|
120
|
+
* The cached snapshot of a raw value, without building one. A write to the value, or to
|
|
121
|
+
* anything its snapshot embeds, clears the cache, so a reader that kept the snapshot it got
|
|
122
|
+
* can tell nothing under the value changed when this returns that same snapshot.
|
|
123
|
+
* @param state The snapshot cache.
|
|
124
|
+
* @param value The raw value.
|
|
125
|
+
* @returns The cached snapshot, or undefined when there's none.
|
|
126
|
+
*/
|
|
127
|
+
function Peek(state, value) {
|
|
128
|
+
return state.rawToSnapshotCache.get(value);
|
|
129
|
+
}
|
|
130
|
+
Snapshot.Peek = Peek;
|
|
131
|
+
/**
|
|
132
|
+
* Registers a value as its own snapshot. Use in a case where an immutable value can
|
|
133
|
+
* represent itself as a valid snapshot without cloning.
|
|
134
|
+
* @param state The snapshot cache.
|
|
135
|
+
* @param value The raw value that is its own snapshot.
|
|
136
|
+
*/
|
|
137
|
+
function Register(state, value) {
|
|
138
|
+
RegisterSnapshot(state, value);
|
|
139
|
+
}
|
|
140
|
+
Snapshot.Register = Register;
|
|
141
|
+
})(Snapshot || (Snapshot = {}));
|
package/Utils/json.d.ts
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
|
+
export type JsonWrite = {
|
|
2
|
+
type: "write";
|
|
3
|
+
path: (string | number)[];
|
|
4
|
+
value: unknown;
|
|
5
|
+
};
|
|
6
|
+
export type JsonMove = {
|
|
7
|
+
type: "move";
|
|
8
|
+
path: (string | number)[];
|
|
9
|
+
sourceProp: string | number;
|
|
10
|
+
targetProp: string | number;
|
|
11
|
+
};
|
|
1
12
|
/**
|
|
2
13
|
* Result of a JSON diff operation, containing paths and values that changed.
|
|
3
14
|
* @template T - The type of the JSON value being diffed
|
|
4
15
|
*/
|
|
5
|
-
export type JsonDiffResult<T = unknown> =
|
|
6
|
-
/** Array path segments (strings for object keys, numbers for array indices) */
|
|
7
|
-
path: (string | number)[];
|
|
8
|
-
/** The new value at this path */
|
|
9
|
-
value: unknown;
|
|
10
|
-
}[];
|
|
16
|
+
export type JsonDiffResult<T = unknown> = (JsonMove | JsonWrite)[];
|
|
11
17
|
/**
|
|
12
18
|
* Determines the JSON type of a value.
|
|
13
19
|
* @param value - The value to check
|
|
@@ -31,9 +37,33 @@ export declare function JsonMerge(source: unknown, patch: unknown): unknown;
|
|
|
31
37
|
* @returns A deep clone of the value
|
|
32
38
|
*/
|
|
33
39
|
export declare function JsonDeepClone<T>(value: T, type?: string): T;
|
|
40
|
+
/**
|
|
41
|
+
* Applies a diff result to a root value in place: moves first, then writes.
|
|
42
|
+
* @param resolve - Returns the object to walk into for `parent[prop]`; the walk stores it back at
|
|
43
|
+
* `parent[prop]` when it's a different object
|
|
44
|
+
* @param assign - Assigns a written value (already cloned) to its parent
|
|
45
|
+
* @param move - Assigns a moved value to its new slot. A move relocates a value that's already in
|
|
46
|
+
* the root, so it's kept separate from `assign`, which handles new values.
|
|
47
|
+
*/
|
|
48
|
+
export declare function JsonApplyDiff(root: any, diff: JsonDiffResult, assign?: (parent: any, prop: string | number, value: any) => void): void;
|
|
49
|
+
/**
|
|
50
|
+
* Applies a diff result to a root value in place. A diff doesn't own its values (see JsonDiff),
|
|
51
|
+
* so each value is deep-cloned before it's written: the root never shares an object with the
|
|
52
|
+
* diff, the value it was computed from, or another record.
|
|
53
|
+
* - A single record with an empty path replaces the root's contents, keeping its identity
|
|
54
|
+
* - Otherwise each record's value is assigned at its path
|
|
55
|
+
* @param root - The value to update; must be an object or array
|
|
56
|
+
* @param diff - The diff result to apply
|
|
57
|
+
* @param callback - Called with the object written to, the property written ("" when an array
|
|
58
|
+
* root is replaced), and whether that property is new to the object
|
|
59
|
+
* @throws If a root replacement would change the root's JSON type, or the root is a primitive
|
|
60
|
+
*/
|
|
61
|
+
export declare function JsonApplyWrites(root: any, diff: JsonWrite[], assign?: (parent: any, prop: string | number, value: any) => void): void;
|
|
34
62
|
/**
|
|
35
63
|
* Computes the differences between two JSON values.
|
|
36
|
-
* Returns an array of paths and values that changed from oldValue to newValue.
|
|
64
|
+
* Returns an array of paths and values that changed from oldValue to newValue. A record doesn't
|
|
65
|
+
* own its value: it references `newValue`'s objects, so two records can share one, and
|
|
66
|
+
* JsonApplyDiff clones each value as it's applied.
|
|
37
67
|
* @template T - The type of the JSON values being compared
|
|
38
68
|
* @param newValue - The new value
|
|
39
69
|
* @param oldValue - The old value to compare against
|
package/Utils/json.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ArraysEqual } from "./array";
|
|
1
2
|
const jsonProto = Object.getPrototypeOf({});
|
|
2
3
|
const arrayProto = Object.getPrototypeOf([]);
|
|
3
4
|
const strProto = Object.getPrototypeOf("");
|
|
@@ -94,9 +95,124 @@ export function JsonDeepClone(value, type = JsonType(value)) {
|
|
|
94
95
|
return value;
|
|
95
96
|
}
|
|
96
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* Applies a diff result to a root value in place: moves first, then writes.
|
|
100
|
+
* @param resolve - Returns the object to walk into for `parent[prop]`; the walk stores it back at
|
|
101
|
+
* `parent[prop]` when it's a different object
|
|
102
|
+
* @param assign - Assigns a written value (already cloned) to its parent
|
|
103
|
+
* @param move - Assigns a moved value to its new slot. A move relocates a value that's already in
|
|
104
|
+
* the root, so it's kept separate from `assign`, which handles new values.
|
|
105
|
+
*/
|
|
106
|
+
export function JsonApplyDiff(root, diff,
|
|
107
|
+
/* resolve?: (parent: any, prop: string | number) => any, */
|
|
108
|
+
assign) {
|
|
109
|
+
const moves = diff.filter(function (diff) {
|
|
110
|
+
return diff.type === "move";
|
|
111
|
+
});
|
|
112
|
+
JsonApplyMoves(root, moves, assign);
|
|
113
|
+
const writes = diff.filter(function (diff) {
|
|
114
|
+
return diff.type === "write";
|
|
115
|
+
});
|
|
116
|
+
JsonApplyWrites(root, writes, assign);
|
|
117
|
+
}
|
|
118
|
+
function DefaultAssign(parent, prop, value) {
|
|
119
|
+
parent[prop] = value;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Applies a diff result to a root value in place. A diff doesn't own its values (see JsonDiff),
|
|
123
|
+
* so each value is deep-cloned before it's written: the root never shares an object with the
|
|
124
|
+
* diff, the value it was computed from, or another record.
|
|
125
|
+
* - A single record with an empty path replaces the root's contents, keeping its identity
|
|
126
|
+
* - Otherwise each record's value is assigned at its path
|
|
127
|
+
* @param root - The value to update; must be an object or array
|
|
128
|
+
* @param diff - The diff result to apply
|
|
129
|
+
* @param callback - Called with the object written to, the property written ("" when an array
|
|
130
|
+
* root is replaced), and whether that property is new to the object
|
|
131
|
+
* @throws If a root replacement would change the root's JSON type, or the root is a primitive
|
|
132
|
+
*/
|
|
133
|
+
export function JsonApplyWrites(root, diff, assign = DefaultAssign) {
|
|
134
|
+
const pathTuples = [["", root]];
|
|
135
|
+
if (diff.length === 1 && diff[0].path.length === 0) {
|
|
136
|
+
const diffRow = diff[0];
|
|
137
|
+
const diffPatch = JsonDeepClone(diffRow.value);
|
|
138
|
+
const type = JsonType(root);
|
|
139
|
+
const patchType = JsonType(diffPatch);
|
|
140
|
+
if (type !== patchType)
|
|
141
|
+
throw new Error("Unable to change type of root value");
|
|
142
|
+
switch (type) {
|
|
143
|
+
case "array": {
|
|
144
|
+
root.splice(0, root.length, ...diffPatch);
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
case "object": {
|
|
148
|
+
const keys = Object.keys(root);
|
|
149
|
+
const patchKeys = Object.keys(diffPatch);
|
|
150
|
+
for (let x = 0; x < keys.length; x++)
|
|
151
|
+
if (!patchKeys.includes(keys[x]))
|
|
152
|
+
delete root[keys[x]];
|
|
153
|
+
Object.assign(root, diffPatch);
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
case "value":
|
|
157
|
+
throw new Error("Unable to replace root value type: " + root);
|
|
158
|
+
}
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
for (let x = 0; x < diff.length; x++) {
|
|
162
|
+
const { path, value } = diff[x];
|
|
163
|
+
let y = 0;
|
|
164
|
+
for (; y < path.length - 1; y++) {
|
|
165
|
+
const property = path[y];
|
|
166
|
+
const tupleIndex = y + 1;
|
|
167
|
+
if (tupleIndex >= pathTuples.length || pathTuples[tupleIndex][0] !== property) {
|
|
168
|
+
const parent = pathTuples[y][1];
|
|
169
|
+
const child = parent[property];
|
|
170
|
+
if (tupleIndex < pathTuples.length) {
|
|
171
|
+
pathTuples[tupleIndex] = [property, child];
|
|
172
|
+
const next = tupleIndex + 1;
|
|
173
|
+
if (next < pathTuples.length)
|
|
174
|
+
pathTuples[next][0] = null;
|
|
175
|
+
}
|
|
176
|
+
else
|
|
177
|
+
pathTuples.push([property, child]);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (y >= path.length - 1) {
|
|
181
|
+
const assignValue = pathTuples[y][1];
|
|
182
|
+
const assignData = JsonDeepClone(value);
|
|
183
|
+
assign(assignValue, path[y], assignData);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
function ReadPath(value, path) {
|
|
188
|
+
let curr = value;
|
|
189
|
+
let x = 0;
|
|
190
|
+
for (; curr && x < path.length; x++)
|
|
191
|
+
curr = curr[path[x]];
|
|
192
|
+
return curr;
|
|
193
|
+
}
|
|
194
|
+
function JsonApplyMoves(root, diff, move = DefaultAssign) {
|
|
195
|
+
if (diff.length === 0)
|
|
196
|
+
return;
|
|
197
|
+
let moveRoot = null;
|
|
198
|
+
let basePath = null;
|
|
199
|
+
let copy = null;
|
|
200
|
+
for (let x = diff.length - 1; x >= 0; x--) {
|
|
201
|
+
if (!ArraysEqual(diff[x].path, basePath)) {
|
|
202
|
+
basePath = diff[x].path;
|
|
203
|
+
moveRoot = ReadPath(root, diff[x].path); //, resolve);
|
|
204
|
+
const type = JsonType(moveRoot);
|
|
205
|
+
copy = type === "array" ? moveRoot.slice() : type === "object" ? Object.assign({}, moveRoot) : root;
|
|
206
|
+
}
|
|
207
|
+
const sourceValue = copy[diff[x].sourceProp];
|
|
208
|
+
move(moveRoot, diff[x].targetProp, sourceValue);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
97
211
|
/**
|
|
98
212
|
* Computes the differences between two JSON values.
|
|
99
|
-
* Returns an array of paths and values that changed from oldValue to newValue.
|
|
213
|
+
* Returns an array of paths and values that changed from oldValue to newValue. A record doesn't
|
|
214
|
+
* own its value: it references `newValue`'s objects, so two records can share one, and
|
|
215
|
+
* JsonApplyDiff clones each value as it's applied.
|
|
100
216
|
* @template T - The type of the JSON values being compared
|
|
101
217
|
* @param newValue - The new value
|
|
102
218
|
* @param oldValue - The old value to compare against
|
|
@@ -108,6 +224,11 @@ export function JsonDiff(newValue, oldValue, rootPath, initResult) {
|
|
|
108
224
|
const result = initResult ?? [];
|
|
109
225
|
const startPath = rootPath ? rootPath.split(".") : [];
|
|
110
226
|
JsonDiffRecursive(startPath, newValue, oldValue, result);
|
|
227
|
+
result.sort(function (a, b) {
|
|
228
|
+
const aNum = a.type === "write" ? 1 : 0;
|
|
229
|
+
const bNum = b.type === "write" ? 1 : 0;
|
|
230
|
+
return aNum - bNum;
|
|
231
|
+
});
|
|
111
232
|
return result;
|
|
112
233
|
}
|
|
113
234
|
/**
|
|
@@ -140,6 +261,7 @@ function JsonDiffRecursive(path, newValue, oldValue, resp) {
|
|
|
140
261
|
if (allChildrenChanged) {
|
|
141
262
|
resp.length > changedPathLength && resp.splice(changedPathLength);
|
|
142
263
|
resp.push({
|
|
264
|
+
type: "write",
|
|
143
265
|
path,
|
|
144
266
|
value: newValue,
|
|
145
267
|
});
|
|
@@ -147,6 +269,7 @@ function JsonDiffRecursive(path, newValue, oldValue, resp) {
|
|
|
147
269
|
}
|
|
148
270
|
return false;
|
|
149
271
|
}
|
|
272
|
+
const MOVE_SYMBOL = Symbol("MOVE_SYMBOL");
|
|
150
273
|
/**
|
|
151
274
|
* Compares two arrays and records differences.
|
|
152
275
|
* @internal
|
|
@@ -160,24 +283,38 @@ function JsonDiffArrays(path, newValue, oldValue, resp) {
|
|
|
160
283
|
if (oldValue.length === 0 || newValue.length === 0) {
|
|
161
284
|
return oldValue.length !== newValue.length;
|
|
162
285
|
}
|
|
163
|
-
let
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
286
|
+
let startIndex = 0;
|
|
287
|
+
for (; startIndex < newValue.length && startIndex < oldValue.length && newValue[startIndex] === oldValue[startIndex]; startIndex++) { }
|
|
288
|
+
// Arrays are equal, no diffing required
|
|
289
|
+
if (startIndex === newValue.length && startIndex === oldValue.length)
|
|
290
|
+
return false;
|
|
291
|
+
const newArraySlice = newValue.slice();
|
|
292
|
+
const oldArraySlice = oldValue.slice();
|
|
293
|
+
for (let x = startIndex; x < oldValue.length; x++) {
|
|
294
|
+
const newIndex = newValue.indexOf(oldValue[x], startIndex);
|
|
295
|
+
if (newIndex >= 0 && newIndex !== x) {
|
|
296
|
+
oldArraySlice[x] = MOVE_SYMBOL;
|
|
297
|
+
newArraySlice[newIndex] = MOVE_SYMBOL;
|
|
298
|
+
resp.push({
|
|
299
|
+
type: "move",
|
|
300
|
+
path: path,
|
|
301
|
+
sourceProp: x,
|
|
302
|
+
targetProp: newIndex
|
|
303
|
+
});
|
|
171
304
|
}
|
|
172
305
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
306
|
+
for (let x = startIndex; x < newValue.length; x++) {
|
|
307
|
+
const arrayPath = path.concat(x);
|
|
308
|
+
if (newArraySlice[x] !== MOVE_SYMBOL)
|
|
309
|
+
JsonDiffRecursive(arrayPath, newArraySlice[x], oldArraySlice[x], resp);
|
|
310
|
+
}
|
|
311
|
+
if (oldValue.length !== newValue.length)
|
|
176
312
|
resp.push({
|
|
313
|
+
type: "write",
|
|
177
314
|
path: path.concat("length"),
|
|
178
315
|
value: newValue.length,
|
|
179
316
|
});
|
|
180
|
-
return
|
|
317
|
+
return false;
|
|
181
318
|
}
|
|
182
319
|
/**
|
|
183
320
|
* Compares two objects and records differences.
|
|
@@ -207,6 +344,7 @@ function JsonDiffObjects(path, newValue, oldValue, resp) {
|
|
|
207
344
|
}
|
|
208
345
|
else if (newValue[newKeys[newKeyIndex]] !== undefined) {
|
|
209
346
|
resp.push({
|
|
347
|
+
type: "write",
|
|
210
348
|
path: childPath,
|
|
211
349
|
value: newValue[newKeys[newKeyIndex]],
|
|
212
350
|
});
|
package/package.json
CHANGED
package/Store/Diff/diffSync.d.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { JsonDiffResult } from "../../Utils/json";
|
|
2
|
-
import { DiffSpliceResult, DiffTreeProjectionMap, IDiffTree } from "./diffTree.types";
|
|
3
|
-
/**
|
|
4
|
-
* Synchronous diff implementation.
|
|
5
|
-
* Computes diffs immediately without queuing or workers.
|
|
6
|
-
*
|
|
7
|
-
* @see StoreSync
|
|
8
|
-
* @see StoreAsync
|
|
9
|
-
*/
|
|
10
|
-
export declare class DiffSync implements IDiffTree {
|
|
11
|
-
private diffTree;
|
|
12
|
-
/**
|
|
13
|
-
* Creates a DiffSync instance.
|
|
14
|
-
* @param keyFunc - Optional function to extract a key from objects
|
|
15
|
-
* @param projections - Optional map of derived-value projections, keyed by id
|
|
16
|
-
*/
|
|
17
|
-
constructor(keyFunc?: {
|
|
18
|
-
(val: any): string;
|
|
19
|
-
}, projections?: DiffTreeProjectionMap);
|
|
20
|
-
/**
|
|
21
|
-
* Computes the diff between a new value and the current value at a path.
|
|
22
|
-
* @param path - Dot-separated path to the value
|
|
23
|
-
* @param value - The new value to compare
|
|
24
|
-
* @returns Diff results showing changes
|
|
25
|
-
*/
|
|
26
|
-
DiffPath(path: string, value: any): {
|
|
27
|
-
path: (string | number)[];
|
|
28
|
-
value: unknown;
|
|
29
|
-
}[];
|
|
30
|
-
PatchPath(path: string, patch: any): {
|
|
31
|
-
path: (string | number)[];
|
|
32
|
-
value: unknown;
|
|
33
|
-
}[];
|
|
34
|
-
PushPath(path: string, items: any[]): JsonDiffResult;
|
|
35
|
-
SplicePath(path: string, start: number, deleteCount: number | undefined, items: any[]): DiffSpliceResult;
|
|
36
|
-
}
|
package/Store/Diff/diffSync.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { DiffTree } from "./diffTree";
|
|
2
|
-
/**
|
|
3
|
-
* Synchronous diff implementation.
|
|
4
|
-
* Computes diffs immediately without queuing or workers.
|
|
5
|
-
*
|
|
6
|
-
* @see StoreSync
|
|
7
|
-
* @see StoreAsync
|
|
8
|
-
*/
|
|
9
|
-
export class DiffSync {
|
|
10
|
-
/**
|
|
11
|
-
* Creates a DiffSync instance.
|
|
12
|
-
* @param keyFunc - Optional function to extract a key from objects
|
|
13
|
-
* @param projections - Optional map of derived-value projections, keyed by id
|
|
14
|
-
*/
|
|
15
|
-
constructor(keyFunc, projections) {
|
|
16
|
-
this.diffTree = new DiffTree(keyFunc, projections);
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Computes the diff between a new value and the current value at a path.
|
|
20
|
-
* @param path - Dot-separated path to the value
|
|
21
|
-
* @param value - The new value to compare
|
|
22
|
-
* @returns Diff results showing changes
|
|
23
|
-
*/
|
|
24
|
-
DiffPath(path, value) {
|
|
25
|
-
const diff = this.diffTree.DiffPath(path, value);
|
|
26
|
-
return diff.concat(this.diffTree.RunProjections());
|
|
27
|
-
}
|
|
28
|
-
PatchPath(path, patch) {
|
|
29
|
-
const diff = this.diffTree.PatchPath(path, patch);
|
|
30
|
-
return diff.concat(this.diffTree.RunProjections());
|
|
31
|
-
}
|
|
32
|
-
PushPath(path, items) {
|
|
33
|
-
const diff = this.diffTree.PushPath(path, items);
|
|
34
|
-
return diff.concat(this.diffTree.RunProjections());
|
|
35
|
-
}
|
|
36
|
-
SplicePath(path, start, deleteCount, items) {
|
|
37
|
-
const spliceResult = this.diffTree.SplicePath(path, start, deleteCount, items);
|
|
38
|
-
const projectionDiff = this.diffTree.RunProjections();
|
|
39
|
-
spliceResult.diffResult = spliceResult.diffResult.concat(projectionDiff);
|
|
40
|
-
// spliceResult.diffResult.push(...this.diffTree.RunProjections());
|
|
41
|
-
return spliceResult;
|
|
42
|
-
}
|
|
43
|
-
}
|