j-templates 8.0.8 → 8.0.10
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/Store/Diff/diffAsync.d.ts +2 -1
- package/Store/Diff/diffAsync.js +6 -0
- package/Store/Diff/diffSync.d.ts +2 -1
- package/Store/Diff/diffSync.js +3 -0
- package/Store/Diff/diffTree.d.ts +11 -1
- package/Store/Diff/diffTree.js +36 -0
- package/Store/Store/store.d.ts +2 -0
- package/Store/Store/store.js +7 -0
- package/Store/Store/storeAsync.js +11 -24
- package/Store/Store/storeSync.js +10 -10
- package/Store/Tree/observableNode.d.ts +1 -0
- package/Store/Tree/observableNode.js +7 -0
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IDiffTree } from "./diffTree";
|
|
1
|
+
import { DiffSpliceResult, IDiffTree } from "./diffTree";
|
|
2
2
|
import { JsonDiffResult } from "../../Utils/json";
|
|
3
3
|
/**
|
|
4
4
|
* Async version of IDiffTree interface with all methods returning promises.
|
|
@@ -38,6 +38,7 @@ export declare class DiffAsync implements IDiffTreeAsync {
|
|
|
38
38
|
path: string;
|
|
39
39
|
value: any;
|
|
40
40
|
}>): Promise<JsonDiffResult>;
|
|
41
|
+
SplicePath(path: string, start: number, deleteCount: number, items: any[], flatten?: boolean): Promise<DiffSpliceResult<unknown>>;
|
|
41
42
|
/**
|
|
42
43
|
* Destroys the DiffAsync instance and terminates the worker.
|
|
43
44
|
*/
|
package/Store/Diff/diffAsync.js
CHANGED
|
@@ -45,6 +45,12 @@ class DiffAsync {
|
|
|
45
45
|
arguments: [data],
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
|
+
async SplicePath(path, start, deleteCount, items, flatten) {
|
|
49
|
+
return await this.workerQueue.Push({
|
|
50
|
+
method: "splicepath",
|
|
51
|
+
arguments: [path, start, deleteCount, items, flatten]
|
|
52
|
+
});
|
|
53
|
+
}
|
|
48
54
|
/**
|
|
49
55
|
* Destroys the DiffAsync instance and terminates the worker.
|
|
50
56
|
*/
|
package/Store/Diff/diffSync.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IDiffTree } from "./diffTree";
|
|
1
|
+
import { DiffSpliceResult, IDiffTree } from "./diffTree";
|
|
2
2
|
/**
|
|
3
3
|
* Synchronous diff implementation.
|
|
4
4
|
* Computes diffs immediately without queuing or workers.
|
|
@@ -31,4 +31,5 @@ export declare class DiffSync implements IDiffTree {
|
|
|
31
31
|
path: string;
|
|
32
32
|
value: any;
|
|
33
33
|
}>): import("../../Utils/json").JsonDiffResult;
|
|
34
|
+
SplicePath(path: string, start: number, deleteCount: number | undefined, items: any[], flatten?: boolean): DiffSpliceResult;
|
|
34
35
|
}
|
package/Store/Diff/diffSync.js
CHANGED
|
@@ -36,5 +36,8 @@ class DiffSync {
|
|
|
36
36
|
DiffBatch(data) {
|
|
37
37
|
return this.diffTree.DiffBatch(data);
|
|
38
38
|
}
|
|
39
|
+
SplicePath(path, start, deleteCount, items, flatten) {
|
|
40
|
+
return this.diffTree.SplicePath(path, start, deleteCount, items, flatten);
|
|
41
|
+
}
|
|
39
42
|
}
|
|
40
43
|
exports.DiffSync = DiffSync;
|
package/Store/Diff/diffTree.d.ts
CHANGED
|
@@ -4,10 +4,19 @@ import { JsonDiffFactoryResult, JsonDiffResult } from "../../Utils/json";
|
|
|
4
4
|
*/
|
|
5
5
|
export interface IDiffMethod {
|
|
6
6
|
/** The method to call */
|
|
7
|
-
method: "create" | "diffpath" | "diffbatch" | "updatepath" | "getpath";
|
|
7
|
+
method: "create" | "diffpath" | "splicepath" | "diffbatch" | "updatepath" | "getpath";
|
|
8
8
|
/** Arguments for the method call */
|
|
9
9
|
arguments: Array<any>;
|
|
10
10
|
}
|
|
11
|
+
export type DiffSpliceResult<T = unknown> = {
|
|
12
|
+
/** Array path segments (strings for object keys, numbers for array indices) */
|
|
13
|
+
path: (string | number)[];
|
|
14
|
+
/** Required by the splice operation **/
|
|
15
|
+
start: number;
|
|
16
|
+
deleteCount: number;
|
|
17
|
+
spliceResult: any[];
|
|
18
|
+
diffResult: JsonDiffResult;
|
|
19
|
+
};
|
|
11
20
|
/**
|
|
12
21
|
* Interface for diff tree operations.
|
|
13
22
|
*/
|
|
@@ -28,6 +37,7 @@ export interface IDiffTree {
|
|
|
28
37
|
* @returns Diff results showing changes
|
|
29
38
|
*/
|
|
30
39
|
DiffPath(path: string, value: any, flatten?: boolean): JsonDiffResult;
|
|
40
|
+
SplicePath(path: string, start: number, deleteCount: number | undefined, items: any[], flatten?: boolean): DiffSpliceResult;
|
|
31
41
|
}
|
|
32
42
|
/**
|
|
33
43
|
* Constructor interface for IDiffTree.
|
package/Store/Diff/diffTree.js
CHANGED
|
@@ -29,6 +29,11 @@ function DiffTreeFactory(jsonDiffFactory, worker) {
|
|
|
29
29
|
ctx.postMessage(diff);
|
|
30
30
|
break;
|
|
31
31
|
}
|
|
32
|
+
case "splicepath": {
|
|
33
|
+
const diff = diffTree.SplicePath(data.arguments[0], data.arguments[1], data.arguments[2], data.arguments[3], data.arguments[4]);
|
|
34
|
+
ctx.postMessage(diff);
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
32
37
|
case "diffbatch": {
|
|
33
38
|
const diff = diffTree.DiffBatch(data.arguments[0]);
|
|
34
39
|
ctx.postMessage(diff);
|
|
@@ -158,6 +163,34 @@ function DiffTreeFactory(jsonDiffFactory, worker) {
|
|
|
158
163
|
}
|
|
159
164
|
return diffResult;
|
|
160
165
|
}
|
|
166
|
+
function SpliceSource(source, path, start, deleteCount, items, flatten, keyFunc) {
|
|
167
|
+
const sourceValue = GetPathValue(source, path);
|
|
168
|
+
if (!Array.isArray(sourceValue))
|
|
169
|
+
throw `Value found at path ${path} is not an array`;
|
|
170
|
+
deleteCount ??= sourceValue.length - start;
|
|
171
|
+
const spliceResult = {
|
|
172
|
+
path: path.split("."),
|
|
173
|
+
start,
|
|
174
|
+
deleteCount,
|
|
175
|
+
spliceResult: null,
|
|
176
|
+
diffResult: []
|
|
177
|
+
};
|
|
178
|
+
spliceResult.spliceResult = sourceValue.splice(start, deleteCount, ...items);
|
|
179
|
+
if (flatten && keyFunc) {
|
|
180
|
+
// Register the keyed entities the new items carry, diffed against the roots
|
|
181
|
+
// already held: a new entity is added whole, one re-inserted unchanged (an undo)
|
|
182
|
+
// produces no diff, so its readers aren't woken.
|
|
183
|
+
const flattened = JsonDeepClone(FlattenValue({}, items, keyFunc));
|
|
184
|
+
const keys = Object.keys(flattened);
|
|
185
|
+
for (let x = 0; x < keys.length; x++)
|
|
186
|
+
JsonDiff(flattened[keys[x]], source[keys[x]], keys[x], spliceResult.diffResult);
|
|
187
|
+
}
|
|
188
|
+
const filteredDiffResult = spliceResult.diffResult.filter((diff) => diff.value !== undefined);
|
|
189
|
+
for (let x = 0; x < filteredDiffResult.length; x++) {
|
|
190
|
+
SetPathValue(source, filteredDiffResult[x].path, filteredDiffResult[x].value);
|
|
191
|
+
}
|
|
192
|
+
return spliceResult;
|
|
193
|
+
}
|
|
161
194
|
/**
|
|
162
195
|
* Internal diff tree implementation.
|
|
163
196
|
* Maintains root state and computes diffs for path/value updates.
|
|
@@ -192,6 +225,9 @@ function DiffTreeFactory(jsonDiffFactory, worker) {
|
|
|
192
225
|
DiffPath(path, value, flatten = true) {
|
|
193
226
|
return UpdateSource(this.rootState, path, value, flatten, this.keyFunc);
|
|
194
227
|
}
|
|
228
|
+
SplicePath(path, start, deleteCount, items, flatten = true) {
|
|
229
|
+
return SpliceSource(this.rootState, path, start, deleteCount, items, flatten, this.keyFunc);
|
|
230
|
+
}
|
|
195
231
|
/**
|
|
196
232
|
* Retrieves the current value at a path.
|
|
197
233
|
* @param path - Dot-separated path to the value
|
package/Store/Store/store.d.ts
CHANGED
|
@@ -32,6 +32,7 @@ export declare abstract class Store {
|
|
|
32
32
|
* @returns The value or the default value
|
|
33
33
|
*/
|
|
34
34
|
Get<O>(id: string, defaultValue: O): O;
|
|
35
|
+
Has(id: string): boolean;
|
|
35
36
|
abstract Write(data: unknown, key?: string): Promise<void> | void;
|
|
36
37
|
abstract Patch(key: string, patch: unknown): Promise<void> | void;
|
|
37
38
|
abstract Push(key: string, ...data: unknown[]): Promise<void> | void;
|
|
@@ -42,6 +43,7 @@ export declare abstract class Store {
|
|
|
42
43
|
* @protected
|
|
43
44
|
*/
|
|
44
45
|
protected UpdateRootMap(results: JsonDiffResult): void;
|
|
46
|
+
protected SpliceRootObject(rootPath: string | number, start: number, deleteCount: number, items: any[]): void;
|
|
45
47
|
/**
|
|
46
48
|
* Updates a specific root object with diff results.
|
|
47
49
|
* Creates the root object if it doesn't exist.
|
package/Store/Store/store.js
CHANGED
|
@@ -45,6 +45,9 @@ class Store {
|
|
|
45
45
|
}
|
|
46
46
|
return result[id];
|
|
47
47
|
}
|
|
48
|
+
Has(id) {
|
|
49
|
+
return this.rootMap.has(id);
|
|
50
|
+
}
|
|
48
51
|
/**
|
|
49
52
|
* Updates the root map with diff results by grouping changes by root path.
|
|
50
53
|
* @param results - Array of diff results to apply
|
|
@@ -60,6 +63,10 @@ class Store {
|
|
|
60
63
|
this.UpdateRootObject(rootGroup[0].path[0], rootGroup);
|
|
61
64
|
}
|
|
62
65
|
}
|
|
66
|
+
SpliceRootObject(rootPath, start, deleteCount, items) {
|
|
67
|
+
const rootObject = this.rootMap.get(rootPath);
|
|
68
|
+
observableNode_1.ObservableNode.ApplySplice(rootObject[rootPath], start, deleteCount, items, this.cloneData);
|
|
69
|
+
}
|
|
63
70
|
/**
|
|
64
71
|
* Updates a specific root object with diff results.
|
|
65
72
|
* Creates the root object if it doesn't exist.
|
|
@@ -82,6 +82,8 @@ class StoreAsync extends store_1.Store {
|
|
|
82
82
|
*/
|
|
83
83
|
async Patch(key, patch) {
|
|
84
84
|
await this.queue.Next(async () => {
|
|
85
|
+
if (!this.Has(key))
|
|
86
|
+
throw "Key not found in store";
|
|
85
87
|
const value = this.Get(key);
|
|
86
88
|
if (value === undefined)
|
|
87
89
|
throw "Unable to patch undefined value";
|
|
@@ -99,6 +101,8 @@ class StoreAsync extends store_1.Store {
|
|
|
99
101
|
*/
|
|
100
102
|
async Push(key, ...data) {
|
|
101
103
|
await this.queue.Next(async () => {
|
|
104
|
+
if (!this.Has(key))
|
|
105
|
+
throw "Key not found in store";
|
|
102
106
|
const arr = this.Get(key);
|
|
103
107
|
const batch = data.map(function (d, i) {
|
|
104
108
|
return {
|
|
@@ -121,31 +125,14 @@ class StoreAsync extends store_1.Store {
|
|
|
121
125
|
* @returns The array of deleted elements.
|
|
122
126
|
*/
|
|
123
127
|
async Splice(key, start, deleteCount, ...items) {
|
|
128
|
+
items = (0, json_1.JsonDeepClone)(items);
|
|
124
129
|
return await this.queue.Next(async () => {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
const spliceResult =
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
diffBatch[diffBatch.length - 1] = { path: `${key}.length`, value: start + arrNodes.length };
|
|
132
|
-
const diffResult = await this.diff.DiffBatch(diffBatch);
|
|
133
|
-
this.UpdateRootMap(diffResult);
|
|
134
|
-
return spliceResult;
|
|
135
|
-
/* const arr = this.Get(key) as any[];
|
|
136
|
-
const arrNodes = arr.slice(start); // Array starting from the splice start index
|
|
137
|
-
const spliceResult = arrNodes.splice(0, deleteCount, ...items);
|
|
138
|
-
|
|
139
|
-
const diffBatch: { path: string, value: any }[] = new Array(arrNodes.length + 1);
|
|
140
|
-
for (let x = 0; x < arrNodes.length; x++)
|
|
141
|
-
diffBatch[x] = { path: `${key}.${x + start}`, value: arrNodes[x]?.toJSON?.() };
|
|
142
|
-
|
|
143
|
-
diffBatch[diffBatch.length - 1] = { path: `${key}.length`, value: arrNodes.length + start + items.length };
|
|
144
|
-
|
|
145
|
-
const diffResult = await this.diff.DiffBatch(diffBatch);
|
|
146
|
-
this.UpdateRootMap(diffResult);
|
|
147
|
-
|
|
148
|
-
return spliceResult; */
|
|
130
|
+
if (!this.Has(key))
|
|
131
|
+
throw "Key not found in store";
|
|
132
|
+
const spliceResult = await this.diff.SplicePath(key, start, deleteCount, items);
|
|
133
|
+
this.UpdateRootMap(spliceResult.diffResult);
|
|
134
|
+
this.SpliceRootObject(spliceResult.path[0], spliceResult.start, spliceResult.deleteCount, items);
|
|
135
|
+
return spliceResult.spliceResult;
|
|
149
136
|
});
|
|
150
137
|
}
|
|
151
138
|
/**
|
package/Store/Store/storeSync.js
CHANGED
|
@@ -63,6 +63,8 @@ class StoreSync extends store_1.Store {
|
|
|
63
63
|
* @throws Will throw an error if the value to be patched is undefined.
|
|
64
64
|
*/
|
|
65
65
|
Patch(key, patch) {
|
|
66
|
+
if (!this.Has(key))
|
|
67
|
+
throw "Key not found in store";
|
|
66
68
|
const value = this.Get(key);
|
|
67
69
|
if (value === undefined)
|
|
68
70
|
throw "Unable to patch undefined value";
|
|
@@ -77,6 +79,8 @@ class StoreSync extends store_1.Store {
|
|
|
77
79
|
* @param data The data items to be pushed into the array.
|
|
78
80
|
*/
|
|
79
81
|
Push(key, ...data) {
|
|
82
|
+
if (!this.Has(key))
|
|
83
|
+
throw "Key not found in store";
|
|
80
84
|
const arr = this.Get(key);
|
|
81
85
|
const batch = data.map(function (d, i) {
|
|
82
86
|
return {
|
|
@@ -97,16 +101,12 @@ class StoreSync extends store_1.Store {
|
|
|
97
101
|
* @returns The array of deleted elements.
|
|
98
102
|
*/
|
|
99
103
|
Splice(key, start, deleteCount, ...items) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const spliceResult =
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
diffBatch[diffBatch.length - 1] = { path: `${key}.length`, value: start + arrNodes.length };
|
|
107
|
-
const diffResult = this.diff.DiffBatch(diffBatch);
|
|
108
|
-
this.UpdateRootMap(diffResult);
|
|
109
|
-
return spliceResult;
|
|
104
|
+
if (!this.Has(key))
|
|
105
|
+
throw "Key not found in store";
|
|
106
|
+
const spliceResult = this.diff.SplicePath(key, start, deleteCount, items);
|
|
107
|
+
this.UpdateRootMap(spliceResult.diffResult);
|
|
108
|
+
this.SpliceRootObject(spliceResult.path[0], spliceResult.start, spliceResult.deleteCount, items);
|
|
109
|
+
return (0, json_1.JsonDeepClone)(spliceResult.spliceResult);
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
exports.StoreSync = StoreSync;
|
|
@@ -68,6 +68,7 @@ export declare namespace ObservableNode {
|
|
|
68
68
|
* @remarks No-op when `value` deep-equals the node's current value (empty diff).
|
|
69
69
|
*/
|
|
70
70
|
function Apply(rootNode: any, value: any): void;
|
|
71
|
+
function ApplySplice(rootNode: any, start: number, deleteCount: number, items: any[], cloneData?: boolean): void;
|
|
71
72
|
/**
|
|
72
73
|
* Applies a JSON diff result to an observable node, efficiently updating only changed properties.
|
|
73
74
|
* Optimizes nested object updates by computing paths incrementally and touching modified properties.
|
|
@@ -409,6 +409,13 @@ var ObservableNode;
|
|
|
409
409
|
ApplyDiff(rootNode, diff);
|
|
410
410
|
}
|
|
411
411
|
ObservableNode.Apply = Apply;
|
|
412
|
+
function ApplySplice(rootNode, start, deleteCount, items, cloneData = true) {
|
|
413
|
+
const root = rootNode[NODE_VALUE];
|
|
414
|
+
const addItems = cloneData ? (0, json_1.JsonDeepClone)(items) : items;
|
|
415
|
+
root.splice(start, deleteCount, ...addItems);
|
|
416
|
+
ObservableNode.Update(root);
|
|
417
|
+
}
|
|
418
|
+
ObservableNode.ApplySplice = ApplySplice;
|
|
412
419
|
/**
|
|
413
420
|
* Applies a JSON diff result to an observable node, efficiently updating only changed properties.
|
|
414
421
|
* Optimizes nested object updates by computing paths incrementally and touching modified properties.
|