j-templates 7.0.84 → 7.0.86
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/Tree/observableScope.d.ts +51 -10
- package/Store/Tree/observableScope.js +104 -34
- package/Utils/decorators.d.ts +7 -7
- package/Utils/decorators.js +13 -9
- package/index.d.ts +1 -1
- package/index.js +4 -2
- package/package.json +1 -1
package/Node/vNode.js
CHANGED
|
@@ -174,7 +174,7 @@ function CreateChildrenScope(vnode, children, data = DefaultData) {
|
|
|
174
174
|
if ((0, functions_1.IsAsync)(data)) {
|
|
175
175
|
const asyncData = data;
|
|
176
176
|
data = function () {
|
|
177
|
-
return (0, observableScope_1.
|
|
177
|
+
return (0, observableScope_1.InlineScope)(async function () {
|
|
178
178
|
return asyncData();
|
|
179
179
|
});
|
|
180
180
|
};
|
|
@@ -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
|
}
|
|
@@ -46,21 +46,62 @@ interface IDynamicObservableScope<T> {
|
|
|
46
46
|
*/
|
|
47
47
|
export type IObservableScope<T> = IStaticObservableScope<T> | IDynamicObservableScope<T>;
|
|
48
48
|
/**
|
|
49
|
-
* Creates
|
|
50
|
-
*
|
|
49
|
+
* Creates an inline computed scope registered as a dependency of the parent.
|
|
50
|
+
* The scope is memoized by ID and reused across reads within the same parent evaluation.
|
|
51
|
+
* Emits on every recomputation — no === gating.
|
|
51
52
|
*
|
|
52
|
-
*
|
|
53
|
-
* Scopes are memoized by ID and reused across multiple reads within a single parent scope evaluation.
|
|
54
|
-
* Defaults to "default" ID - provide custom IDs when using multiple calc scopes.
|
|
53
|
+
* Supports async callbacks — Promise<T> is resolved and the resolved value is emitted.
|
|
55
54
|
*
|
|
56
55
|
* Only works within a watch context (during another scope's execution).
|
|
56
|
+
* Throws if called outside a watch context.
|
|
57
|
+
* Creates non-greedy scopes that emit immediately without === gating.
|
|
58
|
+
* @template T The type of value returned by the callback (extracted from Promise if async).
|
|
59
|
+
* @param callback The function to compute the derived value.
|
|
60
|
+
* @param idOverride Optional custom ID for memoization when using multiple scope calls.
|
|
61
|
+
* @returns The computed value, reusing existing scope if available.
|
|
62
|
+
* @throws Error if called outside a watch context.
|
|
63
|
+
*/
|
|
64
|
+
export declare function InlineScope<T>(callback: () => T | Promise<T>, idOverride?: string): T;
|
|
65
|
+
/**
|
|
66
|
+
* Creates a gatekeeper scope that only emits when the value actually changes (===).
|
|
67
|
+
* Prevents unnecessary downstream re-evaluations when the derived value stays the same.
|
|
68
|
+
*
|
|
69
|
+
* Useful for optimizing expensive operations driven by frequently-changing parent state.
|
|
70
|
+
* Scopes are memoized by ID and reused across reads within the same parent evaluation.
|
|
71
|
+
*
|
|
72
|
+
* Supports async callbacks — Promise<T> is resolved and the resolved value is gated.
|
|
73
|
+
*
|
|
74
|
+
* Only works within a watch context (during another scope's execution).
|
|
75
|
+
* Throws if called outside a watch context.
|
|
57
76
|
* Always creates greedy scopes that batch updates via microtask queue.
|
|
58
|
-
* @template T The type of value returned by the callback.
|
|
77
|
+
* @template T The type of value returned by the callback (extracted from Promise if async).
|
|
78
|
+
* @param callback The function to compute the derived value.
|
|
79
|
+
* @param idOverride Optional custom ID for memoization when using multiple gate calls.
|
|
80
|
+
* @returns The computed value, reusing existing scope if available.
|
|
81
|
+
* @throws Error if called outside a watch context.
|
|
82
|
+
*/
|
|
83
|
+
export declare function GateScope<T>(callback: () => T | Promise<T>, idOverride?: string): T;
|
|
84
|
+
/**
|
|
85
|
+
* Creates a computed scope that isn't registered as a dependency with the parent.
|
|
86
|
+
* Use this function to read reactive data without subscribing to changes
|
|
87
|
+
* to that data.
|
|
88
|
+
*
|
|
89
|
+
* Unlike GateScope, PeekScope does not register itself as a dependency, meaning
|
|
90
|
+
* changes to the data accessed within the callback will not trigger recomputation
|
|
91
|
+
* of the parent scope. The scope is still memoized by ID within the watch context
|
|
92
|
+
* to avoid redundant computation during the same evaluation.
|
|
93
|
+
*
|
|
94
|
+
* Supports async callbacks — Promise<T> is resolved and the resolved value is returned.
|
|
95
|
+
*
|
|
96
|
+
* Only works within a watch context (during another scope's execution).
|
|
97
|
+
* Throws if called outside a watch context.
|
|
98
|
+
* @template T The type of value returned by the callback (extracted from Promise if async).
|
|
59
99
|
* @param callback The function to compute the derived value.
|
|
60
|
-
* @param idOverride Optional custom ID for memoization when using multiple
|
|
100
|
+
* @param idOverride Optional custom ID for memoization when using multiple peek calls.
|
|
61
101
|
* @returns The computed value, reusing existing scope if available.
|
|
102
|
+
* @throws Error if called outside a watch context.
|
|
62
103
|
*/
|
|
63
|
-
export declare function
|
|
104
|
+
export declare function PeekScope<T>(callback: () => T | Promise<T>, idOverride?: string): T;
|
|
64
105
|
export declare namespace ObservableScope {
|
|
65
106
|
/**
|
|
66
107
|
* Creates a new observable scope from a value function.
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ObservableScope = void 0;
|
|
4
|
-
exports.
|
|
4
|
+
exports.InlineScope = InlineScope;
|
|
5
|
+
exports.GateScope = GateScope;
|
|
6
|
+
exports.PeekScope = PeekScope;
|
|
5
7
|
const emitter_1 = require("../../Utils/emitter");
|
|
6
8
|
const functions_1 = require("../../Utils/functions");
|
|
7
9
|
/**
|
|
@@ -26,7 +28,7 @@ function CreateDynamicScope(getFunction, greedy, value) {
|
|
|
26
28
|
emitter: emitter_1.Emitter.Create(),
|
|
27
29
|
emitters: null,
|
|
28
30
|
onDestroyed: null,
|
|
29
|
-
|
|
31
|
+
scopes: null,
|
|
30
32
|
};
|
|
31
33
|
scope.setCallback = OnSet.bind(scope);
|
|
32
34
|
return scope;
|
|
@@ -189,7 +191,7 @@ let watchState = null;
|
|
|
189
191
|
* Executes a callback while tracking all scope and emitter dependencies.
|
|
190
192
|
* Creates a watch context that records what was accessed during execution.
|
|
191
193
|
* @param callback The function to execute while tracking dependencies.
|
|
192
|
-
* @param currentCalc Optional map of existing
|
|
194
|
+
* @param currentCalc Optional map of existing inline scopes to reuse.
|
|
193
195
|
* @returns The watch state containing tracked dependencies and result.
|
|
194
196
|
*/
|
|
195
197
|
function WatchFunction(callback, currentCalc, initialEmitters) {
|
|
@@ -220,17 +222,21 @@ function WatchFunction(callback, currentCalc, initialEmitters) {
|
|
|
220
222
|
*/
|
|
221
223
|
function ExecuteScope(scope) {
|
|
222
224
|
scope.dirty = false;
|
|
223
|
-
const state = WatchFunction(scope.getFunction, scope.
|
|
225
|
+
const state = WatchFunction(scope.getFunction, scope.scopes, scope.emitters);
|
|
224
226
|
UpdateEmitters(scope, state);
|
|
225
227
|
const calcScopes = state.currentCalc;
|
|
226
|
-
scope.
|
|
228
|
+
scope.scopes = state.nextCalc;
|
|
227
229
|
for (const key in calcScopes)
|
|
228
230
|
DestroyScope(calcScopes[key]);
|
|
229
|
-
if (scope.async)
|
|
230
|
-
state.value
|
|
231
|
+
if (scope.async) {
|
|
232
|
+
const promise = state.value;
|
|
233
|
+
promise.then(function (result) {
|
|
234
|
+
if (state.value !== promise)
|
|
235
|
+
return;
|
|
231
236
|
scope.value = result;
|
|
232
237
|
emitter_1.Emitter.Emit(scope.emitter, scope);
|
|
233
238
|
});
|
|
239
|
+
}
|
|
234
240
|
else
|
|
235
241
|
scope.value = state.value;
|
|
236
242
|
}
|
|
@@ -247,48 +253,112 @@ function ExecuteFunction(callback, greedy, allowStatic) {
|
|
|
247
253
|
const state = WatchFunction(callback, null, null);
|
|
248
254
|
if (!allowStatic || async || state.emitters !== null) {
|
|
249
255
|
const scope = CreateDynamicScope(callback, greedy, async ? null : state.value);
|
|
250
|
-
scope.
|
|
256
|
+
scope.scopes = state.nextCalc;
|
|
251
257
|
UpdateEmitters(scope, state);
|
|
252
|
-
if (async)
|
|
253
|
-
state.value
|
|
258
|
+
if (async) {
|
|
259
|
+
const promise = state.value;
|
|
260
|
+
promise.then(function (result) {
|
|
261
|
+
if (state.value !== promise)
|
|
262
|
+
return;
|
|
254
263
|
scope.value = result;
|
|
255
264
|
emitter_1.Emitter.Emit(scope.emitter, scope);
|
|
256
265
|
});
|
|
266
|
+
}
|
|
257
267
|
return scope;
|
|
258
268
|
}
|
|
259
269
|
const value = state.value;
|
|
260
270
|
return CreateStaticScope(value);
|
|
261
271
|
}
|
|
272
|
+
function ScopeHelper(callback, id, greedy) {
|
|
273
|
+
const nextScopes = (watchState.nextCalc ??= {});
|
|
274
|
+
if (nextScopes[id])
|
|
275
|
+
return nextScopes[id];
|
|
276
|
+
const currentScopes = watchState.currentCalc;
|
|
277
|
+
nextScopes[id] =
|
|
278
|
+
currentScopes?.[id] ?? ExecuteFunction(callback, greedy, true);
|
|
279
|
+
if (currentScopes?.[id])
|
|
280
|
+
delete currentScopes[id];
|
|
281
|
+
return nextScopes[id];
|
|
282
|
+
}
|
|
262
283
|
/**
|
|
263
|
-
* Creates
|
|
264
|
-
*
|
|
284
|
+
* Creates an inline computed scope registered as a dependency of the parent.
|
|
285
|
+
* The scope is memoized by ID and reused across reads within the same parent evaluation.
|
|
286
|
+
* Emits on every recomputation — no === gating.
|
|
287
|
+
*
|
|
288
|
+
* Supports async callbacks — Promise<T> is resolved and the resolved value is emitted.
|
|
289
|
+
*
|
|
290
|
+
* Only works within a watch context (during another scope's execution).
|
|
291
|
+
* Throws if called outside a watch context.
|
|
292
|
+
* Creates non-greedy scopes that emit immediately without === gating.
|
|
293
|
+
* @template T The type of value returned by the callback (extracted from Promise if async).
|
|
294
|
+
* @param callback The function to compute the derived value.
|
|
295
|
+
* @param idOverride Optional custom ID for memoization when using multiple scope calls.
|
|
296
|
+
* @returns The computed value, reusing existing scope if available.
|
|
297
|
+
* @throws Error if called outside a watch context.
|
|
298
|
+
*/
|
|
299
|
+
function InlineScope(callback, idOverride) {
|
|
300
|
+
if (watchState === null) {
|
|
301
|
+
throw new Error("scope() must be called within a watch context");
|
|
302
|
+
}
|
|
303
|
+
const id = idOverride ?? "scope_default";
|
|
304
|
+
const scope = ScopeHelper(callback, id, false);
|
|
305
|
+
RegisterScope(scope);
|
|
306
|
+
return GetScopeValue(scope);
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Creates a gatekeeper scope that only emits when the value actually changes (===).
|
|
310
|
+
* Prevents unnecessary downstream re-evaluations when the derived value stays the same.
|
|
311
|
+
*
|
|
312
|
+
* Useful for optimizing expensive operations driven by frequently-changing parent state.
|
|
313
|
+
* Scopes are memoized by ID and reused across reads within the same parent evaluation.
|
|
265
314
|
*
|
|
266
|
-
*
|
|
267
|
-
* Scopes are memoized by ID and reused across multiple reads within a single parent scope evaluation.
|
|
268
|
-
* Defaults to "default" ID - provide custom IDs when using multiple calc scopes.
|
|
315
|
+
* Supports async callbacks — Promise<T> is resolved and the resolved value is gated.
|
|
269
316
|
*
|
|
270
317
|
* Only works within a watch context (during another scope's execution).
|
|
318
|
+
* Throws if called outside a watch context.
|
|
271
319
|
* Always creates greedy scopes that batch updates via microtask queue.
|
|
272
|
-
* @template T The type of value returned by the callback.
|
|
320
|
+
* @template T The type of value returned by the callback (extracted from Promise if async).
|
|
273
321
|
* @param callback The function to compute the derived value.
|
|
274
|
-
* @param idOverride Optional custom ID for memoization when using multiple
|
|
322
|
+
* @param idOverride Optional custom ID for memoization when using multiple gate calls.
|
|
275
323
|
* @returns The computed value, reusing existing scope if available.
|
|
324
|
+
* @throws Error if called outside a watch context.
|
|
276
325
|
*/
|
|
277
|
-
function
|
|
278
|
-
if (watchState === null)
|
|
279
|
-
|
|
280
|
-
const nextScopes = (watchState.nextCalc ??= {});
|
|
281
|
-
const id = idOverride ?? "default";
|
|
282
|
-
if (nextScopes[id]) {
|
|
283
|
-
RegisterScope(nextScopes[id]);
|
|
284
|
-
return GetScopeValue(nextScopes[id]);
|
|
326
|
+
function GateScope(callback, idOverride) {
|
|
327
|
+
if (watchState === null) {
|
|
328
|
+
throw new Error("gate() must be called within a watch context");
|
|
285
329
|
}
|
|
286
|
-
const
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
330
|
+
const id = idOverride ?? "gate_default";
|
|
331
|
+
const scope = ScopeHelper(callback, id, true);
|
|
332
|
+
RegisterScope(scope);
|
|
333
|
+
return GetScopeValue(scope);
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Creates a computed scope that isn't registered as a dependency with the parent.
|
|
337
|
+
* Use this function to read reactive data without subscribing to changes
|
|
338
|
+
* to that data.
|
|
339
|
+
*
|
|
340
|
+
* Unlike GateScope, PeekScope does not register itself as a dependency, meaning
|
|
341
|
+
* changes to the data accessed within the callback will not trigger recomputation
|
|
342
|
+
* of the parent scope. The scope is still memoized by ID within the watch context
|
|
343
|
+
* to avoid redundant computation during the same evaluation.
|
|
344
|
+
*
|
|
345
|
+
* Supports async callbacks — Promise<T> is resolved and the resolved value is returned.
|
|
346
|
+
*
|
|
347
|
+
* Only works within a watch context (during another scope's execution).
|
|
348
|
+
* Throws if called outside a watch context.
|
|
349
|
+
* @template T The type of value returned by the callback (extracted from Promise if async).
|
|
350
|
+
* @param callback The function to compute the derived value.
|
|
351
|
+
* @param idOverride Optional custom ID for memoization when using multiple peek calls.
|
|
352
|
+
* @returns The computed value, reusing existing scope if available.
|
|
353
|
+
* @throws Error if called outside a watch context.
|
|
354
|
+
*/
|
|
355
|
+
function PeekScope(callback, idOverride) {
|
|
356
|
+
if (watchState === null) {
|
|
357
|
+
throw new Error("peek() must be called within a watch context");
|
|
358
|
+
}
|
|
359
|
+
const id = idOverride ?? "peek_default";
|
|
360
|
+
const scope = ScopeHelper(callback, id, false);
|
|
361
|
+
return GetScopeValue(scope);
|
|
292
362
|
}
|
|
293
363
|
/**
|
|
294
364
|
* Updates a scope's dependency emitters using efficient diffing.
|
|
@@ -350,12 +420,12 @@ function DestroyScope(scope) {
|
|
|
350
420
|
if (!scope || scope.type === "static")
|
|
351
421
|
return;
|
|
352
422
|
emitter_1.Emitter.Clear(scope.emitter);
|
|
353
|
-
for (const key in scope.
|
|
354
|
-
DestroyScope(scope.
|
|
423
|
+
for (const key in scope.scopes)
|
|
424
|
+
DestroyScope(scope.scopes[key]);
|
|
355
425
|
for (let x = 0; x < scope.emitters.length; x++)
|
|
356
426
|
emitter_1.Emitter.Remove(scope.emitters[x], scope.setCallback);
|
|
357
427
|
scope.value = undefined;
|
|
358
|
-
scope.
|
|
428
|
+
scope.scopes = null;
|
|
359
429
|
scope.emitters = null;
|
|
360
430
|
scope.emitter = null;
|
|
361
431
|
scope.getFunction = null;
|
package/Utils/decorators.d.ts
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* | getters only (expensive) | @Computed | Cached + object reuse via Store |
|
|
22
22
|
* | getters only (simple) | @Scope | Cached, but new reference on update |
|
|
23
23
|
* | getters only (sync, StoreAsync) | @ComputedAsync | Sync getter, StoreAsync caching + object reuse |
|
|
24
|
-
* | async functions (direct scope) | ObservableScope.Create(async) | Direct async, new reference, initial null |
|
|
24
|
+
* | async functions (direct scope) | ObservableScope.Create(async) | Direct async, new reference, initial null |
|
|
25
25
|
* | subscribe to changes | @Watch | Calls method when scope value changes |
|
|
26
26
|
* | dependency injection | @Inject | Gets value from component injector |
|
|
27
27
|
* | cleanup on destroy | @Destroy| Calls .Destroy() on component teardown |
|
|
@@ -233,7 +233,7 @@ export declare function Computed<T extends WeakKey, K extends keyof T, D extends
|
|
|
233
233
|
* Both use synchronous getters and provide object identity preservation.
|
|
234
234
|
*
|
|
235
235
|
* **Comparison**:
|
|
236
|
-
* | Aspect | @Scope | @Computed | @ComputedAsync |
|
|
236
|
+
* | Aspect | @Scope | @Computed | @ComputedAsync | scope(async) + @Scope |
|
|
237
237
|
* |--------|--------|-----------|----------------|----------------------|
|
|
238
238
|
* | Caches value | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes (memoized) |
|
|
239
239
|
* | Getter type | Sync | Sync | Sync | Async supported |
|
|
@@ -461,15 +461,15 @@ export declare function Value(): any;
|
|
|
461
461
|
* - Object identity matters (array/object references used in templates)
|
|
462
462
|
* - You need DOM reference preservation to avoid re-renders
|
|
463
463
|
*
|
|
464
|
-
* **Async pattern with @Scope**: Use `
|
|
464
|
+
* **Async pattern with @Scope**: Use `scope(async () => ...)` for async operations:
|
|
465
465
|
* ```typescript
|
|
466
466
|
* @Scope()
|
|
467
467
|
* get CurrentUser() {
|
|
468
|
-
* return
|
|
468
|
+
* return scope(async () => fetchUser(`/api/user/${this.userId}`));
|
|
469
469
|
* }
|
|
470
470
|
* ```
|
|
471
|
-
* - `
|
|
472
|
-
* - Returns
|
|
471
|
+
* - `scope` creates an inline computed scope that resolves the async operation
|
|
472
|
+
* - Returns the resolved value (not a Promise)
|
|
473
473
|
* - Automatically batches updates via microtask queue
|
|
474
474
|
* - New reference on each update (no object reuse)
|
|
475
475
|
*
|
|
@@ -486,7 +486,7 @@ export declare function Value(): any;
|
|
|
486
486
|
* @see {@link ComputedAsync} for sync getters with StoreAsync backend
|
|
487
487
|
* @see {@link ObservableNode.ApplyDiff} for how @Computed maintains object identity
|
|
488
488
|
* @see {@link ObservableScope} for the scope-based reactivity system
|
|
489
|
-
* @see {@link
|
|
489
|
+
* @see {@link scope} for inline computed scopes within @Scope
|
|
490
490
|
*/
|
|
491
491
|
export declare function Scope(): typeof ScopeDecorator;
|
|
492
492
|
/**
|
package/Utils/decorators.js
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* | getters only (expensive) | @Computed | Cached + object reuse via Store |
|
|
23
23
|
* | getters only (simple) | @Scope | Cached, but new reference on update |
|
|
24
24
|
* | getters only (sync, StoreAsync) | @ComputedAsync | Sync getter, StoreAsync caching + object reuse |
|
|
25
|
-
* | async functions (direct scope) | ObservableScope.Create(async) | Direct async, new reference, initial null |
|
|
25
|
+
* | async functions (direct scope) | ObservableScope.Create(async) | Direct async, new reference, initial null |
|
|
26
26
|
* | subscribe to changes | @Watch | Calls method when scope value changes |
|
|
27
27
|
* | dependency injection | @Inject | Gets value from component injector |
|
|
28
28
|
* | cleanup on destroy | @Destroy| Calls .Destroy() on component teardown |
|
|
@@ -136,10 +136,14 @@ function GetDestroyArrayForPrototype(prototype, create = true) {
|
|
|
136
136
|
function CreateComputedScope(getter, store, defaultValue) {
|
|
137
137
|
const getterScope = observableScope_1.ObservableScope.Create(getter, true);
|
|
138
138
|
observableScope_1.ObservableScope.Watch(getterScope, (scope) => {
|
|
139
|
-
const data = observableScope_1.ObservableScope.
|
|
139
|
+
const data = observableScope_1.ObservableScope.Peek(scope);
|
|
140
140
|
store.Write(data, "root");
|
|
141
141
|
});
|
|
142
|
-
const
|
|
142
|
+
const data = observableScope_1.ObservableScope.Peek(getterScope);
|
|
143
|
+
store.Write(data, "root");
|
|
144
|
+
const propertyScope = observableScope_1.ObservableScope.Create(() => {
|
|
145
|
+
return store.Get("root", defaultValue);
|
|
146
|
+
});
|
|
143
147
|
observableScope_1.ObservableScope.OnDestroyed(propertyScope, function () {
|
|
144
148
|
observableScope_1.ObservableScope.Destroy(getterScope);
|
|
145
149
|
if (store instanceof Store_1.StoreAsync)
|
|
@@ -356,7 +360,7 @@ function ComputedDecorator(target, prop, descriptor) {
|
|
|
356
360
|
* Both use synchronous getters and provide object identity preservation.
|
|
357
361
|
*
|
|
358
362
|
* **Comparison**:
|
|
359
|
-
* | Aspect | @Scope | @Computed | @ComputedAsync |
|
|
363
|
+
* | Aspect | @Scope | @Computed | @ComputedAsync | scope(async) + @Scope |
|
|
360
364
|
* |--------|--------|-----------|----------------|----------------------|
|
|
361
365
|
* | Caches value | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes (memoized) |
|
|
362
366
|
* | Getter type | Sync | Sync | Sync | Async supported |
|
|
@@ -684,15 +688,15 @@ function ValueDecorator(target, propertyKey) {
|
|
|
684
688
|
* - Object identity matters (array/object references used in templates)
|
|
685
689
|
* - You need DOM reference preservation to avoid re-renders
|
|
686
690
|
*
|
|
687
|
-
* **Async pattern with @Scope**: Use `
|
|
691
|
+
* **Async pattern with @Scope**: Use `scope(async () => ...)` for async operations:
|
|
688
692
|
* ```typescript
|
|
689
693
|
* @Scope()
|
|
690
694
|
* get CurrentUser() {
|
|
691
|
-
* return
|
|
695
|
+
* return scope(async () => fetchUser(`/api/user/${this.userId}`));
|
|
692
696
|
* }
|
|
693
697
|
* ```
|
|
694
|
-
* - `
|
|
695
|
-
* - Returns
|
|
698
|
+
* - `scope` creates an inline computed scope that resolves the async operation
|
|
699
|
+
* - Returns the resolved value (not a Promise)
|
|
696
700
|
* - Automatically batches updates via microtask queue
|
|
697
701
|
* - New reference on each update (no object reuse)
|
|
698
702
|
*
|
|
@@ -709,7 +713,7 @@ function ValueDecorator(target, propertyKey) {
|
|
|
709
713
|
* @see {@link ComputedAsync} for sync getters with StoreAsync backend
|
|
710
714
|
* @see {@link ObservableNode.ApplyDiff} for how @Computed maintains object identity
|
|
711
715
|
* @see {@link ObservableScope} for the scope-based reactivity system
|
|
712
|
-
* @see {@link
|
|
716
|
+
* @see {@link scope} for inline computed scopes within @Scope
|
|
713
717
|
*/
|
|
714
718
|
function Scope() {
|
|
715
719
|
return ScopeDecorator;
|
package/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { Component } from './Node/component';
|
|
2
|
-
export {
|
|
2
|
+
export { InlineScope as scope, GateScope as gate, PeekScope as peek } from './Store/Tree/observableScope';
|
package/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.peek = exports.gate = exports.scope = 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
|
-
Object.defineProperty(exports, "
|
|
7
|
+
Object.defineProperty(exports, "scope", { enumerable: true, get: function () { return observableScope_1.InlineScope; } });
|
|
8
|
+
Object.defineProperty(exports, "gate", { enumerable: true, get: function () { return observableScope_1.GateScope; } });
|
|
9
|
+
Object.defineProperty(exports, "peek", { enumerable: true, get: function () { return observableScope_1.PeekScope; } });
|