j-templates 8.0.19 → 8.0.21
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.types.d.ts +1 -1
- package/SYNTAX_PRIMER.md +677 -1426
- package/Store/Tree/observableScope.d.ts +15 -15
- package/Store/Tree/observableScope.js +23 -26
- package/Utils/decorators.d.ts +14 -11
- package/Utils/decorators.js +39 -22
- package/Utils/emitter.d.ts +1 -1
- package/Utils/emitter.js +33 -28
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/package.json +1 -1
|
@@ -92,26 +92,24 @@ export declare function MappedScope<D, T>(data: D, callback: (data: D) => T | Pr
|
|
|
92
92
|
*/
|
|
93
93
|
export declare function GateScope<T>(callback: () => T | Promise<T>, idOverride?: string): T;
|
|
94
94
|
/**
|
|
95
|
-
*
|
|
95
|
+
* Invokes a callback with dependency tracking suspended.
|
|
96
96
|
* Use this function to read reactive data without subscribing to changes
|
|
97
97
|
* to that data.
|
|
98
98
|
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
99
|
+
* No scope is created: the callback runs immediately on every call and nothing
|
|
100
|
+
* is memoized. Reactive values read inside the callback are not registered with
|
|
101
|
+
* the current watch context, so changes to them will not trigger recomputation
|
|
102
|
+
* of the parent scope. The previous watch context is restored afterwards, even
|
|
103
|
+
* if the callback throws.
|
|
103
104
|
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
* @
|
|
109
|
-
* @
|
|
110
|
-
* @param idOverride Optional custom ID for memoization when using multiple peek calls.
|
|
111
|
-
* @returns The computed value, reusing existing scope if available.
|
|
112
|
-
* @throws Error if called outside a watch context.
|
|
105
|
+
* Can be called anywhere, inside or outside a watch context. Because tracking is
|
|
106
|
+
* suspended, InlineScope, GateScope and MappedScope throw if called from within
|
|
107
|
+
* the callback. Async callbacks are not awaited; the Promise is returned as-is.
|
|
108
|
+
* @template T The type of value returned by the callback.
|
|
109
|
+
* @param callback The function to invoke without dependency tracking.
|
|
110
|
+
* @returns The value returned by the callback.
|
|
113
111
|
*/
|
|
114
|
-
export declare function
|
|
112
|
+
export declare function PeekCallback<T>(callback: () => T): T;
|
|
115
113
|
export declare namespace ObservableScope {
|
|
116
114
|
/**
|
|
117
115
|
* Creates a new observable scope from a value function.
|
|
@@ -178,6 +176,8 @@ export declare namespace ObservableScope {
|
|
|
178
176
|
/**
|
|
179
177
|
* Subscribes to changes on a dynamic scope.
|
|
180
178
|
* @template T The type of value stored in the scope.
|
|
179
|
+
* The callback must not cause the same scope to emit again (for example by calling
|
|
180
|
+
* `Update(scope)`): re-entrant emits throw.
|
|
181
181
|
* @param scope The scope to watch for changes.
|
|
182
182
|
* @param callback Function to invoke when the scope's value changes.
|
|
183
183
|
*/
|
|
@@ -268,11 +268,7 @@ function ExecuteScope(scope) {
|
|
|
268
268
|
}
|
|
269
269
|
}
|
|
270
270
|
function ExecuteBasicScope(scope) {
|
|
271
|
-
|
|
272
|
-
watchState = null;
|
|
273
|
-
const result = scope.getFunction();
|
|
274
|
-
watchState = parent;
|
|
275
|
-
return result;
|
|
271
|
+
return PeekCallback(scope.getFunction);
|
|
276
272
|
}
|
|
277
273
|
/**
|
|
278
274
|
* Creates a scope from a function, choosing between static and dynamic based on dependencies.
|
|
@@ -355,7 +351,6 @@ function MappedScopeHelper(callback, data, onUpdated, onDestroyed) {
|
|
|
355
351
|
}
|
|
356
352
|
const SCOPE_DEFAULT = Symbol("SCOPE_DEFAULT");
|
|
357
353
|
const GATE_DEFAULT = Symbol("GATE_DEFAULT");
|
|
358
|
-
const PEEK_DEFAULT = Symbol("PEEK_DEFAULT");
|
|
359
354
|
/**
|
|
360
355
|
* Creates an inline computed scope registered as a dependency of the parent.
|
|
361
356
|
* The scope is memoized by ID and reused across reads within the same parent evaluation.
|
|
@@ -417,32 +412,32 @@ export function GateScope(callback, idOverride) {
|
|
|
417
412
|
return GetScopeValue(scope);
|
|
418
413
|
}
|
|
419
414
|
/**
|
|
420
|
-
*
|
|
415
|
+
* Invokes a callback with dependency tracking suspended.
|
|
421
416
|
* Use this function to read reactive data without subscribing to changes
|
|
422
417
|
* to that data.
|
|
423
418
|
*
|
|
424
|
-
*
|
|
425
|
-
*
|
|
426
|
-
*
|
|
427
|
-
*
|
|
419
|
+
* No scope is created: the callback runs immediately on every call and nothing
|
|
420
|
+
* is memoized. Reactive values read inside the callback are not registered with
|
|
421
|
+
* the current watch context, so changes to them will not trigger recomputation
|
|
422
|
+
* of the parent scope. The previous watch context is restored afterwards, even
|
|
423
|
+
* if the callback throws.
|
|
428
424
|
*
|
|
429
|
-
*
|
|
430
|
-
*
|
|
431
|
-
*
|
|
432
|
-
*
|
|
433
|
-
* @
|
|
434
|
-
* @
|
|
435
|
-
* @param idOverride Optional custom ID for memoization when using multiple peek calls.
|
|
436
|
-
* @returns The computed value, reusing existing scope if available.
|
|
437
|
-
* @throws Error if called outside a watch context.
|
|
425
|
+
* Can be called anywhere, inside or outside a watch context. Because tracking is
|
|
426
|
+
* suspended, InlineScope, GateScope and MappedScope throw if called from within
|
|
427
|
+
* the callback. Async callbacks are not awaited; the Promise is returned as-is.
|
|
428
|
+
* @template T The type of value returned by the callback.
|
|
429
|
+
* @param callback The function to invoke without dependency tracking.
|
|
430
|
+
* @returns The value returned by the callback.
|
|
438
431
|
*/
|
|
439
|
-
export function
|
|
440
|
-
|
|
441
|
-
|
|
432
|
+
export function PeekCallback(callback) {
|
|
433
|
+
const parent = watchState;
|
|
434
|
+
watchState = null;
|
|
435
|
+
try {
|
|
436
|
+
return callback();
|
|
437
|
+
}
|
|
438
|
+
finally {
|
|
439
|
+
watchState = parent;
|
|
442
440
|
}
|
|
443
|
-
const id = idOverride ?? PEEK_DEFAULT;
|
|
444
|
-
const scope = ScopeHelper(callback, id, false);
|
|
445
|
-
return GetScopeValue(scope);
|
|
446
441
|
}
|
|
447
442
|
/**
|
|
448
443
|
* Updates a scope's dependency emitters using efficient diffing.
|
|
@@ -621,6 +616,8 @@ export var ObservableScope;
|
|
|
621
616
|
/**
|
|
622
617
|
* Subscribes to changes on a dynamic scope.
|
|
623
618
|
* @template T The type of value stored in the scope.
|
|
619
|
+
* The callback must not cause the same scope to emit again (for example by calling
|
|
620
|
+
* `Update(scope)`): re-entrant emits throw.
|
|
624
621
|
* @param scope The scope to watch for changes.
|
|
625
622
|
* @param callback Function to invoke when the scope's value changes.
|
|
626
623
|
*/
|
package/Utils/decorators.d.ts
CHANGED
|
@@ -39,13 +39,13 @@
|
|
|
39
39
|
* | Aspect | @Computed | @Scope |
|
|
40
40
|
* |--------|-----------|--------|
|
|
41
41
|
* | Caching | ✅ Yes | ✅ Yes |
|
|
42
|
-
* | Object identity preserved | ✅ Yes (
|
|
42
|
+
* | Object identity preserved | ✅ Yes (Apply) | ❌ No (new object) |
|
|
43
43
|
* | Overhead | Store + diff | Single scope |
|
|
44
44
|
* | Best for | Complex objects | Primitives/simple values |
|
|
45
45
|
*
|
|
46
46
|
* Object Identity (Key Difference):
|
|
47
47
|
* ---------------------------------
|
|
48
|
-
* @Computed: Same object reference, in-place updates via ObservableNode.
|
|
48
|
+
* @Computed: Same object reference, in-place updates via ObservableNode.Apply
|
|
49
49
|
* @Scope: New object reference on every update
|
|
50
50
|
*
|
|
51
51
|
* Example:
|
|
@@ -104,13 +104,16 @@ import { Injector } from "./injector";
|
|
|
104
104
|
* @remarks
|
|
105
105
|
* The @Computed decorator uses a Gated getter scope driving a persistent observable node:
|
|
106
106
|
* 1. Getter scope (Gated): Re-evaluates the getter when dependencies change, batched via
|
|
107
|
-
* the microtask queue
|
|
107
|
+
* the microtask queue, and returns a clone of the result. A watcher on this scope
|
|
108
|
+
* applies each new clone to the node.
|
|
108
109
|
* 2. ObservableNode.Apply: Diffs the fresh value against the node's current root and applies
|
|
109
|
-
* only the changed paths in-place, preserving the node's object identity.
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
* emits, notifying top-level subscribers
|
|
110
|
+
* only the changed paths in-place, preserving the node's object identity. If the result
|
|
111
|
+
* deep-equals the previous value, nothing is changed and nothing is emitted.
|
|
112
|
+
* 3. Downstream notification: Per-property emitters fire for each changed path, so scopes
|
|
113
|
+
* reading sub-properties update directly. The property itself is backed by a separate
|
|
114
|
+
* scope that reads the node's root; it emits, notifying top-level subscribers, only when
|
|
115
|
+
* the diff collapses to a full root replacement (type change or removed keys) and the
|
|
116
|
+
* root value gets a new identity.
|
|
114
117
|
*
|
|
115
118
|
* **Initialization**: @Computed uses lazy initialization - the scopes are created on first access:
|
|
116
119
|
* ```typescript
|
|
@@ -127,7 +130,7 @@ import { Injector } from "./injector";
|
|
|
127
130
|
* dependencies change. The key difference is what happens during re-evaluation:
|
|
128
131
|
*
|
|
129
132
|
* **Key benefit - Object Reuse**: The returned object maintains its identity across updates.
|
|
130
|
-
* Only the changed properties are modified in-place using ObservableNode.
|
|
133
|
+
* Only the changed properties are modified in-place using ObservableNode.Apply. This enables:
|
|
131
134
|
* - DOM reference preservation (no unnecessary re-renders)
|
|
132
135
|
* - Existing proxy reuse (no proxy recreation overhead)
|
|
133
136
|
* - Identity checks (===) remain stable across updates
|
|
@@ -156,7 +159,7 @@ import { Injector } from "./injector";
|
|
|
156
159
|
* @see {@link Scope} for simple getter-based reactive properties (caches but new reference)
|
|
157
160
|
* @see {@link ComputedAsync} for async computed properties
|
|
158
161
|
* @see {@link ObservableNode.Apply} for how diffs are applied in-place to maintain object identity
|
|
159
|
-
* @see {@link ObservableScope} for the Gated scope mechanism (batched
|
|
162
|
+
* @see {@link ObservableScope} for the Gated scope mechanism (batched updates)
|
|
160
163
|
* @see {@link StoreSync} for the store-backed variant used by @ComputedAsync
|
|
161
164
|
*/
|
|
162
165
|
export declare function Computed<T extends WeakKey, K extends keyof T, D extends T[K]>(): (target: T, propertyKey: K, descriptor: PropertyDescriptor) => PropertyDescriptor;
|
|
@@ -488,7 +491,7 @@ export declare function Value(): any;
|
|
|
488
491
|
*
|
|
489
492
|
* @see {@link Computed} for cached computed properties with object reuse
|
|
490
493
|
* @see {@link ComputedAsync} for sync getters with StoreAsync backend
|
|
491
|
-
* @see {@link ObservableNode.
|
|
494
|
+
* @see {@link ObservableNode.Apply} for how @Computed maintains object identity
|
|
492
495
|
* @see {@link ObservableScope} for the scope-based reactivity system
|
|
493
496
|
* @see {@link scope} for inline computed scopes within @Scope
|
|
494
497
|
*/
|
package/Utils/decorators.js
CHANGED
|
@@ -39,13 +39,13 @@
|
|
|
39
39
|
* | Aspect | @Computed | @Scope |
|
|
40
40
|
* |--------|-----------|--------|
|
|
41
41
|
* | Caching | ✅ Yes | ✅ Yes |
|
|
42
|
-
* | Object identity preserved | ✅ Yes (
|
|
42
|
+
* | Object identity preserved | ✅ Yes (Apply) | ❌ No (new object) |
|
|
43
43
|
* | Overhead | Store + diff | Single scope |
|
|
44
44
|
* | Best for | Complex objects | Primitives/simple values |
|
|
45
45
|
*
|
|
46
46
|
* Object Identity (Key Difference):
|
|
47
47
|
* ---------------------------------
|
|
48
|
-
* @Computed: Same object reference, in-place updates via ObservableNode.
|
|
48
|
+
* @Computed: Same object reference, in-place updates via ObservableNode.Apply
|
|
49
49
|
* @Scope: New object reference on every update
|
|
50
50
|
*
|
|
51
51
|
* Example:
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
* console.log(list === list2); // @Computed: true, @Scope: false
|
|
57
57
|
* ```
|
|
58
58
|
*/
|
|
59
|
-
import { ObservableScope, } from "../Store/Tree/observableScope";
|
|
59
|
+
import { ObservableScope, PeekCallback, } from "../Store/Tree/observableScope";
|
|
60
60
|
import { ObservableNode } from "../Store/Tree/observableNode";
|
|
61
61
|
import { StoreAsync } from "../Store";
|
|
62
62
|
/**
|
|
@@ -144,29 +144,43 @@ function CreateStoreScope(getter, store, defaultValue) {
|
|
|
144
144
|
return propertyScope;
|
|
145
145
|
}
|
|
146
146
|
/**
|
|
147
|
-
* Creates
|
|
147
|
+
* Creates an observable scope that exposes a getter's value through a persistent
|
|
148
148
|
* observable node, preserving the value's object identity across updates.
|
|
149
149
|
*
|
|
150
|
-
*
|
|
151
|
-
* via ObservableNode.Apply
|
|
150
|
+
* The getter runs in a Gated scope that returns a clone of its value. A watcher on that
|
|
151
|
+
* scope merges each new clone into the node in-place via ObservableNode.Apply, with
|
|
152
|
+
* dependency tracking suspended. The returned scope reads the node's root:
|
|
152
153
|
* - Content changes (same structure, changed properties) fire only the affected
|
|
153
|
-
* per-property
|
|
154
|
+
* per-property emitters - the returned scope does not emit.
|
|
154
155
|
* - Structural changes (type change or removed keys) replace the root value with a new
|
|
155
|
-
* identity
|
|
156
|
-
* - Deep-equal results
|
|
156
|
+
* identity; the root's emitter fires and the returned scope emits.
|
|
157
|
+
* - Deep-equal results change nothing in the node, so nothing downstream is notified.
|
|
158
|
+
*
|
|
159
|
+
* Destroying the returned scope also destroys the Gated getter scope.
|
|
157
160
|
*
|
|
158
161
|
* @param getter Function computing the value. May read reactive dependencies.
|
|
159
|
-
* @returns
|
|
162
|
+
* @returns A scope whose value is the observable node's root.
|
|
160
163
|
*/
|
|
161
164
|
function CreateNodeScope(getter) {
|
|
162
|
-
const observableNode = ObservableNode.Create({ root: null });
|
|
163
165
|
const getterScope = ObservableScope.Gated(function () {
|
|
164
166
|
const value = getter();
|
|
165
167
|
const clonedValue = ObservableNode.Clone(value);
|
|
166
|
-
|
|
168
|
+
return clonedValue;
|
|
169
|
+
});
|
|
170
|
+
const observableNode = ObservableNode.Create({ root: ObservableScope.Peek(getterScope) });
|
|
171
|
+
ObservableScope.Watch(getterScope, function (scope) {
|
|
172
|
+
PeekCallback(function () {
|
|
173
|
+
const value = ObservableScope.Peek(scope);
|
|
174
|
+
ObservableNode.Apply(observableNode, { root: value });
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
const nodeScope = ObservableScope.Create(function () {
|
|
167
178
|
return observableNode.root;
|
|
168
179
|
});
|
|
169
|
-
|
|
180
|
+
ObservableScope.OnDestroyed(nodeScope, function () {
|
|
181
|
+
ObservableScope.Destroy(getterScope);
|
|
182
|
+
});
|
|
183
|
+
return nodeScope;
|
|
170
184
|
}
|
|
171
185
|
/**
|
|
172
186
|
* Computed decorator factory for creating synchronous computed properties with caching and object reuse.
|
|
@@ -214,13 +228,16 @@ function CreateNodeScope(getter) {
|
|
|
214
228
|
* @remarks
|
|
215
229
|
* The @Computed decorator uses a Gated getter scope driving a persistent observable node:
|
|
216
230
|
* 1. Getter scope (Gated): Re-evaluates the getter when dependencies change, batched via
|
|
217
|
-
* the microtask queue
|
|
231
|
+
* the microtask queue, and returns a clone of the result. A watcher on this scope
|
|
232
|
+
* applies each new clone to the node.
|
|
218
233
|
* 2. ObservableNode.Apply: Diffs the fresh value against the node's current root and applies
|
|
219
|
-
* only the changed paths in-place, preserving the node's object identity.
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
*
|
|
223
|
-
* emits, notifying top-level subscribers
|
|
234
|
+
* only the changed paths in-place, preserving the node's object identity. If the result
|
|
235
|
+
* deep-equals the previous value, nothing is changed and nothing is emitted.
|
|
236
|
+
* 3. Downstream notification: Per-property emitters fire for each changed path, so scopes
|
|
237
|
+
* reading sub-properties update directly. The property itself is backed by a separate
|
|
238
|
+
* scope that reads the node's root; it emits, notifying top-level subscribers, only when
|
|
239
|
+
* the diff collapses to a full root replacement (type change or removed keys) and the
|
|
240
|
+
* root value gets a new identity.
|
|
224
241
|
*
|
|
225
242
|
* **Initialization**: @Computed uses lazy initialization - the scopes are created on first access:
|
|
226
243
|
* ```typescript
|
|
@@ -237,7 +254,7 @@ function CreateNodeScope(getter) {
|
|
|
237
254
|
* dependencies change. The key difference is what happens during re-evaluation:
|
|
238
255
|
*
|
|
239
256
|
* **Key benefit - Object Reuse**: The returned object maintains its identity across updates.
|
|
240
|
-
* Only the changed properties are modified in-place using ObservableNode.
|
|
257
|
+
* Only the changed properties are modified in-place using ObservableNode.Apply. This enables:
|
|
241
258
|
* - DOM reference preservation (no unnecessary re-renders)
|
|
242
259
|
* - Existing proxy reuse (no proxy recreation overhead)
|
|
243
260
|
* - Identity checks (===) remain stable across updates
|
|
@@ -266,7 +283,7 @@ function CreateNodeScope(getter) {
|
|
|
266
283
|
* @see {@link Scope} for simple getter-based reactive properties (caches but new reference)
|
|
267
284
|
* @see {@link ComputedAsync} for async computed properties
|
|
268
285
|
* @see {@link ObservableNode.Apply} for how diffs are applied in-place to maintain object identity
|
|
269
|
-
* @see {@link ObservableScope} for the Gated scope mechanism (batched
|
|
286
|
+
* @see {@link ObservableScope} for the Gated scope mechanism (batched updates)
|
|
270
287
|
* @see {@link StoreSync} for the store-backed variant used by @ComputedAsync
|
|
271
288
|
*/
|
|
272
289
|
export function Computed() {
|
|
@@ -733,7 +750,7 @@ function ValueDecorator(target, propertyKey) {
|
|
|
733
750
|
*
|
|
734
751
|
* @see {@link Computed} for cached computed properties with object reuse
|
|
735
752
|
* @see {@link ComputedAsync} for sync getters with StoreAsync backend
|
|
736
|
-
* @see {@link ObservableNode.
|
|
753
|
+
* @see {@link ObservableNode.Apply} for how @Computed maintains object identity
|
|
737
754
|
* @see {@link ObservableScope} for the scope-based reactivity system
|
|
738
755
|
* @see {@link scope} for inline computed scopes within @Scope
|
|
739
756
|
*/
|
package/Utils/emitter.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type EmitterCallback<T extends readonly any[] = any[]> = (...args: T) => void;
|
|
2
|
-
export type Emitter = [number, ...EmitterCallback[]];
|
|
2
|
+
export type Emitter = [[number, number], ...EmitterCallback[]];
|
|
3
3
|
export declare namespace Emitter {
|
|
4
4
|
function Create(): Emitter;
|
|
5
5
|
function On(emitter: Emitter, callback: EmitterCallback): void;
|
package/Utils/emitter.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { RemoveNulls } from "./array";
|
|
2
1
|
import { _requestIdleCallback } from "./scheduling";
|
|
3
2
|
const pendingCompactEmitters = new Set();
|
|
4
3
|
function Compact(emitter) {
|
|
5
|
-
if (emitter.length === 1 || emitter[0] === 0)
|
|
4
|
+
if (emitter.length === 1 || emitter[0][0] === 0)
|
|
6
5
|
return;
|
|
7
6
|
pendingCompactEmitters.add(emitter);
|
|
8
7
|
ScheduleCompact();
|
|
@@ -22,57 +21,63 @@ function PerformCompact() {
|
|
|
22
21
|
CompactEmitter(compactEmitters[x]);
|
|
23
22
|
}
|
|
24
23
|
function CompactEmitter(emitter) {
|
|
25
|
-
if (emitter[0] === 0)
|
|
24
|
+
if (emitter[0][0] === 0)
|
|
26
25
|
return;
|
|
27
|
-
emitter.splice(1, emitter[0]);
|
|
28
|
-
emitter[0] = 0;
|
|
26
|
+
emitter.splice(1, emitter[0][0]);
|
|
27
|
+
emitter[0][0] = 0;
|
|
29
28
|
}
|
|
30
29
|
export var Emitter;
|
|
31
30
|
(function (Emitter) {
|
|
32
31
|
function Create() {
|
|
33
|
-
return [0];
|
|
32
|
+
return [[0, -1]];
|
|
34
33
|
}
|
|
35
34
|
Emitter.Create = Create;
|
|
36
35
|
function On(emitter, callback) {
|
|
37
36
|
emitter.push(callback);
|
|
38
37
|
}
|
|
39
38
|
Emitter.On = On;
|
|
40
|
-
|
|
41
|
-
const modifiedDuringEmit = new Set();
|
|
39
|
+
// Re-entry during emit is not supported and considered a bug in client code
|
|
42
40
|
function Emit(emitter, ...args) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
emitter[0] = 0;
|
|
41
|
+
if (emitter[0][1] !== -1)
|
|
42
|
+
throw new Error("Emitter.Emit: re-entry during emit is not supported");
|
|
43
|
+
try {
|
|
44
|
+
for (let x = emitter[0][1] = emitter[0][0] + 1; x < emitter.length; emitter[0][1] = ++x) {
|
|
45
|
+
emitter[x](...args);
|
|
46
|
+
}
|
|
50
47
|
}
|
|
48
|
+
finally {
|
|
49
|
+
emitter[0][1] = -1;
|
|
50
|
+
}
|
|
51
|
+
if (emitter[0][0] !== 0)
|
|
52
|
+
Compact(emitter);
|
|
51
53
|
}
|
|
52
54
|
Emitter.Emit = Emit;
|
|
55
|
+
function RemoveFromEnd(emitter, index) {
|
|
56
|
+
emitter[index] = emitter[emitter.length - 1];
|
|
57
|
+
emitter.pop();
|
|
58
|
+
}
|
|
59
|
+
function RemoveFromBeginning(emitter, index) {
|
|
60
|
+
const tombstoneSize = emitter[0][0];
|
|
61
|
+
emitter[index] = emitter[tombstoneSize + 1];
|
|
62
|
+
emitter[tombstoneSize + 1] = null;
|
|
63
|
+
emitter[0][0]++;
|
|
64
|
+
}
|
|
53
65
|
function Remove(emitter, callback) {
|
|
54
66
|
if (emitter.length === 1)
|
|
55
67
|
return;
|
|
56
|
-
const startIndex = emitter[0] + 1;
|
|
68
|
+
const startIndex = emitter[0][0] + 1;
|
|
57
69
|
const index = emitter.indexOf(callback, startIndex);
|
|
58
70
|
if (index < 1)
|
|
59
71
|
return;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
emitter
|
|
64
|
-
emitter[startIndex] = null;
|
|
65
|
-
Compact(emitter);
|
|
66
|
-
}
|
|
67
|
-
else {
|
|
68
|
-
emitter[index] = null;
|
|
69
|
-
modifiedDuringEmit.add(emitter);
|
|
70
|
-
}
|
|
72
|
+
if (index <= emitter[0][1])
|
|
73
|
+
RemoveFromBeginning(emitter, index);
|
|
74
|
+
else
|
|
75
|
+
RemoveFromEnd(emitter, index);
|
|
71
76
|
}
|
|
72
77
|
Emitter.Remove = Remove;
|
|
73
78
|
function Clear(emitter) {
|
|
74
79
|
emitter.length > 1 && emitter.splice(1);
|
|
75
|
-
emitter[0] = 0;
|
|
80
|
+
emitter[0][0] = 0;
|
|
76
81
|
}
|
|
77
82
|
Emitter.Clear = Clear;
|
|
78
83
|
})(Emitter || (Emitter = {}));
|
package/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { Component } from './Node/component';
|
|
2
|
-
export { InlineScope as scope, GateScope as gate,
|
|
2
|
+
export { InlineScope as scope, GateScope as gate, PeekCallback as peek, MappedScope as mapped } from './Store/Tree/observableScope';
|
|
3
3
|
export { vNode } from './Node/vNode.types';
|
package/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { Component } from './Node/component';
|
|
2
|
-
export { InlineScope as scope, GateScope as gate,
|
|
2
|
+
export { InlineScope as scope, GateScope as gate, PeekCallback as peek, MappedScope as mapped } from './Store/Tree/observableScope';
|