j-templates 8.0.5 → 8.0.6

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.
@@ -28,7 +28,7 @@ export declare class DiffAsync implements IDiffTreeAsync {
28
28
  * @param value - The new value to compare
29
29
  * @returns Promise that resolves to diff results showing changes
30
30
  */
31
- DiffPath(path: string, value: any): Promise<JsonDiffResult>;
31
+ DiffPath(path: string, value: any, flatten?: boolean): Promise<JsonDiffResult>;
32
32
  /**
33
33
  * Computes diffs for a batch of path/value pairs asynchronously.
34
34
  * @param data - Array of objects with path and value properties
@@ -28,10 +28,10 @@ class DiffAsync {
28
28
  * @param value - The new value to compare
29
29
  * @returns Promise that resolves to diff results showing changes
30
30
  */
31
- async DiffPath(path, value) {
31
+ async DiffPath(path, value, flatten = true) {
32
32
  return await this.workerQueue.Push({
33
33
  method: "diffpath",
34
- arguments: [path, value],
34
+ arguments: [path, value, flatten],
35
35
  });
36
36
  }
37
37
  /**
@@ -21,7 +21,7 @@ export declare class DiffSync implements IDiffTree {
21
21
  * @param value - The new value to compare
22
22
  * @returns Diff results showing changes
23
23
  */
24
- DiffPath(path: string, value: any): import("../../Utils/json").JsonDiffResult;
24
+ DiffPath(path: string, value: any, flatten?: boolean): import("../../Utils/json").JsonDiffResult;
25
25
  /**
26
26
  * Computes diffs for a batch of path/value pairs.
27
27
  * @param data - Array of objects with path and value properties
@@ -25,8 +25,8 @@ class DiffSync {
25
25
  * @param value - The new value to compare
26
26
  * @returns Diff results showing changes
27
27
  */
28
- DiffPath(path, value) {
29
- return this.diffTree.DiffPath(path, value);
28
+ DiffPath(path, value, flatten = true) {
29
+ return this.diffTree.DiffPath(path, value, flatten);
30
30
  }
31
31
  /**
32
32
  * Computes diffs for a batch of path/value pairs.
@@ -27,7 +27,7 @@ export interface IDiffTree {
27
27
  * @param value - The new value to compare
28
28
  * @returns Diff results showing changes
29
29
  */
30
- DiffPath(path: string, value: any): JsonDiffResult;
30
+ DiffPath(path: string, value: any, flatten?: boolean): JsonDiffResult;
31
31
  }
32
32
  /**
33
33
  * Constructor interface for IDiffTree.
@@ -25,7 +25,7 @@ function DiffTreeFactory(jsonDiffFactory, worker) {
25
25
  break;
26
26
  }
27
27
  case "diffpath": {
28
- const diff = diffTree.DiffPath(data.arguments[0], data.arguments[1]);
28
+ const diff = diffTree.DiffPath(data.arguments[0], data.arguments[1], data.arguments[2]);
29
29
  ctx.postMessage(diff);
30
30
  break;
31
31
  }
@@ -133,18 +133,18 @@ function DiffTreeFactory(jsonDiffFactory, worker) {
133
133
  * @param keyFunc - Optional function to extract keys from objects
134
134
  * @returns Diff results showing all changes made
135
135
  */
136
- function UpdateSource(source, path, value, keyFunc) {
136
+ function UpdateSource(source, path, value, flatten, keyFunc) {
137
137
  const diffResult = [];
138
138
  if (keyFunc) {
139
139
  const keyPath = ResolveKeyPath(source, path, keyFunc);
140
140
  if (keyPath !== path) {
141
- const keyDiffResult = UpdateSource(source, keyPath, value, keyFunc);
141
+ const keyDiffResult = UpdateSource(source, keyPath, value, flatten, keyFunc);
142
142
  diffResult.push(...keyDiffResult);
143
143
  }
144
144
  }
145
145
  const sourceValue = GetPathValue(source, path);
146
146
  JsonDiff(value, sourceValue, path, diffResult);
147
- if (keyFunc) {
147
+ if (flatten && keyFunc) {
148
148
  let flattened = {};
149
149
  flattened = FlattenValue(flattened, value, keyFunc);
150
150
  flattened = JsonDeepClone(flattened);
@@ -189,8 +189,8 @@ function DiffTreeFactory(jsonDiffFactory, worker) {
189
189
  * @param value - The new value to compare
190
190
  * @returns Diff results showing changes
191
191
  */
192
- DiffPath(path, value) {
193
- return UpdateSource(this.rootState, path, value, this.keyFunc);
192
+ DiffPath(path, value, flatten = true) {
193
+ return UpdateSource(this.rootState, path, value, flatten, this.keyFunc);
194
194
  }
195
195
  /**
196
196
  * Retrieves the current value at a path.
@@ -6,7 +6,7 @@ import { JsonDiffResult } from "../../Utils/json";
6
6
  * @see StoreSync
7
7
  * @see StoreAsync
8
8
  */
9
- export declare class Store {
9
+ export declare abstract class Store {
10
10
  protected keyFunc?: (value: any) => string | undefined;
11
11
  private rootMap;
12
12
  private createNode;
@@ -31,6 +31,10 @@ export declare class Store {
31
31
  * @returns The value or the default value
32
32
  */
33
33
  Get<O>(id: string, defaultValue: O): O;
34
+ abstract Write(data: unknown, key?: string): Promise<void> | void;
35
+ abstract Patch(key: string, patch: unknown): Promise<void> | void;
36
+ abstract Push(key: string, ...data: unknown[]): Promise<void> | void;
37
+ abstract Splice(key: string, start: number, deleteCount?: number, ...items: unknown[]): Promise<any[]> | any[];
34
38
  /**
35
39
  * Updates the root map with diff results by grouping changes by root path.
36
40
  * @param results - Array of diff results to apply
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Store = void 0;
4
+ const json_1 = require("../../Utils/json");
4
5
  const observableNode_1 = require("../Tree/observableNode");
5
6
  /**
6
7
  * Base class for observable data store management.
@@ -27,6 +28,7 @@ class Store {
27
28
  if (rootObject === undefined)
28
29
  throw `No root object found for key: ${key}`;
29
30
  const rootValue = observableNode_1.ObservableNode.Unwrap(rootObject); // rootObject[GET_OBSERVABLE_VALUE];
31
+ observableNode_1.ObservableNode.Touch(rootValue, key);
30
32
  const alias = rootValue[key];
31
33
  return alias;
32
34
  });
@@ -70,7 +72,7 @@ class Store {
70
72
  if (rootObject === undefined) {
71
73
  if (results.length > 1 || results[0].path.length > 1)
72
74
  throw `Unable to initialize root path ${rootPath} with ${results.length} results and initial path ${results[0].path}`;
73
- const newRootObject = this.createNode({ [rootPath]: results[0].value });
75
+ const newRootObject = this.createNode({ [rootPath]: (0, json_1.JsonDeepClone)(results[0].value) });
74
76
  this.rootMap.set(rootPath, newRootObject);
75
77
  return;
76
78
  }
@@ -47,6 +47,10 @@ export declare class StoreAsync extends Store {
47
47
  * @param keyFunc Optional function to generate a key for a given data value.
48
48
  */
49
49
  constructor(keyFunc?: (value: any) => string | undefined);
50
+ /**
51
+ * Returns a promise that resolve once all current queued writes have completed
52
+ */
53
+ Flush(): Promise<void>;
50
54
  /**
51
55
  * Writes data to the store asynchronously.
52
56
  * This method ensures that write operations are queued and executed in a non-blocking manner.
@@ -52,6 +52,12 @@ class StoreAsync extends store_1.Store {
52
52
  this.queue = new asyncQueue_1.AsyncQueue();
53
53
  this.diff = new diffAsync_1.DiffAsync(keyFunc);
54
54
  }
55
+ /**
56
+ * Returns a promise that resolve once all current queued writes have completed
57
+ */
58
+ async Flush() {
59
+ return this.queue.Flush();
60
+ }
55
61
  /**
56
62
  * Writes data to the store asynchronously.
57
63
  * This method ensures that write operations are queued and executed in a non-blocking manner.
@@ -82,7 +88,7 @@ class StoreAsync extends store_1.Store {
82
88
  throw "Unable to patch undefined value";
83
89
  const json = value.toJSON();
84
90
  const mergedJson = (0, json_1.JsonMerge)(json, patch);
85
- const diffResult = await this.diff.DiffPath(key, mergedJson);
91
+ const diffResult = await this.diff.DiffPath(key, mergedJson, false);
86
92
  this.UpdateRootMap(diffResult);
87
93
  });
88
94
  }
@@ -68,7 +68,7 @@ class StoreSync extends store_1.Store {
68
68
  throw "Unable to patch undefined value";
69
69
  const json = observableNode_1.ObservableNode.Unwrap(value);
70
70
  const mergedJson = (0, json_1.JsonMerge)(json, patch);
71
- const diffResult = this.diff.DiffPath(key, mergedJson);
71
+ const diffResult = this.diff.DiffPath(key, mergedJson, false);
72
72
  this.UpdateRootMap(diffResult);
73
73
  }
74
74
  /**
@@ -46,6 +46,9 @@ export declare namespace ObservableNode {
46
46
  * @param prop Optional property name or index to touch a specific nested property.
47
47
  */
48
48
  function Update<T>(value: T, prop?: keyof T): void;
49
+ function Assign<T>(value: T, prop: keyof T, propValue: any): void;
50
+ function Touch<T>(value: T, prop?: keyof T): void;
51
+ function Read<T>(value: T, prop: keyof T): void;
49
52
  /**
50
53
  * Merges a new value into an observable node in-place, preserving the node's object identity.
51
54
  * Computes the diff between the node's current value and the provided value, then applies only
@@ -8,7 +8,8 @@ const NODE_VALUE = Symbol("NODE_VALUE");
8
8
  const NODE_PROXY = Symbol("NODE_PROXY");
9
9
  const toJSON = "toJSON";
10
10
  const IS_NODE = Symbol("IS_NODE");
11
- const OBJECT_SCOPE = Symbol("ARRAY_SCOPE");
11
+ const OBJECT_SCOPE = Symbol("OBJECT_SCOPE");
12
+ const ITERATOR_SCOPE = Symbol("ITERATOR_SCOPE");
12
13
  function Identity(value) {
13
14
  return value;
14
15
  }
@@ -31,15 +32,19 @@ function getOwnPropertyDescriptorArray(target, prop) {
31
32
  };
32
33
  }
33
34
  function has(value, prop) {
35
+ observableScope_1.ObservableScope.Touch(value[ITERATOR_SCOPE]);
34
36
  return Object.hasOwn(value[NODE_VALUE], prop);
35
37
  }
36
38
  function hasArray(value, prop) {
39
+ observableScope_1.ObservableScope.Touch(value[ITERATOR_SCOPE]);
37
40
  return Object.hasOwn(value[NODE_VALUE], prop);
38
41
  }
39
42
  function ownKeys(value) {
43
+ observableScope_1.ObservableScope.Touch(value[ITERATOR_SCOPE]);
40
44
  return Object.keys(value[NODE_VALUE]);
41
45
  }
42
46
  function ownKeysArray(value) {
47
+ observableScope_1.ObservableScope.Touch(value[ITERATOR_SCOPE]);
43
48
  return Object.keys(value[NODE_VALUE]);
44
49
  }
45
50
  function UnwrapProxy(value, type = (0, json_2.JsonType)(value)) {
@@ -85,6 +90,9 @@ function CloneProxy(value, type = (0, json_2.JsonType)(value)) {
85
90
  }
86
91
  return value;
87
92
  }
93
+ function GetPropertyScope(object, prop) {
94
+ return object[prop] ??= observableScope_1.ObservableScope.Basic(Property.bind(null, object[NODE_VALUE], prop));
95
+ }
88
96
  function CreateProxyFactory(alias) {
89
97
  function ToJsonCopy(value) {
90
98
  const type = (0, json_2.JsonType)(value);
@@ -204,7 +212,8 @@ function CreateProxyFactory(alias) {
204
212
  function CreateObjectProxy(value) {
205
213
  const wrapper = {
206
214
  [NODE_VALUE]: value,
207
- [NODE_PROXY]: null
215
+ [NODE_PROXY]: null,
216
+ [ITERATOR_SCOPE]: observableScope_1.ObservableScope.Basic(Identity.bind(null, value))
208
217
  };
209
218
  const proxy = wrapper[NODE_PROXY] = new Proxy(wrapper, {
210
219
  get: ObjectProxyGetter,
@@ -224,6 +233,7 @@ function CreateProxyFactory(alias) {
224
233
  return true;
225
234
  }
226
235
  function ObjectProxyGetter(object, prop) {
236
+ observableScope_1.ObservableScope.Touch(object[OBJECT_SCOPE]);
227
237
  switch (prop) {
228
238
  case IS_NODE:
229
239
  return true;
@@ -239,7 +249,7 @@ function CreateProxyFactory(alias) {
239
249
  }
240
250
  }
241
251
  function GetAccessorValue(object, prop) {
242
- const scope = object[prop] ??= observableScope_1.ObservableScope.Basic(Property.bind(null, object[NODE_VALUE], prop));
252
+ const scope = GetPropertyScope(object, prop);
243
253
  const value = observableScope_1.ObservableScope.Value(scope);
244
254
  return CreateProxyFromValue(value);
245
255
  }
@@ -330,14 +340,51 @@ var ObservableNode;
330
340
  * @param value The observable node to touch.
331
341
  * @param prop Optional property name or index to touch a specific nested property.
332
342
  */
333
- function Update(value, prop = OBJECT_SCOPE) {
343
+ function Update(value, prop) {
334
344
  const wrapper = wrapperCache.get(value);
335
345
  if (wrapper) {
336
- const scope = Array.isArray(wrapper) ? wrapper[OBJECT_SCOPE] : wrapper[prop] ?? wrapper[OBJECT_SCOPE];
346
+ const scope = Array.isArray(wrapper) ? wrapper[OBJECT_SCOPE] : (prop && wrapper[prop]) ?? wrapper[ITERATOR_SCOPE];
337
347
  observableScope_1.ObservableScope.Update(scope);
338
348
  }
339
349
  }
340
350
  ObservableNode.Update = Update;
351
+ function Assign(value, prop, propValue) {
352
+ const propExists = Object.hasOwn(value, prop);
353
+ value[prop] = propValue;
354
+ const wrapper = wrapperCache.get(value);
355
+ if (wrapper) {
356
+ if (Array.isArray(wrapper))
357
+ observableScope_1.ObservableScope.Update(wrapper[OBJECT_SCOPE]);
358
+ else {
359
+ const scope = wrapper[prop];
360
+ if (scope) {
361
+ // A prop was just added to the object, fire the iterator scope
362
+ if (!propExists)
363
+ observableScope_1.ObservableScope.Update(wrapper[ITERATOR_SCOPE]);
364
+ observableScope_1.ObservableScope.Update(scope);
365
+ }
366
+ else
367
+ observableScope_1.ObservableScope.Update(wrapper[ITERATOR_SCOPE]);
368
+ }
369
+ }
370
+ }
371
+ ObservableNode.Assign = Assign;
372
+ function Touch(value, prop) {
373
+ const wrapper = wrapperCache.get(value);
374
+ if (wrapper) {
375
+ const scope = prop && GetPropertyScope(wrapper, prop) || wrapper[OBJECT_SCOPE];
376
+ observableScope_1.ObservableScope.Touch(scope);
377
+ }
378
+ }
379
+ ObservableNode.Touch = Touch;
380
+ function Read(value, prop) {
381
+ const wrapper = wrapperCache.get(value);
382
+ if (wrapper) {
383
+ const scope = Array.isArray(wrapper) ? wrapper[OBJECT_SCOPE] : (prop && wrapper[prop]) ?? wrapper[ITERATOR_SCOPE];
384
+ observableScope_1.ObservableScope.Update(scope);
385
+ }
386
+ }
387
+ ObservableNode.Read = Read;
341
388
  /**
342
389
  * Merges a new value into an observable node in-place, preserving the node's object identity.
343
390
  * Computes the diff between the node's current value and the provided value, then applies only
@@ -372,7 +419,7 @@ var ObservableNode;
372
419
  const root = rootNode[NODE_VALUE];
373
420
  if (diffResult.length === 1 && diffResult[0].path.length === 0) {
374
421
  // Replacing rootNode
375
- const rootPatch = diffResult[0].value;
422
+ const rootPatch = (0, json_1.JsonDeepClone)(diffResult[0].value);
376
423
  const rootType = (0, json_2.JsonType)(root);
377
424
  const rootPatchType = (0, json_2.JsonType)(rootPatch);
378
425
  if (rootType !== rootPatchType)
@@ -418,8 +465,9 @@ var ObservableNode;
418
465
  }
419
466
  }
420
467
  const assignValue = pathTuples[y][1];
421
- assignValue[path[y]] = value;
422
- ObservableNode.Update(assignValue, path[y]);
468
+ // assignValue[path[y]] = JsonDeepClone(value);
469
+ // ObservableNode.Update(assignValue, path[y]);
470
+ ObservableNode.Assign(assignValue, path[y], (0, json_1.JsonDeepClone)(value));
423
471
  }
424
472
  }
425
473
  ObservableNode.ApplyDiff = ApplyDiff;
package/Store/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export { Store } from "./Store/store";
1
2
  export { StoreSync } from "./Store/storeSync";
2
3
  export { StoreAsync } from "./Store/storeAsync";
3
4
  export { ObservableScope } from "./Tree/observableScope";
package/Store/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ObservableNode = exports.ObservableScope = exports.StoreAsync = exports.StoreSync = void 0;
3
+ exports.ObservableNode = exports.ObservableScope = exports.StoreAsync = exports.StoreSync = exports.Store = void 0;
4
+ var store_1 = require("./Store/store");
5
+ Object.defineProperty(exports, "Store", { enumerable: true, get: function () { return store_1.Store; } });
4
6
  var storeSync_1 = require("./Store/storeSync");
5
7
  Object.defineProperty(exports, "StoreSync", { enumerable: true, get: function () { return storeSync_1.StoreSync; } });
6
8
  var storeAsync_1 = require("./Store/storeAsync");
@@ -4,6 +4,7 @@
4
4
  export declare class AsyncQueue {
5
5
  private running;
6
6
  private queue;
7
+ Flush(): Promise<void>;
7
8
  /**
8
9
  * Adds a callback to the queue and returns a promise that resolves when it executes.
9
10
  * @template T - The type the callback promise resolves to
@@ -10,6 +10,13 @@ class AsyncQueue {
10
10
  this.running = false;
11
11
  this.queue = list_1.List.Create();
12
12
  }
13
+ Flush() {
14
+ const ret = new Promise(resolve => {
15
+ list_1.List.Add(this.queue, resolve);
16
+ });
17
+ this.Start();
18
+ return ret;
19
+ }
13
20
  /**
14
21
  * Adds a callback to the queue and returns a promise that resolves when it executes.
15
22
  * @template T - The type the callback promise resolves to
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "j-templates",
3
- "version": "8.0.5",
3
+ "version": "8.0.6",
4
4
  "description": "j-templates",
5
5
  "license": "MIT",
6
6
  "repository": "https://github.com/TypesInCode/jTemplates",