j-templates 8.0.25 → 8.0.27
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/Node/vNode.js +1 -1
- package/Store/Diff/diffSync.d.ts +12 -12
- package/Store/Diff/diffSync.js +15 -12
- package/Store/Diff/diffTree.d.ts +11 -27
- package/Store/Diff/diffTree.js +52 -29
- package/Store/Diff/diffTreeWorker.d.ts +11 -2
- package/Store/Diff/diffTreeWorker.js +37 -20
- package/Store/Store/storeAsync.d.ts +41 -34
- package/Store/Store/storeAsync.js +100 -79
- package/Store/Store/storeSync.js +3 -17
- package/Utils/asyncQueue.d.ts +3 -0
- package/Utils/asyncQueue.js +22 -4
- package/package.json +1 -1
- package/Store/Diff/diffAsync.d.ts +0 -47
- package/Store/Diff/diffAsync.js +0 -54
- package/Store/Diff/diffTree_v2.d.ts +0 -135
- package/Store/Diff/diffTree_v2.js +0 -445
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { AsyncQueue } from "../../Utils/asyncQueue";
|
|
2
|
-
import {
|
|
3
|
-
import { DiffAsync } from "../Diff/diffAsync";
|
|
2
|
+
import { WorkerQueue } from "../Diff/workerQueue";
|
|
4
3
|
import { Store } from "./store";
|
|
5
4
|
/**
|
|
6
5
|
* StoreAsync class extends the base Store class to provide asynchronous data management operations.
|
|
@@ -23,138 +22,160 @@ import { Store } from "./store";
|
|
|
23
22
|
* await store.Patch("user", { age: 31 });
|
|
24
23
|
*
|
|
25
24
|
* // Pushing data into an array asynchronously
|
|
26
|
-
* await store.
|
|
25
|
+
* await store.Write([], "users");
|
|
26
|
+
* await store.Push("users", { id: 1 }, { id: 2 });
|
|
27
27
|
*
|
|
28
28
|
* // Splicing an array asynchronously
|
|
29
|
-
* const deletedItems = await store.Splice("
|
|
29
|
+
* const deletedItems = await store.Splice("users", 0, 1, { id: 3 });
|
|
30
30
|
*
|
|
31
31
|
* // Cleaning up resources
|
|
32
32
|
* store.Destroy();
|
|
33
33
|
*
|
|
34
34
|
* @see Store
|
|
35
35
|
* @see StoreSync
|
|
36
|
-
* @see DiffAsync
|
|
37
36
|
*/
|
|
38
37
|
export class StoreAsync extends Store {
|
|
39
38
|
/**
|
|
40
39
|
* Creates an instance of StoreAsync.
|
|
41
|
-
* @param diffWorker A `Worker` running a `DiffTree` connected via
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* was constructed with, if any.
|
|
40
|
+
* @param diffWorker A `Worker` running a `DiffTree` connected via `ConnectWorkerToDiffTree`
|
|
41
|
+
* (e.g. a bundled `defaultDiffTreeWorker` entry). Any `keyFunc`/projections the diff needs
|
|
42
|
+
* must be baked into that worker's own entry file.
|
|
43
|
+
* @param keyFunc Optional function to generate a key for a given data value, used locally by
|
|
44
|
+
* this store to resolve root objects. Pass the same key logic the worker's `DiffTree` was
|
|
45
|
+
* constructed with, if any.
|
|
48
46
|
*/
|
|
49
47
|
constructor(diffWorker, keyFunc) {
|
|
50
48
|
super(keyFunc, false);
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
this.
|
|
56
|
-
this.nextWritePromise = null;
|
|
57
|
-
this.nextWriteBatch = null;
|
|
58
|
-
this.diff = new DiffAsync(diffWorker);
|
|
49
|
+
this.writeKeySet = new Set();
|
|
50
|
+
this.currentBatch = [];
|
|
51
|
+
this.currentBatchPromise = Promise.resolve([]);
|
|
52
|
+
this.workerQueue = new WorkerQueue(diffWorker);
|
|
53
|
+
this.asyncQueue = new AsyncQueue(true);
|
|
59
54
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
55
|
+
async Schedule(method) {
|
|
56
|
+
if (this.currentBatch.length === 0) {
|
|
57
|
+
const batch = this.currentBatch;
|
|
58
|
+
this.currentBatchPromise = this.asyncQueue.Next(async () => {
|
|
59
|
+
await Promise.resolve();
|
|
60
|
+
if (batch === this.currentBatch)
|
|
61
|
+
this.currentBatch = [];
|
|
62
|
+
const results = await this.workerQueue.Push(batch);
|
|
63
|
+
for (let x = 0; x < results.length; x++) {
|
|
64
|
+
const result = results[x];
|
|
65
|
+
switch (result.type) {
|
|
66
|
+
case "diff": {
|
|
67
|
+
this.UpdateRootMap(result.result);
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
case "splice": {
|
|
71
|
+
const spliceResult = result.result;
|
|
72
|
+
this.UpdateRootMap(spliceResult.diffResult);
|
|
73
|
+
this.SpliceRootObject(spliceResult.path[0], spliceResult.start, spliceResult.deleteCount, spliceResult.items);
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return results;
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
const batchIndex = this.currentBatch.length;
|
|
82
|
+
this.currentBatch.push(method);
|
|
83
|
+
const batchResult = await this.currentBatchPromise;
|
|
84
|
+
return batchResult[batchIndex].result;
|
|
65
85
|
}
|
|
66
86
|
/**
|
|
67
87
|
* Writes data to the store asynchronously.
|
|
68
|
-
*
|
|
88
|
+
* Changes made in the same tick are sent to the worker together as one batch and applied in
|
|
89
|
+
* the order they were made. A change to this key may be made before the returned promise
|
|
90
|
+
* resolves; it's applied after this write.
|
|
69
91
|
* @param data The data to be written. Can be of any type.
|
|
70
92
|
* @param key Optional key for the data. If not provided, the keyFunc will be used to generate a key.
|
|
71
|
-
* @
|
|
93
|
+
* @returns A promise that resolves once the write has been applied to the store.
|
|
94
|
+
* @throws Will throw an error if no key is provided for the data, or reject with the original
|
|
95
|
+
* error if an earlier change failed.
|
|
72
96
|
*/
|
|
73
97
|
async Write(data, key) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
98
|
+
key = key || this.keyFunc?.(data);
|
|
99
|
+
if (!key)
|
|
100
|
+
throw new Error("No key provided for data");
|
|
101
|
+
this.writeKeySet.add(key);
|
|
102
|
+
await this.Schedule({
|
|
103
|
+
method: "diffpath",
|
|
104
|
+
arguments: [key, data]
|
|
79
105
|
});
|
|
80
|
-
|
|
81
|
-
this.nextWritePromise = this.queue.Next(async () => {
|
|
82
|
-
await Promise.resolve();
|
|
83
|
-
this.nextWriteBatch = null;
|
|
84
|
-
const diffResult = await this.diff.DiffBatch(nextWriteBatch);
|
|
85
|
-
this.UpdateRootMap(diffResult);
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
return this.nextWritePromise;
|
|
106
|
+
this.writeKeySet.delete(key);
|
|
89
107
|
}
|
|
90
108
|
/**
|
|
91
109
|
* Patches an existing value in the store with new data asynchronously.
|
|
92
|
-
*
|
|
110
|
+
* The patch is merged with the current value in the worker, so it applies on top of any
|
|
111
|
+
* change made before it, including ones not yet applied to the store.
|
|
93
112
|
* @param key The key of the value to be patched.
|
|
94
113
|
* @param patch The patch data to be merged with the existing value.
|
|
95
|
-
* @
|
|
114
|
+
* @returns A promise that resolves once the patch has been applied to the store.
|
|
115
|
+
* @throws Will throw if the key isn't in the store and has no pending Write, or reject with
|
|
116
|
+
* the original error if an earlier change failed.
|
|
96
117
|
*/
|
|
97
118
|
async Patch(key, patch) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
throw "Unable to patch undefined value";
|
|
104
|
-
const json = value.toJSON();
|
|
105
|
-
const mergedJson = JsonMerge(json, patch);
|
|
106
|
-
const diffResult = await this.diff.DiffPath(key, mergedJson, false);
|
|
107
|
-
this.UpdateRootMap(diffResult);
|
|
119
|
+
if (!this.Has(key) && !this.writeKeySet.has(key))
|
|
120
|
+
throw "Key not found in store";
|
|
121
|
+
await this.Schedule({
|
|
122
|
+
method: "patchpath",
|
|
123
|
+
arguments: [key, patch]
|
|
108
124
|
});
|
|
109
125
|
}
|
|
110
126
|
/**
|
|
111
127
|
* Pushes data into an array stored at the specified key asynchronously.
|
|
112
|
-
* This method ensures that push operations are queued and executed in a non-blocking manner.
|
|
113
128
|
* @param key The key of the array where data will be pushed.
|
|
114
129
|
* @param data The data items to be pushed into the array.
|
|
130
|
+
* @returns A promise that resolves once the items have been applied to the store.
|
|
131
|
+
* @throws Will throw if the key isn't in the store and has no pending Write, or reject with
|
|
132
|
+
* the original error if an earlier change failed.
|
|
115
133
|
*/
|
|
116
134
|
async Push(key, ...data) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
return {
|
|
123
|
-
path: `${key}.${arr.length + i}`,
|
|
124
|
-
value: d,
|
|
125
|
-
};
|
|
126
|
-
});
|
|
127
|
-
const diffResult = await this.diff.DiffBatch(batch);
|
|
128
|
-
this.UpdateRootMap(diffResult);
|
|
135
|
+
if (!this.Has(key) && !this.writeKeySet.has(key))
|
|
136
|
+
throw "Key not found in store";
|
|
137
|
+
await this.Schedule({
|
|
138
|
+
method: "pushpath",
|
|
139
|
+
arguments: [key, data]
|
|
129
140
|
});
|
|
130
141
|
}
|
|
131
142
|
/**
|
|
132
143
|
* Splices an array stored at the specified key with new data asynchronously.
|
|
133
|
-
* This method
|
|
134
|
-
* It modifies the array by deleting elements and inserting new ones at the specified position.
|
|
144
|
+
* This method modifies the array by deleting elements and inserting new ones at the specified position.
|
|
135
145
|
* @param key The key of the array to be spliced.
|
|
136
146
|
* @param start The position at which to start changing the array.
|
|
137
147
|
* @param deleteCount Optional number of elements to delete. If not provided, all elements from start to end will be deleted.
|
|
138
148
|
* @param items Optional elements to insert into the array.
|
|
139
|
-
* @returns
|
|
149
|
+
* @returns A promise that resolves to the array of deleted elements once the splice has been
|
|
150
|
+
* applied to the store.
|
|
151
|
+
* @throws Will throw if the key isn't in the store and has no pending Write, or reject with
|
|
152
|
+
* the original error if an earlier change failed.
|
|
140
153
|
*/
|
|
141
154
|
async Splice(key, start, deleteCount, ...items) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
this.UpdateRootMap(spliceResult.diffResult);
|
|
148
|
-
this.SpliceRootObject(spliceResult.path[0], spliceResult.start, spliceResult.deleteCount, items);
|
|
149
|
-
return spliceResult.spliceResult;
|
|
155
|
+
if (!this.Has(key) && !this.writeKeySet.has(key))
|
|
156
|
+
throw "Key not found in store";
|
|
157
|
+
const spliceResult = await this.Schedule({
|
|
158
|
+
method: "splicepath",
|
|
159
|
+
arguments: [key, start, deleteCount, items]
|
|
150
160
|
});
|
|
161
|
+
return spliceResult.spliceResult;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Returns a promise that resolves once every change made before this call has been applied
|
|
165
|
+
* to the store. Changes made after this call are sent in a later batch, so they aren't
|
|
166
|
+
* waited for and haven't been applied when the promise resolves.
|
|
167
|
+
* @throws Rejects with the original error if a change made before this call failed.
|
|
168
|
+
*/
|
|
169
|
+
async Flush() {
|
|
170
|
+
this.currentBatch = [];
|
|
171
|
+
return this.asyncQueue.Flush();
|
|
151
172
|
}
|
|
152
173
|
/**
|
|
153
174
|
* Destroys the StoreAsync instance, stopping the async queue and cleaning up the diff instance.
|
|
154
175
|
* This method should be called when the instance is no longer needed to free up resources.
|
|
155
176
|
*/
|
|
156
177
|
Destroy() {
|
|
157
|
-
this.
|
|
158
|
-
this.
|
|
178
|
+
this.asyncQueue.Stop();
|
|
179
|
+
this.workerQueue.Destroy();
|
|
159
180
|
}
|
|
160
181
|
}
|
package/Store/Store/storeSync.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { JsonDeepClone } from "../../Utils/json";
|
|
2
2
|
import { DiffSync } from "../Diff/diffSync";
|
|
3
|
-
import { ObservableNode } from "../Tree/observableNode";
|
|
4
3
|
import { Store } from "./store";
|
|
5
4
|
/**
|
|
6
5
|
* StoreSync class extends the base Store class to provide synchronous data management operations.
|
|
@@ -51,7 +50,6 @@ export class StoreSync extends Store {
|
|
|
51
50
|
key = key || this.keyFunc?.(data);
|
|
52
51
|
if (!key)
|
|
53
52
|
throw "No key provided for data";
|
|
54
|
-
data = ObservableNode.Unwrap(data);
|
|
55
53
|
const diffResult = this.diff.DiffPath(key, data);
|
|
56
54
|
this.UpdateRootMap(diffResult);
|
|
57
55
|
}
|
|
@@ -64,12 +62,7 @@ export class StoreSync extends Store {
|
|
|
64
62
|
Patch(key, patch) {
|
|
65
63
|
if (!this.Has(key))
|
|
66
64
|
throw "Key not found in store";
|
|
67
|
-
const
|
|
68
|
-
if (value === undefined)
|
|
69
|
-
throw "Unable to patch undefined value";
|
|
70
|
-
const json = ObservableNode.Unwrap(value);
|
|
71
|
-
const mergedJson = JsonMerge(json, patch);
|
|
72
|
-
const diffResult = this.diff.DiffPath(key, mergedJson, false);
|
|
65
|
+
const diffResult = this.diff.PatchPath(key, patch);
|
|
73
66
|
this.UpdateRootMap(diffResult);
|
|
74
67
|
}
|
|
75
68
|
/**
|
|
@@ -80,14 +73,7 @@ export class StoreSync extends Store {
|
|
|
80
73
|
Push(key, ...data) {
|
|
81
74
|
if (!this.Has(key))
|
|
82
75
|
throw "Key not found in store";
|
|
83
|
-
const
|
|
84
|
-
const batch = data.map(function (d, i) {
|
|
85
|
-
return {
|
|
86
|
-
path: `${key}.${arr.length + i}`,
|
|
87
|
-
value: d,
|
|
88
|
-
};
|
|
89
|
-
});
|
|
90
|
-
const diffResult = this.diff.DiffBatch(batch);
|
|
76
|
+
const diffResult = this.diff.PushPath(key, data);
|
|
91
77
|
this.UpdateRootMap(diffResult);
|
|
92
78
|
}
|
|
93
79
|
/**
|
package/Utils/asyncQueue.d.ts
CHANGED
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
* A queue that executes async callbacks sequentially, one at a time.
|
|
3
3
|
*/
|
|
4
4
|
export declare class AsyncQueue {
|
|
5
|
+
private maintainError;
|
|
5
6
|
private running;
|
|
7
|
+
private error;
|
|
6
8
|
private queue;
|
|
9
|
+
constructor(maintainError?: boolean);
|
|
7
10
|
Flush(): Promise<void>;
|
|
8
11
|
/**
|
|
9
12
|
* Adds a callback to the queue and returns a promise that resolves when it executes.
|
package/Utils/asyncQueue.js
CHANGED
|
@@ -3,13 +3,23 @@ import { List } from "./list";
|
|
|
3
3
|
* A queue that executes async callbacks sequentially, one at a time.
|
|
4
4
|
*/
|
|
5
5
|
export class AsyncQueue {
|
|
6
|
-
constructor() {
|
|
6
|
+
constructor(maintainError = false) {
|
|
7
|
+
this.maintainError = maintainError;
|
|
7
8
|
this.running = false;
|
|
9
|
+
this.error = null;
|
|
8
10
|
this.queue = List.Create();
|
|
9
11
|
}
|
|
10
12
|
Flush() {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
if (this.maintainError && this.error)
|
|
14
|
+
return Promise.reject(this.error);
|
|
15
|
+
const ret = new Promise((resolve, reject) => {
|
|
16
|
+
List.Add(this.queue, () => {
|
|
17
|
+
if (this.maintainError && this.error) {
|
|
18
|
+
reject(this.error);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
resolve();
|
|
22
|
+
});
|
|
13
23
|
});
|
|
14
24
|
this.Start();
|
|
15
25
|
return ret;
|
|
@@ -21,13 +31,21 @@ export class AsyncQueue {
|
|
|
21
31
|
* @returns Promise that resolves with the callback's result when executed
|
|
22
32
|
*/
|
|
23
33
|
Next(callback) {
|
|
34
|
+
if (this.maintainError && this.error)
|
|
35
|
+
return Promise.reject(this.error);
|
|
24
36
|
const ret = new Promise((resolve, reject) => {
|
|
25
|
-
List.Add(this.queue, async
|
|
37
|
+
List.Add(this.queue, async () => {
|
|
38
|
+
if (this.maintainError && this.error) {
|
|
39
|
+
reject(this.error);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
26
42
|
try {
|
|
27
43
|
const ret = await callback();
|
|
28
44
|
resolve(ret);
|
|
29
45
|
}
|
|
30
46
|
catch (e) {
|
|
47
|
+
if (this.maintainError)
|
|
48
|
+
this.error = e;
|
|
31
49
|
reject(e);
|
|
32
50
|
}
|
|
33
51
|
});
|
package/package.json
CHANGED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { DiffSpliceResult, IDiffTree } from "./diffTree";
|
|
2
|
-
import { JsonDiffResult } from "../../Utils/json";
|
|
3
|
-
/**
|
|
4
|
-
* Async version of IDiffTree interface with all methods returning promises.
|
|
5
|
-
*/
|
|
6
|
-
type IDiffTreeAsync = {
|
|
7
|
-
[property in keyof IDiffTree]: (...args: Parameters<IDiffTree[property]>) => Promise<ReturnType<IDiffTree[property]>>;
|
|
8
|
-
};
|
|
9
|
-
/**
|
|
10
|
-
* Asynchronous diff implementation using web workers.
|
|
11
|
-
* Offloads diff computation to a worker to prevent blocking the main thread.
|
|
12
|
-
*
|
|
13
|
-
* @see StoreAsync
|
|
14
|
-
* @see DiffSync
|
|
15
|
-
*/
|
|
16
|
-
export declare class DiffAsync implements IDiffTreeAsync {
|
|
17
|
-
private workerQueue;
|
|
18
|
-
/**
|
|
19
|
-
* Creates a DiffAsync instance around an already-running worker.
|
|
20
|
-
* @param diffWorker - A `Worker` running a `DiffTree` connected via
|
|
21
|
-
* `ConnectWorkerToDiffTree` (e.g. a bundled `defaultDiffTreeWorker` entry, or a custom
|
|
22
|
-
* entry file for a non-default `keyFunc`/`projections` baked into the worker thread).
|
|
23
|
-
*/
|
|
24
|
-
constructor(diffWorker: Worker);
|
|
25
|
-
/**
|
|
26
|
-
* Computes the diff between a new value and the current value at a path asynchronously.
|
|
27
|
-
* @param path - Dot-separated path to the value
|
|
28
|
-
* @param value - The new value to compare
|
|
29
|
-
* @returns Promise that resolves to diff results showing changes
|
|
30
|
-
*/
|
|
31
|
-
DiffPath(path: string, value: any, flatten?: boolean): Promise<JsonDiffResult>;
|
|
32
|
-
/**
|
|
33
|
-
* Computes diffs for a batch of path/value pairs asynchronously.
|
|
34
|
-
* @param data - Array of objects with path and value properties
|
|
35
|
-
* @returns Promise that resolves to combined diff results
|
|
36
|
-
*/
|
|
37
|
-
DiffBatch(data: Array<{
|
|
38
|
-
path: string;
|
|
39
|
-
value: any;
|
|
40
|
-
}>): Promise<JsonDiffResult>;
|
|
41
|
-
SplicePath(path: string, start: number, deleteCount: number, items: any[], flatten?: boolean): Promise<DiffSpliceResult<unknown>>;
|
|
42
|
-
/**
|
|
43
|
-
* Destroys the DiffAsync instance and terminates the worker.
|
|
44
|
-
*/
|
|
45
|
-
Destroy(): void;
|
|
46
|
-
}
|
|
47
|
-
export {};
|
package/Store/Diff/diffAsync.js
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { WorkerQueue } from "./workerQueue";
|
|
2
|
-
/**
|
|
3
|
-
* Asynchronous diff implementation using web workers.
|
|
4
|
-
* Offloads diff computation to a worker to prevent blocking the main thread.
|
|
5
|
-
*
|
|
6
|
-
* @see StoreAsync
|
|
7
|
-
* @see DiffSync
|
|
8
|
-
*/
|
|
9
|
-
export class DiffAsync {
|
|
10
|
-
/**
|
|
11
|
-
* Creates a DiffAsync instance around an already-running worker.
|
|
12
|
-
* @param diffWorker - A `Worker` running a `DiffTree` connected via
|
|
13
|
-
* `ConnectWorkerToDiffTree` (e.g. a bundled `defaultDiffTreeWorker` entry, or a custom
|
|
14
|
-
* entry file for a non-default `keyFunc`/`projections` baked into the worker thread).
|
|
15
|
-
*/
|
|
16
|
-
constructor(diffWorker) {
|
|
17
|
-
this.workerQueue = new WorkerQueue(diffWorker);
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Computes the diff between a new value and the current value at a path asynchronously.
|
|
21
|
-
* @param path - Dot-separated path to the value
|
|
22
|
-
* @param value - The new value to compare
|
|
23
|
-
* @returns Promise that resolves to diff results showing changes
|
|
24
|
-
*/
|
|
25
|
-
async DiffPath(path, value, flatten = true) {
|
|
26
|
-
return await this.workerQueue.Push({
|
|
27
|
-
method: "diffpath",
|
|
28
|
-
arguments: [path, value, flatten],
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Computes diffs for a batch of path/value pairs asynchronously.
|
|
33
|
-
* @param data - Array of objects with path and value properties
|
|
34
|
-
* @returns Promise that resolves to combined diff results
|
|
35
|
-
*/
|
|
36
|
-
async DiffBatch(data) {
|
|
37
|
-
return await this.workerQueue.Push({
|
|
38
|
-
method: "diffbatch",
|
|
39
|
-
arguments: [data],
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
async SplicePath(path, start, deleteCount, items, flatten) {
|
|
43
|
-
return await this.workerQueue.Push({
|
|
44
|
-
method: "splicepath",
|
|
45
|
-
arguments: [path, start, deleteCount, items, flatten]
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Destroys the DiffAsync instance and terminates the worker.
|
|
50
|
-
*/
|
|
51
|
-
Destroy() {
|
|
52
|
-
this.workerQueue.Destroy();
|
|
53
|
-
}
|
|
54
|
-
}
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import { type JsonDiffResult } from "../../Utils/json";
|
|
2
|
-
/**
|
|
3
|
-
* Interface for diff tree operations.
|
|
4
|
-
*/
|
|
5
|
-
export interface IDiffTree {
|
|
6
|
-
/**
|
|
7
|
-
* Computes diffs for a batch of path/value pairs.
|
|
8
|
-
* @param data - Array of objects with path and value properties
|
|
9
|
-
* @returns Combined diff results
|
|
10
|
-
*/
|
|
11
|
-
DiffBatch(data: Array<{
|
|
12
|
-
path: string;
|
|
13
|
-
value: any;
|
|
14
|
-
}>): JsonDiffResult;
|
|
15
|
-
/**
|
|
16
|
-
* Computes the diff between a new value and the current value at a path.
|
|
17
|
-
* @param path - Dot-separated path to the value
|
|
18
|
-
* @param value - The new value to compare
|
|
19
|
-
* @returns Diff results showing changes
|
|
20
|
-
*/
|
|
21
|
-
DiffPath(path: string, value: any, flatten?: boolean): JsonDiffResult;
|
|
22
|
-
SplicePath(path: string, start: number, deleteCount: number | undefined, items: any[], flatten?: boolean): DiffSpliceResult;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Constructor interface for IDiffTree.
|
|
26
|
-
*/
|
|
27
|
-
export interface IDiffTreeConstructor {
|
|
28
|
-
/**
|
|
29
|
-
* Creates a new IDiffTree instance.
|
|
30
|
-
* @param keyFunc - Optional function to extract a key from a value
|
|
31
|
-
* @param projections - Optional map of derived-value projections, keyed by id
|
|
32
|
-
*/
|
|
33
|
-
new (keyFunc?: {
|
|
34
|
-
(val: any): string;
|
|
35
|
-
}, projections?: DiffTreeProjectionMap): IDiffTree;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* A pure function computing a derived value from the current values at `reads`. Called with
|
|
39
|
-
* the resolved read paths (`keys`) first, then each value positionally in the same order as
|
|
40
|
-
* `reads`, so each value parameter can be typed at the call site instead of cast out of a
|
|
41
|
-
* generic read. A trailing wildcard read expands to one key/value pair per matched root key,
|
|
42
|
-
* so `keys` lets the function tell which root each trailing value came from.
|
|
43
|
-
*/
|
|
44
|
-
export type DiffTreeProjectionFunc = (keys: string[], ...values: any[]) => any;
|
|
45
|
-
/**
|
|
46
|
-
* A projection's declaration: the dot-separated paths it reads (a plain tree path, an
|
|
47
|
-
* entity's key, or another projection's `$projection_<id>` key for chaining) and the
|
|
48
|
-
* function computing its result from their current values, positionally. Declaring `reads`
|
|
49
|
-
* up front lets the tree topologically sort projections and reject a dependency cycle at
|
|
50
|
-
* construction instead of on first write.
|
|
51
|
-
*
|
|
52
|
-
* The final entry in `reads` may instead be a wildcard root key (e.g. `"user_*"`, no dot
|
|
53
|
-
* nesting) matching every root key with that prefix; each match is read and passed to the
|
|
54
|
-
* projection as its own trailing key/value pair. A wildcard read can't be chained off a
|
|
55
|
-
* projection's `$projection_<id>` key and can't appear anywhere but last.
|
|
56
|
-
*/
|
|
57
|
-
export type DiffTreeProjectionDefinition = {
|
|
58
|
-
reads: string[];
|
|
59
|
-
projection: DiffTreeProjectionFunc;
|
|
60
|
-
};
|
|
61
|
-
/** A map of projection id to its declaration, keyed by the id used in `$projection_<id>`. */
|
|
62
|
-
export type DiffTreeProjectionMap = {
|
|
63
|
-
[id: string]: DiffTreeProjectionDefinition;
|
|
64
|
-
};
|
|
65
|
-
/** Reserved key prefix a projection's result is stored under: `$projection_<id>`. */
|
|
66
|
-
export declare const PROJECTION_PREFIX = "$projection_";
|
|
67
|
-
export type DiffSpliceResult<T = unknown> = {
|
|
68
|
-
/** Array path segments (strings for object keys, numbers for array indices) */
|
|
69
|
-
path: (string | number)[];
|
|
70
|
-
/** Required by the splice operation **/
|
|
71
|
-
start: number;
|
|
72
|
-
deleteCount: number;
|
|
73
|
-
spliceResult: any[];
|
|
74
|
-
diffResult: JsonDiffResult;
|
|
75
|
-
};
|
|
76
|
-
/**
|
|
77
|
-
* Diff tree implementation. Maintains root state and computes diffs for path/value updates.
|
|
78
|
-
* Used directly by `DiffSync`, and is the building block for a `DiffAsync` worker entry
|
|
79
|
-
* file: construct one with the desired `keyFunc`/`projections` and connect it to the worker
|
|
80
|
-
* thread with `ConnectWorkerToDiffTree` (see `defaultDiffTreeWorker.ts` for the no-argument
|
|
81
|
-
* case, or a custom entry file when either is needed).
|
|
82
|
-
*/
|
|
83
|
-
export declare class DiffTree {
|
|
84
|
-
private keyFunc?;
|
|
85
|
-
private rootState;
|
|
86
|
-
private projectionOrder;
|
|
87
|
-
private projectionMemo;
|
|
88
|
-
/**
|
|
89
|
-
* Creates a DiffTree instance.
|
|
90
|
-
* @param keyFunc - Optional function to extract a key from objects
|
|
91
|
-
* @param projections - Optional map of derived-value projections, keyed by id. Cycles
|
|
92
|
-
* and reads of an unregistered projection id are rejected here, at construction.
|
|
93
|
-
*/
|
|
94
|
-
constructor(keyFunc?: {
|
|
95
|
-
(val: any): string;
|
|
96
|
-
}, projections?: DiffTreeProjectionMap);
|
|
97
|
-
private RunProjections;
|
|
98
|
-
/**
|
|
99
|
-
* Computes diffs for a batch of path/value pairs.
|
|
100
|
-
* @param data - Array of objects with path and value properties
|
|
101
|
-
* @returns Combined diff results
|
|
102
|
-
*/
|
|
103
|
-
DiffBatch(data: Array<{
|
|
104
|
-
path: string;
|
|
105
|
-
value: any;
|
|
106
|
-
}>): {
|
|
107
|
-
path: (string | number)[];
|
|
108
|
-
value: unknown;
|
|
109
|
-
}[];
|
|
110
|
-
/**
|
|
111
|
-
* Computes the diff between a new value and the current value at a path.
|
|
112
|
-
* @param path - Dot-separated path to the value
|
|
113
|
-
* @param value - The new value to compare
|
|
114
|
-
* @returns Diff results showing changes
|
|
115
|
-
*/
|
|
116
|
-
DiffPath(path: string, value: any, flatten?: boolean): JsonDiffResult;
|
|
117
|
-
PatchPath(path: string, patch: any): JsonDiffResult;
|
|
118
|
-
PushPath(path: string, data: unknown[]): {
|
|
119
|
-
path: (string | number)[];
|
|
120
|
-
value: unknown;
|
|
121
|
-
}[];
|
|
122
|
-
SplicePath(path: string, start: number, deleteCount: number, items: any[], flatten?: boolean): DiffSpliceResult<unknown>;
|
|
123
|
-
/**
|
|
124
|
-
* Retrieves the current value at a path.
|
|
125
|
-
* @param path - Dot-separated path to the value
|
|
126
|
-
* @returns The value at the specified path
|
|
127
|
-
*/
|
|
128
|
-
GetPath(path: string): any;
|
|
129
|
-
/**
|
|
130
|
-
* Returns an immutable, cached snapshot of the value at a path (empty string for the
|
|
131
|
-
* whole tree). Not part of `IDiffTree`; internal, for a future feature.
|
|
132
|
-
* @param path - Dot-separated path to the value
|
|
133
|
-
*/
|
|
134
|
-
Snapshot(path: string): any;
|
|
135
|
-
}
|