j-templates 7.0.90 → 7.0.92

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.
@@ -1,58 +1,52 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ObservableNode = exports.GET_TO_JSON = exports.GET_OBSERVABLE_VALUE = exports.IS_OBSERVABLE_NODE = void 0;
3
+ exports.ObservableNode = void 0;
4
4
  const json_1 = require("../../Utils/json");
5
5
  const json_2 = require("../../Utils/json");
6
6
  const observableScope_1 = require("./observableScope");
7
- /**
8
- * Symbol to identify observable nodes.
9
- * Used to check if a value is an observable node proxy.
10
- */
11
- exports.IS_OBSERVABLE_NODE = Symbol("isObservableNode");
12
- /**
13
- * Symbol to get the raw underlying value from an observable node.
14
- * Returns the unwrapped, non-proxied value.
15
- */
16
- exports.GET_OBSERVABLE_VALUE = Symbol("getObservableValue");
17
- /**
18
- * Symbol for the toJSON method on observable nodes.
19
- * Used to serialize observable nodes to plain JSON.
20
- */
21
- exports.GET_TO_JSON = Symbol("toJSON");
22
- const proxyCache = new WeakMap();
23
- const scopeCache = new WeakMap();
24
- const leafScopeCache = new WeakMap();
7
+ const NODE_VALUE = Symbol("NODE_VALUE");
8
+ const NODE_PROXY = Symbol("NODE_PROXY");
9
+ const toJSON = "toJSON";
10
+ const IS_NODE = Symbol("IS_NODE");
11
+ const ARRAY_SCOPE = "ARRAY_SCOPE";
12
+ function Identity(value) {
13
+ return value;
14
+ }
15
+ function Property(value, prop) {
16
+ return value[prop];
17
+ }
18
+ const wrapperCache = new WeakMap();
25
19
  function getOwnPropertyDescriptor(target, prop) {
26
- const descriptor = Object.getOwnPropertyDescriptor(target, prop);
20
+ const descriptor = Object.getOwnPropertyDescriptor(target[NODE_VALUE], prop);
27
21
  return {
28
22
  ...descriptor,
29
23
  configurable: true,
30
24
  };
31
25
  }
32
26
  function getOwnPropertyDescriptorArray(target, prop) {
33
- const descriptor = Object.getOwnPropertyDescriptor(target, prop);
27
+ const descriptor = Object.getOwnPropertyDescriptor(target[NODE_VALUE], prop);
34
28
  return {
35
29
  ...descriptor,
36
30
  configurable: true,
37
31
  };
38
32
  }
39
33
  function has(value, prop) {
40
- return Object.hasOwn(value, prop);
34
+ return Object.hasOwn(value[NODE_VALUE], prop);
41
35
  }
42
36
  function hasArray(value, prop) {
43
- return Object.hasOwn(value, prop);
37
+ return Object.hasOwn(value[NODE_VALUE], prop);
44
38
  }
45
39
  function ownKeys(value) {
46
- return Object.keys(value);
40
+ return Object.keys(value[NODE_VALUE]);
47
41
  }
48
42
  function ownKeysArray(value) {
49
- return Object.keys(value);
43
+ return Object.keys(value[NODE_VALUE]);
50
44
  }
51
45
  function UnwrapProxy(value, type = (0, json_2.JsonType)(value)) {
52
46
  if (type === "value")
53
47
  return value;
54
- if (value[exports.IS_OBSERVABLE_NODE])
55
- return value[exports.GET_OBSERVABLE_VALUE];
48
+ if (value[IS_NODE])
49
+ return value[NODE_VALUE];
56
50
  switch (type) {
57
51
  case "object": {
58
52
  const keys = Object.keys(value);
@@ -69,10 +63,6 @@ function UnwrapProxy(value, type = (0, json_2.JsonType)(value)) {
69
63
  return value;
70
64
  }
71
65
  function CreateProxyFactory(alias) {
72
- function CreateProxy(value) {
73
- value = UnwrapProxy(value);
74
- return CreateProxyFromValue(value);
75
- }
76
66
  function ToJsonCopy(value) {
77
67
  const type = (0, json_2.JsonType)(value);
78
68
  switch (type) {
@@ -99,41 +89,42 @@ function CreateProxyFactory(alias) {
99
89
  }
100
90
  const ToJson = alias !== undefined ? ToJsonCopy : ToJsonDefault;
101
91
  const readOnly = alias !== undefined;
92
+ function SetObjectValue(object, prop, value) {
93
+ object[NODE_VALUE][prop] = value;
94
+ observableScope_1.ObservableScope.Update(object[prop]);
95
+ }
96
+ function SetArrayValue(object, prop, value) {
97
+ object[NODE_VALUE][prop] = value;
98
+ observableScope_1.ObservableScope.Update(object[ARRAY_SCOPE]);
99
+ }
100
+ function CreateProxy(value) {
101
+ value = UnwrapProxy(value);
102
+ return CreateProxyFromValue(value);
103
+ }
102
104
  function CreateArrayProxy(value) {
103
- const scope = observableScope_1.ObservableScope.Create(() => value, false, true);
104
- const proxy = new Proxy(value, {
105
+ const wrapper = Object.assign([], {
106
+ [NODE_VALUE]: value,
107
+ [NODE_PROXY]: null,
108
+ [ARRAY_SCOPE]: observableScope_1.ObservableScope.Basic(Identity.bind(null, value))
109
+ });
110
+ const proxy = wrapper[NODE_PROXY] = new Proxy(wrapper, {
105
111
  get: ArrayProxyGetter,
106
112
  set: ArrayProxySetter,
107
113
  has: hasArray,
108
114
  ownKeys: ownKeysArray,
109
115
  getOwnPropertyDescriptor: getOwnPropertyDescriptorArray,
110
116
  });
111
- scopeCache.set(value, scope);
112
- proxyCache.set(value, proxy);
113
- return proxy;
114
- }
115
- function CreateObjectProxy(value) {
116
- const proxy = new Proxy(value, {
117
- get: ObjectProxyGetter,
118
- set: ObjectProxySetter,
119
- has,
120
- ownKeys,
121
- getOwnPropertyDescriptor,
122
- });
123
- leafScopeCache.set(value, {});
124
- proxyCache.set(value, proxy);
117
+ wrapperCache.set(value, wrapper);
125
118
  return proxy;
126
119
  }
127
- function ArrayProxySetter(array, prop, value) {
120
+ function ArrayProxySetter(object, prop, value) {
128
121
  if (readOnly)
129
122
  throw `Object is readonly`;
130
123
  value = UnwrapProxy(value);
131
- array[prop] = value;
132
- const scope = scopeCache.get(array);
133
- observableScope_1.ObservableScope.Update(scope);
124
+ SetArrayValue(object, prop, value);
134
125
  return true;
135
126
  }
136
- function ArrayProxyGetter(array, prop) {
127
+ function ArrayProxyGetter(object, prop) {
137
128
  if (readOnly)
138
129
  switch (prop) {
139
130
  case "push":
@@ -146,25 +137,23 @@ function CreateProxyFactory(alias) {
146
137
  throw "Object is readonly";
147
138
  }
148
139
  switch (prop) {
149
- case exports.IS_OBSERVABLE_NODE:
140
+ case IS_NODE:
150
141
  return true;
151
- case exports.GET_TO_JSON:
142
+ case toJSON:
152
143
  return function () {
153
- return ToJson(array);
144
+ return ToJson(object[NODE_VALUE]);
154
145
  };
155
- case exports.GET_OBSERVABLE_VALUE:
156
- return array;
146
+ case NODE_VALUE:
147
+ return object[NODE_VALUE];
157
148
  default: {
158
- const scope = scopeCache.get(array);
159
- array = observableScope_1.ObservableScope.Value(scope);
149
+ const scope = object[ARRAY_SCOPE]; // scopeCache.get(array) as IObservableScope<unknown[]>;
150
+ const array = observableScope_1.ObservableScope.Value(scope);
160
151
  const arrayValue = array[prop];
161
152
  if (typeof prop === "symbol")
162
153
  return arrayValue;
163
154
  if (typeof arrayValue === "function")
164
155
  return function ArrayFunction(...args) {
165
- const proxyArray = prop === "slice" ? array.slice(...args) : array.slice();
166
- for (let x = 0; x < proxyArray.length; x++)
167
- proxyArray[x] = CreateProxyFromValue(proxyArray[x]);
156
+ const proxyArray = prop === "slice" ? array.slice(...args).map(CreateProxyFromValue) : array.map(CreateProxyFromValue);
168
157
  let result = prop === "slice"
169
158
  ? proxyArray
170
159
  : proxyArray[prop](...args);
@@ -189,82 +178,77 @@ function CreateProxyFactory(alias) {
189
178
  }
190
179
  }
191
180
  }
192
- function SetPropertyValue(object, prop, value) {
193
- object[prop] = value;
194
- const leafScopes = leafScopeCache.get(object);
195
- observableScope_1.ObservableScope.Update((leafScopes && leafScopes[prop]) || scopeCache.get(object));
181
+ function CreateObjectProxy(value) {
182
+ const wrapper = {
183
+ [NODE_VALUE]: value,
184
+ [NODE_PROXY]: null
185
+ };
186
+ const proxy = wrapper[NODE_PROXY] = new Proxy(wrapper, {
187
+ get: ObjectProxyGetter,
188
+ set: ObjectProxySetter,
189
+ has,
190
+ ownKeys,
191
+ getOwnPropertyDescriptor,
192
+ });
193
+ wrapperCache.set(value, wrapper);
194
+ return proxy;
196
195
  }
197
196
  function ObjectProxySetter(object, prop, value) {
198
197
  if (readOnly)
199
198
  throw `Object is readonly`;
200
- const jsonType = (0, json_2.JsonType)(value);
201
- if (jsonType === "value") {
202
- value !== object[prop] && SetPropertyValue(object, prop, value);
203
- }
204
- else {
205
- value = UnwrapProxy(value, jsonType);
206
- const diff = (0, json_1.JsonDiff)(value, object[prop]);
207
- for (let x = 0; x < diff.length; x++) {
208
- if (diff[x].path.length === 0) {
209
- SetPropertyValue(object, prop, diff[x].value);
210
- }
211
- else {
212
- const path = diff[x].path;
213
- let curr = object[prop];
214
- let y = 0;
215
- for (; y < path.length - 1; y++)
216
- curr = curr[path[y]];
217
- SetPropertyValue(curr, path[y], diff[x].value);
218
- }
219
- }
220
- }
199
+ value = UnwrapProxy(value);
200
+ SetObjectValue(object, prop, value);
221
201
  return true;
222
202
  }
223
203
  function ObjectProxyGetter(object, prop) {
224
204
  switch (prop) {
225
- case exports.IS_OBSERVABLE_NODE:
205
+ case IS_NODE:
226
206
  return true;
227
- case exports.GET_TO_JSON:
207
+ case toJSON:
228
208
  return function () {
229
209
  return ToJson(object);
230
210
  };
231
- case exports.GET_OBSERVABLE_VALUE:
232
- return object;
211
+ case NODE_VALUE:
212
+ return object[NODE_VALUE];
233
213
  default: {
234
214
  return GetAccessorValue(object, prop);
235
215
  }
236
216
  }
237
217
  }
238
- function GetAccessorValue(parent, prop) {
239
- const leafScopes = leafScopeCache.get(parent);
240
- leafScopes[prop] ??= observableScope_1.ObservableScope.Create(function () {
241
- const value = parent[prop];
242
- return CreateProxyFromValue(value);
243
- }, false, true);
244
- return observableScope_1.ObservableScope.Value(leafScopes[prop]);
218
+ function GetAccessorValue(object, prop) {
219
+ const scope = object[prop] ??= observableScope_1.ObservableScope.Basic(Property.bind(null, object[NODE_VALUE], prop));
220
+ const value = observableScope_1.ObservableScope.Value(scope);
221
+ return CreateProxyFromValue(value);
245
222
  }
246
223
  function CreateProxyFromValue(value) {
247
224
  const type = (0, json_2.JsonType)(value);
248
225
  switch (type) {
249
226
  case "object": {
250
- let proxy = proxyCache.get(value) ?? CreateObjectProxy(value);
227
+ const wrapper = wrapperCache.get(value);
228
+ let proxy = wrapper?.[NODE_PROXY] ?? CreateObjectProxy(value);
251
229
  if (alias !== undefined) {
252
230
  const aliasValue = alias(proxy);
253
- if (aliasValue !== undefined)
254
- proxy = proxyCache.get(aliasValue) ?? CreateObjectProxy(aliasValue);
231
+ if (aliasValue !== undefined && aliasValue !== value) {
232
+ const wrapper = wrapperCache.get(aliasValue);
233
+ proxy = wrapper?.[NODE_PROXY] ?? CreateObjectProxy(aliasValue);
234
+ }
255
235
  }
256
236
  return proxy;
257
237
  }
258
238
  case "array": {
259
- const proxy = proxyCache.get(value) ?? CreateArrayProxy(value);
260
- observableScope_1.ObservableScope.Touch(scopeCache.get(value));
239
+ const wrapper = wrapperCache.get(value);
240
+ const proxy = wrapper?.[NODE_PROXY] ?? CreateArrayProxy(value);
241
+ observableScope_1.ObservableScope.Touch(wrapper?.[ARRAY_SCOPE]);
261
242
  return proxy;
262
243
  }
263
244
  default:
264
245
  return value;
265
246
  }
266
247
  }
267
- return CreateProxy;
248
+ return function CreateProxy(value) {
249
+ value = UnwrapProxy(value);
250
+ return CreateProxyFromValue(value);
251
+ };
268
252
  }
269
253
  const DefaultCreateProxy = CreateProxyFactory();
270
254
  var ObservableNode;
@@ -297,16 +281,20 @@ var ObservableNode;
297
281
  * @param value The observable node to touch.
298
282
  * @param prop Optional property name or index to touch a specific nested property.
299
283
  */
300
- function Touch(value, prop) {
301
- let scope;
302
- if (prop !== undefined) {
303
- const leafScopes = leafScopeCache.get(value);
304
- scope = leafScopes?.[prop];
284
+ function Touch(value, prop = ARRAY_SCOPE) {
285
+ const wrapper = wrapperCache.get(value);
286
+ if (wrapper) {
287
+ const scope = wrapper[prop] ?? wrapper[ARRAY_SCOPE];
288
+ observableScope_1.ObservableScope.Update(scope);
305
289
  }
306
- scope ??= scopeCache.get(value);
307
- observableScope_1.ObservableScope.Update(scope);
308
290
  }
309
291
  ObservableNode.Touch = Touch;
292
+ function Apply(rootNode, update) {
293
+ const root = rootNode[NODE_VALUE];
294
+ const diff = (0, json_1.JsonDiff)(update, root);
295
+ ApplyDiff(rootNode, diff);
296
+ }
297
+ ObservableNode.Apply = Apply;
310
298
  /**
311
299
  * Applies a JSON diff result to an observable node, efficiently updating only changed properties.
312
300
  * Optimizes nested object updates by computing paths incrementally and touching modified properties.
@@ -314,7 +302,36 @@ var ObservableNode;
314
302
  * @param diffResult The diff result from JsonDiff containing path-value pairs of changes.
315
303
  */
316
304
  function ApplyDiff(rootNode, diffResult) {
317
- const root = rootNode[exports.GET_OBSERVABLE_VALUE];
305
+ const root = rootNode[NODE_VALUE];
306
+ if (diffResult.length === 1 && diffResult[0].path.length === 0) {
307
+ // Replacing rootNode
308
+ const rootPatch = diffResult[0].value;
309
+ const rootType = (0, json_2.JsonType)(root);
310
+ const rootPatchType = (0, json_2.JsonType)(root);
311
+ if (rootType !== rootPatchType)
312
+ throw new Error("Unable to change type of Root ObservableNode: " + rootType);
313
+ switch (rootType) {
314
+ case "array": {
315
+ root.splice(0, root.length, ...rootPatch);
316
+ ObservableNode.Touch(root);
317
+ break;
318
+ }
319
+ case "object": {
320
+ const keys = Object.keys(root);
321
+ const patchKeys = Object.keys(rootPatch);
322
+ for (let x = 0; x < keys.length; x++)
323
+ if (!patchKeys.includes(keys[x]))
324
+ delete root[keys[x]];
325
+ Object.assign(root, rootPatch);
326
+ for (let x = 0; x < keys.length; x++)
327
+ ObservableNode.Touch(root, keys[x]);
328
+ break;
329
+ }
330
+ case "value":
331
+ throw new Error("Unable to replace value type: " + root);
332
+ }
333
+ return;
334
+ }
318
335
  const pathTuples = [["", root]];
319
336
  for (let x = 0; x < diffResult.length; x++) {
320
337
  const { path, value } = diffResult[x];
@@ -7,6 +7,14 @@ import { Emitter, EmitterCallback } from "../../Utils/emitter";
7
7
  interface IStaticObservableScope<T> {
8
8
  type: "static";
9
9
  value: T;
10
+ onDestroyed: Emitter | null;
11
+ destroyed: boolean;
12
+ }
13
+ export interface IBasicObservableScope<T> {
14
+ type: "basic";
15
+ emitter: Emitter;
16
+ getFunction: () => T;
17
+ destroyed: boolean;
10
18
  }
11
19
  /**
12
20
  * Represents a dynamic (reactive) observable scope.
@@ -34,12 +42,12 @@ interface IDynamicObservableScope<T> {
34
42
  emitter: Emitter;
35
43
  /** Array of emitters this scope listens to for dependency changes */
36
44
  emitters: (Emitter | null)[];
45
+ onUpdated: Emitter | null;
37
46
  /** Emitter for notifying when the scope is destroyed */
38
47
  onDestroyed: Emitter | null;
48
+ scopes: [any, IObservableScope<any>][] | null;
39
49
  /** Map of nested scopes created during this scope's execution */
40
- scopes: {
41
- [id: string]: IObservableScope<unknown> | null;
42
- } | null;
50
+ mappedScopes: Map<any, IObservableScope<unknown>[]> | null;
43
51
  }
44
52
  /**
45
53
  * A reactive or static scope containing a value.
@@ -63,6 +71,7 @@ export type IObservableScope<T> = IStaticObservableScope<T> | IDynamicObservable
63
71
  * @throws Error if called outside a watch context.
64
72
  */
65
73
  export declare function InlineScope<T>(callback: () => T | Promise<T>, idOverride?: string): T;
74
+ export declare function MappedScope<D, T>(data: D, callback: (data: D) => T | Promise<T>, onUpdated?: (lastValue: T, scope: IObservableScope<T>) => void, onDestroyed?: (lastValue: T) => void): T;
66
75
  /**
67
76
  * Creates a gatekeeper scope that only emits when the value actually changes (===).
68
77
  * Prevents unnecessary downstream re-evaluations when the derived value stays the same.
@@ -114,7 +123,13 @@ export declare namespace ObservableScope {
114
123
  */
115
124
  function Create<T>(valueFunction: {
116
125
  (): T | Promise<T>;
117
- }, greedy?: boolean, force?: boolean): IObservableScope<T>;
126
+ }): IObservableScope<T>;
127
+ function Greedy<T>(valueFunction: {
128
+ (): T | Promise<T>;
129
+ }): IObservableScope<T>;
130
+ function Basic<T>(valueFunction: {
131
+ (): T;
132
+ }): IBasicObservableScope<T>;
118
133
  /**
119
134
  * Registers an emitter as a dependency for the current watch context.
120
135
  * @param emitter The emitter to register as a dependency.
@@ -126,20 +141,20 @@ export declare namespace ObservableScope {
126
141
  * @param scope The scope to peek at.
127
142
  * @returns The scope's current value.
128
143
  */
129
- function Peek<T>(scope: IObservableScope<T>): T;
144
+ function Peek<T>(scope: IObservableScope<T> | IBasicObservableScope<T>): T;
130
145
  /**
131
146
  * Gets a scope's current value and registers as a dependency.
132
147
  * @template T The type of value stored in the scope.
133
148
  * @param scope The scope to get the value from.
134
149
  * @returns The scope's current value.
135
150
  */
136
- function Value<T>(scope: IObservableScope<T>): T;
151
+ function Value<T>(scope: IObservableScope<T> | IBasicObservableScope<T>): T;
137
152
  /**
138
153
  * Registers a scope as a dependency without retrieving its value.
139
154
  * @template T The type of value stored in the scope.
140
155
  * @param scope The scope to register as a dependency.
141
156
  */
142
- function Touch<T>(scope: IObservableScope<T>): void;
157
+ function Touch<T>(scope: IObservableScope<T> | IBasicObservableScope<T>): void;
143
158
  /**
144
159
  * Subscribes to changes on a dynamic scope.
145
160
  * @template T The type of value stored in the scope.
@@ -154,25 +169,28 @@ export declare namespace ObservableScope {
154
169
  * @param callback The callback function to remove.
155
170
  */
156
171
  function Unwatch<T>(scope: IObservableScope<T>, callback: (scope: IObservableScope<T>) => void): void;
172
+ function OnUpdated<T>(scope: IObservableScope<T>, callback: {
173
+ (lastValue: T, scope: IObservableScope<T>): void;
174
+ }): void;
157
175
  /**
158
176
  * Registers a callback to be invoked when the scope is destroyed.
159
177
  * @param scope The scope to monitor for destruction.
160
178
  * @param callback Function to invoke when the scope is destroyed.
161
179
  */
162
- function OnDestroyed(scope: IObservableScope<unknown>, callback: {
163
- (): void;
180
+ function OnDestroyed<T>(scope: IObservableScope<T>, callback: {
181
+ (lastValue: T): void;
164
182
  }): void;
165
183
  /**
166
184
  * Marks a scope as dirty, triggering recomputation on next access or batch.
167
185
  * @param scope The scope to mark for update.
168
186
  */
169
- function Update(scope: IObservableScope<any>): void;
187
+ function Update(scope: IObservableScope<any> | IBasicObservableScope<any>): void;
170
188
  /**
171
189
  * Destroys a scope, cleaning up all resources and dependencies.
172
190
  * @template T The type of value stored in the scope.
173
191
  * @param scope The scope to destroy.
174
192
  */
175
- function Destroy<T>(scope: IObservableScope<T>): void;
193
+ function Destroy<T>(scope: IObservableScope<T> | IBasicObservableScope<T>): void;
176
194
  /**
177
195
  * Destroys multiple scopes, cleaning up their resources.
178
196
  * @param scopes Array of scopes to destroy.