j-templates 7.0.84 → 7.0.85
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/Tree/observableScope.d.ts +19 -2
- package/Store/Tree/observableScope.js +58 -23
- package/index.d.ts +1 -1
- package/index.js +2 -1
- package/package.json +1 -1
|
@@ -35,8 +35,8 @@ interface IDynamicObservableScope<T> {
|
|
|
35
35
|
emitters: (Emitter | null)[];
|
|
36
36
|
/** Emitter for notifying when the scope is destroyed */
|
|
37
37
|
onDestroyed: Emitter | null;
|
|
38
|
-
/** Map of nested
|
|
39
|
-
|
|
38
|
+
/** Map of nested scopes created during this scope's execution */
|
|
39
|
+
scopes: {
|
|
40
40
|
[id: string]: IObservableScope<unknown> | null;
|
|
41
41
|
} | null;
|
|
42
42
|
}
|
|
@@ -61,6 +61,23 @@ export type IObservableScope<T> = IStaticObservableScope<T> | IDynamicObservable
|
|
|
61
61
|
* @returns The computed value, reusing existing scope if available.
|
|
62
62
|
*/
|
|
63
63
|
export declare function CalcScope<T>(callback: () => T, idOverride?: string): T;
|
|
64
|
+
/**
|
|
65
|
+
* Creates a computed scope that isn't registered as a dependency with the parent.
|
|
66
|
+
* Use this function to read reactive data without subscribing to changes
|
|
67
|
+
* to that data.
|
|
68
|
+
*
|
|
69
|
+
* Unlike CalcScope, PeekScope does not register itself as a dependency, meaning
|
|
70
|
+
* changes to the data accessed within the callback will not trigger recomputation
|
|
71
|
+
* of the parent scope. The scope is still memoized by ID within the watch context
|
|
72
|
+
* to avoid redundant computation during the same evaluation.
|
|
73
|
+
*
|
|
74
|
+
* Only works within a watch context (during another scope's execution).
|
|
75
|
+
* @template T The type of value returned by the callback.
|
|
76
|
+
* @param callback The function to compute the derived value.
|
|
77
|
+
* @param idOverride Optional custom ID for memoization when using multiple peek scopes.
|
|
78
|
+
* @returns The computed value, reusing existing scope if available.
|
|
79
|
+
*/
|
|
80
|
+
export declare function PeekScope<T>(callback: () => T, idOverride?: string): T;
|
|
64
81
|
export declare namespace ObservableScope {
|
|
65
82
|
/**
|
|
66
83
|
* Creates a new observable scope from a value function.
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ObservableScope = void 0;
|
|
4
4
|
exports.CalcScope = CalcScope;
|
|
5
|
+
exports.PeekScope = PeekScope;
|
|
5
6
|
const emitter_1 = require("../../Utils/emitter");
|
|
6
7
|
const functions_1 = require("../../Utils/functions");
|
|
7
8
|
/**
|
|
@@ -26,7 +27,7 @@ function CreateDynamicScope(getFunction, greedy, value) {
|
|
|
26
27
|
emitter: emitter_1.Emitter.Create(),
|
|
27
28
|
emitters: null,
|
|
28
29
|
onDestroyed: null,
|
|
29
|
-
|
|
30
|
+
scopes: null,
|
|
30
31
|
};
|
|
31
32
|
scope.setCallback = OnSet.bind(scope);
|
|
32
33
|
return scope;
|
|
@@ -220,17 +221,21 @@ function WatchFunction(callback, currentCalc, initialEmitters) {
|
|
|
220
221
|
*/
|
|
221
222
|
function ExecuteScope(scope) {
|
|
222
223
|
scope.dirty = false;
|
|
223
|
-
const state = WatchFunction(scope.getFunction, scope.
|
|
224
|
+
const state = WatchFunction(scope.getFunction, scope.scopes, scope.emitters);
|
|
224
225
|
UpdateEmitters(scope, state);
|
|
225
226
|
const calcScopes = state.currentCalc;
|
|
226
|
-
scope.
|
|
227
|
+
scope.scopes = state.nextCalc;
|
|
227
228
|
for (const key in calcScopes)
|
|
228
229
|
DestroyScope(calcScopes[key]);
|
|
229
|
-
if (scope.async)
|
|
230
|
-
state.value
|
|
230
|
+
if (scope.async) {
|
|
231
|
+
const promise = state.value;
|
|
232
|
+
promise.then(function (result) {
|
|
233
|
+
if (state.value !== promise)
|
|
234
|
+
return;
|
|
231
235
|
scope.value = result;
|
|
232
236
|
emitter_1.Emitter.Emit(scope.emitter, scope);
|
|
233
237
|
});
|
|
238
|
+
}
|
|
234
239
|
else
|
|
235
240
|
scope.value = state.value;
|
|
236
241
|
}
|
|
@@ -247,18 +252,33 @@ function ExecuteFunction(callback, greedy, allowStatic) {
|
|
|
247
252
|
const state = WatchFunction(callback, null, null);
|
|
248
253
|
if (!allowStatic || async || state.emitters !== null) {
|
|
249
254
|
const scope = CreateDynamicScope(callback, greedy, async ? null : state.value);
|
|
250
|
-
scope.
|
|
255
|
+
scope.scopes = state.nextCalc;
|
|
251
256
|
UpdateEmitters(scope, state);
|
|
252
|
-
if (async)
|
|
253
|
-
state.value
|
|
257
|
+
if (async) {
|
|
258
|
+
const promise = state.value;
|
|
259
|
+
promise.then(function (result) {
|
|
260
|
+
if (state.value !== promise)
|
|
261
|
+
return;
|
|
254
262
|
scope.value = result;
|
|
255
263
|
emitter_1.Emitter.Emit(scope.emitter, scope);
|
|
256
264
|
});
|
|
265
|
+
}
|
|
257
266
|
return scope;
|
|
258
267
|
}
|
|
259
268
|
const value = state.value;
|
|
260
269
|
return CreateStaticScope(value);
|
|
261
270
|
}
|
|
271
|
+
function ScopeHelper(callback, id, greedy) {
|
|
272
|
+
const nextScopes = (watchState.nextCalc ??= {});
|
|
273
|
+
if (nextScopes[id])
|
|
274
|
+
return nextScopes[id];
|
|
275
|
+
const currentScopes = watchState.currentCalc;
|
|
276
|
+
nextScopes[id] =
|
|
277
|
+
currentScopes?.[id] ?? ExecuteFunction(callback, greedy, true);
|
|
278
|
+
if (currentScopes?.[id])
|
|
279
|
+
delete currentScopes[id];
|
|
280
|
+
return nextScopes[id];
|
|
281
|
+
}
|
|
262
282
|
/**
|
|
263
283
|
* Creates a computed scope that acts as a gatekeeper for parent scope emissions.
|
|
264
284
|
* If this scope's value doesn't change (=== comparison) it won't emit.
|
|
@@ -277,18 +297,33 @@ function ExecuteFunction(callback, greedy, allowStatic) {
|
|
|
277
297
|
function CalcScope(callback, idOverride) {
|
|
278
298
|
if (watchState === null)
|
|
279
299
|
return callback();
|
|
280
|
-
const
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
300
|
+
const id = idOverride ?? "calc_default";
|
|
301
|
+
const scope = ScopeHelper(callback, id, true);
|
|
302
|
+
RegisterScope(scope);
|
|
303
|
+
return GetScopeValue(scope);
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Creates a computed scope that isn't registered as a dependency with the parent.
|
|
307
|
+
* Use this function to read reactive data without subscribing to changes
|
|
308
|
+
* to that data.
|
|
309
|
+
*
|
|
310
|
+
* Unlike CalcScope, PeekScope does not register itself as a dependency, meaning
|
|
311
|
+
* changes to the data accessed within the callback will not trigger recomputation
|
|
312
|
+
* of the parent scope. The scope is still memoized by ID within the watch context
|
|
313
|
+
* to avoid redundant computation during the same evaluation.
|
|
314
|
+
*
|
|
315
|
+
* Only works within a watch context (during another scope's execution).
|
|
316
|
+
* @template T The type of value returned by the callback.
|
|
317
|
+
* @param callback The function to compute the derived value.
|
|
318
|
+
* @param idOverride Optional custom ID for memoization when using multiple peek scopes.
|
|
319
|
+
* @returns The computed value, reusing existing scope if available.
|
|
320
|
+
*/
|
|
321
|
+
function PeekScope(callback, idOverride) {
|
|
322
|
+
if (watchState === null)
|
|
323
|
+
return callback();
|
|
324
|
+
const id = idOverride ?? "peek_default";
|
|
325
|
+
const scope = ScopeHelper(callback, id, false);
|
|
326
|
+
return GetScopeValue(scope);
|
|
292
327
|
}
|
|
293
328
|
/**
|
|
294
329
|
* Updates a scope's dependency emitters using efficient diffing.
|
|
@@ -350,12 +385,12 @@ function DestroyScope(scope) {
|
|
|
350
385
|
if (!scope || scope.type === "static")
|
|
351
386
|
return;
|
|
352
387
|
emitter_1.Emitter.Clear(scope.emitter);
|
|
353
|
-
for (const key in scope.
|
|
354
|
-
DestroyScope(scope.
|
|
388
|
+
for (const key in scope.scopes)
|
|
389
|
+
DestroyScope(scope.scopes[key]);
|
|
355
390
|
for (let x = 0; x < scope.emitters.length; x++)
|
|
356
391
|
emitter_1.Emitter.Remove(scope.emitters[x], scope.setCallback);
|
|
357
392
|
scope.value = undefined;
|
|
358
|
-
scope.
|
|
393
|
+
scope.scopes = null;
|
|
359
394
|
scope.emitters = null;
|
|
360
395
|
scope.emitter = null;
|
|
361
396
|
scope.getFunction = null;
|
package/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { Component } from './Node/component';
|
|
2
|
-
export { CalcScope as calc } from './Store/Tree/observableScope';
|
|
2
|
+
export { CalcScope as calc, PeekScope as peek } from './Store/Tree/observableScope';
|
package/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.calc = exports.Component = void 0;
|
|
3
|
+
exports.peek = exports.calc = exports.Component = void 0;
|
|
4
4
|
var component_1 = require("./Node/component");
|
|
5
5
|
Object.defineProperty(exports, "Component", { enumerable: true, get: function () { return component_1.Component; } });
|
|
6
6
|
var observableScope_1 = require("./Store/Tree/observableScope");
|
|
7
7
|
Object.defineProperty(exports, "calc", { enumerable: true, get: function () { return observableScope_1.CalcScope; } });
|
|
8
|
+
Object.defineProperty(exports, "peek", { enumerable: true, get: function () { return observableScope_1.PeekScope; } });
|