j-templates 7.0.68 → 7.0.70
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/DOM/domNodeConfig.js +5 -4
- package/Node/component.d.ts +0 -8
- package/Node/component.js +1 -42
- package/Node/vNode.js +1 -41
- package/Store/Tree/observableScope.d.ts +99 -0
- package/Store/Tree/observableScope.js +250 -46
- package/Utils/decorators.js +0 -10
- package/Utils/emitter.js +1 -19
- package/package.json +1 -1
package/DOM/domNodeConfig.js
CHANGED
|
@@ -169,9 +169,10 @@ exports.DOMNodeConfig = {
|
|
|
169
169
|
target.appendChild(children[x]);
|
|
170
170
|
},
|
|
171
171
|
reconcileChild(target, child) {
|
|
172
|
-
if (target.
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
172
|
+
if (target.firstChild === child)
|
|
173
|
+
return;
|
|
174
|
+
target.appendChild(child);
|
|
175
|
+
while (target.firstChild !== child)
|
|
176
|
+
target.removeChild(target.firstChild);
|
|
176
177
|
},
|
|
177
178
|
};
|
package/Node/component.d.ts
CHANGED
|
@@ -38,14 +38,6 @@ export declare class Component<D = void, T = void, E = {}> {
|
|
|
38
38
|
* Accessor for the component's template collection.
|
|
39
39
|
*/
|
|
40
40
|
protected get Templates(): T;
|
|
41
|
-
/**
|
|
42
|
-
* Creates a new Component instance. Not intended to be overriden.
|
|
43
|
-
*
|
|
44
|
-
* @param data - Initial data or a factory function returning data/promise.
|
|
45
|
-
* @param templates - Template definitions for rendering.
|
|
46
|
-
* @param vNode - The underlying virtual node instance.
|
|
47
|
-
* @param componentEvents - Optional event callbacks.
|
|
48
|
-
*/
|
|
49
41
|
constructor(vNode: vNodeType, config: vComponentConfig<D, E>, templates: T);
|
|
50
42
|
/**
|
|
51
43
|
* Returns the component's rendered vNode(s).
|
package/Node/component.js
CHANGED
|
@@ -48,32 +48,9 @@ class Component {
|
|
|
48
48
|
get Templates() {
|
|
49
49
|
return this.templates;
|
|
50
50
|
}
|
|
51
|
-
/**
|
|
52
|
-
* Creates a new Component instance. Not intended to be overriden.
|
|
53
|
-
*
|
|
54
|
-
* @param data - Initial data or a factory function returning data/promise.
|
|
55
|
-
* @param templates - Template definitions for rendering.
|
|
56
|
-
* @param vNode - The underlying virtual node instance.
|
|
57
|
-
* @param componentEvents - Optional event callbacks.
|
|
58
|
-
*/
|
|
59
|
-
/* constructor(
|
|
60
|
-
data: D | (() => D | Promise<D>),
|
|
61
|
-
templates: T,
|
|
62
|
-
private vNode: vNodeType,
|
|
63
|
-
private componentEvents: ComponentEvents<E>,
|
|
64
|
-
) {
|
|
65
|
-
if (typeof data === "function")
|
|
66
|
-
this.scope = new ObservableScope<D>(data as () => D | Promise<D>);
|
|
67
|
-
else this.scope = new ObservableScope<D>(() => data);
|
|
68
|
-
|
|
69
|
-
this.templates = templates || ({} as T);
|
|
70
|
-
} */
|
|
71
51
|
constructor(vNode, config, templates) {
|
|
72
52
|
this.vNode = vNode;
|
|
73
53
|
const { data, on } = config;
|
|
74
|
-
/* if (typeof data === "function")
|
|
75
|
-
this.scope = new ObservableScope<D>(data as () => D | Promise<D>);
|
|
76
|
-
else this.scope = new ObservableScope<D>(() => data); */
|
|
77
54
|
if (typeof data === "function")
|
|
78
55
|
this.scope = Store_1.ObservableScope.Create(data);
|
|
79
56
|
else
|
|
@@ -119,30 +96,13 @@ class Component {
|
|
|
119
96
|
}
|
|
120
97
|
}
|
|
121
98
|
exports.Component = Component;
|
|
122
|
-
/* type ComponentConstructor<D, T, E> = {
|
|
123
|
-
new (
|
|
124
|
-
data: D | (() => D | Promise<D>),
|
|
125
|
-
templates: T,
|
|
126
|
-
vNode: vNodeType,
|
|
127
|
-
componentEvents: ComponentEvents<E>,
|
|
128
|
-
): Component<D, T, E>;
|
|
129
|
-
}; */
|
|
130
99
|
(function (Component) {
|
|
131
100
|
/**
|
|
132
101
|
* Function wraps the Component as a function that can be used to create vNode objects
|
|
133
102
|
* and generate templates.
|
|
134
103
|
*/
|
|
135
|
-
function ToFunction(type,
|
|
136
|
-
// constructor: ComponentConstructor<D, T, E>,
|
|
137
|
-
constructor, namespace) {
|
|
104
|
+
function ToFunction(type, constructor, namespace) {
|
|
138
105
|
return function (config, templates) {
|
|
139
|
-
/* const { data, on, props } = config;
|
|
140
|
-
|
|
141
|
-
class ConcreteComponent extends constructor {
|
|
142
|
-
constructor(vnode: vNodeType) {
|
|
143
|
-
super(data, templates, vnode, on);
|
|
144
|
-
}
|
|
145
|
-
} */
|
|
146
106
|
function ComponentFactory(vnode) {
|
|
147
107
|
return new constructor(vnode, config, templates);
|
|
148
108
|
}
|
|
@@ -151,7 +111,6 @@ exports.Component = Component;
|
|
|
151
111
|
namespace: namespace ?? null,
|
|
152
112
|
props: config.props,
|
|
153
113
|
componentFactory: ComponentFactory,
|
|
154
|
-
// componentConstructor: ConcreteComponent,
|
|
155
114
|
};
|
|
156
115
|
return vNode_1.vNode.Create(definition);
|
|
157
116
|
};
|
package/Node/vNode.js
CHANGED
|
@@ -14,7 +14,6 @@ var vNode;
|
|
|
14
14
|
return {
|
|
15
15
|
definition,
|
|
16
16
|
type: definition.type,
|
|
17
|
-
// injector: definition.componentConstructor
|
|
18
17
|
injector: definition.componentFactory
|
|
19
18
|
? injector_1.Injector.Scope(injector_1.Injector.Current(), function () {
|
|
20
19
|
return new injector_1.Injector();
|
|
@@ -95,9 +94,7 @@ var vNode;
|
|
|
95
94
|
vNode.Attach = Attach;
|
|
96
95
|
})(vNode || (exports.vNode = vNode = {}));
|
|
97
96
|
function InitNode(vnode) {
|
|
98
|
-
const { type, namespace, props, attrs, on, data,
|
|
99
|
-
// componentConstructor,
|
|
100
|
-
componentFactory, children, childrenArray, } = vnode.definition;
|
|
97
|
+
const { type, namespace, props, attrs, on, data, componentFactory, children, childrenArray, } = vnode.definition;
|
|
101
98
|
const node = (vnode.node =
|
|
102
99
|
vnode.definition.node ?? nodeConfig_1.NodeConfig.createNode(type, namespace));
|
|
103
100
|
vnode.definition = null;
|
|
@@ -105,11 +102,8 @@ function InitNode(vnode) {
|
|
|
105
102
|
const assignProperties = nodeConfig_1.NodeConfig.createPropertyAssignment(node);
|
|
106
103
|
if (typeof props === "function") {
|
|
107
104
|
const scope = Store_1.ObservableScope.Create(props);
|
|
108
|
-
// const [value, scope] = ObservableScope.CreateIf(props as () => any);
|
|
109
|
-
// if (scope) {
|
|
110
105
|
vnode.scopes.push(scope);
|
|
111
106
|
Store_1.ObservableScope.Watch(scope, ScheduledAssignment(assignProperties));
|
|
112
|
-
// }
|
|
113
107
|
assignProperties(Store_1.ObservableScope.Value(scope));
|
|
114
108
|
}
|
|
115
109
|
else
|
|
@@ -119,11 +113,8 @@ function InitNode(vnode) {
|
|
|
119
113
|
const assignEvents = nodeConfig_1.NodeConfig.createEventAssignment(node);
|
|
120
114
|
if (typeof on === "function") {
|
|
121
115
|
const scope = Store_1.ObservableScope.Create(on);
|
|
122
|
-
// const [value, scope] = ObservableScope.CreateIf(on);
|
|
123
|
-
// if (scope) {
|
|
124
116
|
vnode.scopes.push(scope);
|
|
125
117
|
Store_1.ObservableScope.Watch(scope, ScheduledAssignment(assignEvents));
|
|
126
|
-
// }
|
|
127
118
|
assignEvents(Store_1.ObservableScope.Value(scope));
|
|
128
119
|
}
|
|
129
120
|
else
|
|
@@ -133,19 +124,14 @@ function InitNode(vnode) {
|
|
|
133
124
|
const assignAttributes = nodeConfig_1.NodeConfig.createAttributeAssignment(node);
|
|
134
125
|
if (typeof attrs === "function") {
|
|
135
126
|
const scope = Store_1.ObservableScope.Create(attrs);
|
|
136
|
-
// const [value, scope] = ObservableScope.CreateIf(attrs);
|
|
137
|
-
// if (scope) {
|
|
138
127
|
vnode.scopes.push(scope);
|
|
139
128
|
Store_1.ObservableScope.Watch(scope, ScheduledAssignment(assignAttributes));
|
|
140
|
-
//}
|
|
141
129
|
assignAttributes(Store_1.ObservableScope.Value(scope));
|
|
142
130
|
}
|
|
143
131
|
else
|
|
144
132
|
assignAttributes(attrs);
|
|
145
133
|
}
|
|
146
|
-
// if (componentConstructor) {
|
|
147
134
|
if (componentFactory) {
|
|
148
|
-
// vnode.component = new componentConstructor(vnode);
|
|
149
135
|
vnode.component = componentFactory(vnode);
|
|
150
136
|
vnode.component.Bound();
|
|
151
137
|
function componentChildren() {
|
|
@@ -171,7 +157,6 @@ function Children(vnode, children, data) {
|
|
|
171
157
|
return;
|
|
172
158
|
const startChildren = vnode.children;
|
|
173
159
|
const newChildren = Store_1.ObservableScope.Value(scope);
|
|
174
|
-
// AssignChildren(vnode, scope);
|
|
175
160
|
if (startChildren !== newChildren) {
|
|
176
161
|
vnode.children = newChildren;
|
|
177
162
|
UpdateChildren(vnode);
|
|
@@ -179,21 +164,7 @@ function Children(vnode, children, data) {
|
|
|
179
164
|
}));
|
|
180
165
|
}
|
|
181
166
|
vnode.children = Store_1.ObservableScope.Value(childrenScope);
|
|
182
|
-
// AssignChildren(vnode, childrenScope);
|
|
183
167
|
}
|
|
184
|
-
/* function AssignChildren(
|
|
185
|
-
vnode: vNodeType,
|
|
186
|
-
childrenScope: IObservableScope<
|
|
187
|
-
[
|
|
188
|
-
any,
|
|
189
|
-
vNodeType[],
|
|
190
|
-
IObservableScope<string | vNodeType | vNodeType[]> | null,
|
|
191
|
-
][]
|
|
192
|
-
>,
|
|
193
|
-
) {
|
|
194
|
-
const children = ObservableScope.Peek(childrenScope);
|
|
195
|
-
vnode.children = children;
|
|
196
|
-
} */
|
|
197
168
|
const DEFAULT_DATA = [undefined];
|
|
198
169
|
function DefaultData() {
|
|
199
170
|
return DEFAULT_DATA;
|
|
@@ -302,7 +273,6 @@ function EvaluateNextNodesLarge(injector, getNextChildren, nextData, nodeArray)
|
|
|
302
273
|
if (currentChildIndex !== -1) {
|
|
303
274
|
const currentChild = currentChildren[currentChildIndex];
|
|
304
275
|
currentChildren[currentChildIndex] = null;
|
|
305
|
-
// if (currentChild[2]) {
|
|
306
276
|
const scope = currentChild[2];
|
|
307
277
|
const value = scope.value;
|
|
308
278
|
const updatedValue = Store_1.ObservableScope.Value(scope);
|
|
@@ -310,13 +280,7 @@ function EvaluateNextNodesLarge(injector, getNextChildren, nextData, nodeArray)
|
|
|
310
280
|
vNode.DestroyAll(currentChild[1]);
|
|
311
281
|
currentChild[1] = CreateNodeArray(updatedValue);
|
|
312
282
|
}
|
|
313
|
-
// }
|
|
314
|
-
/* if (currentChild[2]?.dirty) {
|
|
315
|
-
const nextChildren = ObservableScope.Value(currentChild[2]);
|
|
316
|
-
currentChild[1] = CreateNodeArray(nextChildren);
|
|
317
|
-
} */
|
|
318
283
|
nextNodes[x] = currentChild;
|
|
319
|
-
// currentChildren[currentChildIndex] = null;
|
|
320
284
|
if (currentChildIndex === 0)
|
|
321
285
|
dataMap.delete(data);
|
|
322
286
|
}
|
|
@@ -324,9 +288,6 @@ function EvaluateNextNodesLarge(injector, getNextChildren, nextData, nodeArray)
|
|
|
324
288
|
const scope = Store_1.ObservableScope.Create(function () {
|
|
325
289
|
return injector_1.Injector.Scope(injector, getNextChildren, data);
|
|
326
290
|
});
|
|
327
|
-
/* const [nextChildren, scope] = ObservableScope.CreateIf(function () {
|
|
328
|
-
return Injector.Scope(injector, getNextChildren, data);
|
|
329
|
-
}); */
|
|
330
291
|
nextNodes[x] = [
|
|
331
292
|
data,
|
|
332
293
|
CreateNodeArray(Store_1.ObservableScope.Value(scope)),
|
|
@@ -411,7 +372,6 @@ function ScheduledAssignment(assign) {
|
|
|
411
372
|
return;
|
|
412
373
|
scheduled = true;
|
|
413
374
|
nodeConfig_1.NodeConfig.scheduleUpdate(function () {
|
|
414
|
-
// if (scope.destroyed) return;
|
|
415
375
|
scheduled = false;
|
|
416
376
|
const value = Store_1.ObservableScope.Peek(scope);
|
|
417
377
|
assign(value);
|
|
@@ -1,39 +1,138 @@
|
|
|
1
1
|
import { Emitter, EmitterCallback } from "../../Utils/emitter";
|
|
2
|
+
/**
|
|
3
|
+
* Represents a static (non-reactive) observable scope.
|
|
4
|
+
* Static scopes are immutable and do not track dependencies or emit updates.
|
|
5
|
+
* @template T The type of value stored in the scope.
|
|
6
|
+
*/
|
|
2
7
|
interface IStaticObservableScope<T> {
|
|
3
8
|
type: "static";
|
|
4
9
|
value: T;
|
|
5
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Represents a dynamic (reactive) observable scope.
|
|
13
|
+
* Dynamic scopes track dependencies, detect when values change, and emit updates.
|
|
14
|
+
* @template T The type of value stored in the scope.
|
|
15
|
+
*/
|
|
6
16
|
interface IDynamicObservableScope<T> {
|
|
7
17
|
type: "dynamic";
|
|
18
|
+
/** Whether the scope's getter function is async */
|
|
8
19
|
async: boolean;
|
|
20
|
+
/** Whether updates are batched (true) or immediate (false) */
|
|
9
21
|
greedy: boolean;
|
|
22
|
+
/** Whether the scope needs recomputation */
|
|
10
23
|
dirty: boolean;
|
|
24
|
+
/** Whether the scope has been destroyed */
|
|
11
25
|
destroyed: boolean;
|
|
26
|
+
/** Function that returns the scope's current or computed value */
|
|
12
27
|
getFunction: () => Promise<T> | T;
|
|
28
|
+
/** Callback invoked when dependencies change */
|
|
13
29
|
setCallback: EmitterCallback;
|
|
30
|
+
/** Current cached value */
|
|
14
31
|
value: T;
|
|
32
|
+
/** Emitter for notifying listeners of value changes */
|
|
15
33
|
emitter: Emitter;
|
|
34
|
+
/** Array of emitters this scope listens to for dependency changes */
|
|
16
35
|
emitters: (Emitter | null)[];
|
|
36
|
+
/** Emitter for notifying when the scope is destroyed */
|
|
17
37
|
onDestroyed: Emitter | null;
|
|
38
|
+
/** Map of nested calc scopes created during this scope's execution */
|
|
18
39
|
calcScopes: {
|
|
19
40
|
[id: string]: IObservableScope<unknown> | null;
|
|
20
41
|
} | null;
|
|
21
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* A reactive or static scope containing a value.
|
|
45
|
+
* @template T The type of value stored in the scope.
|
|
46
|
+
*/
|
|
22
47
|
export type IObservableScope<T> = IStaticObservableScope<T> | IDynamicObservableScope<T>;
|
|
48
|
+
/**
|
|
49
|
+
* Creates a computed scope that acts as a gatekeeper for parent scope emissions.
|
|
50
|
+
* If this scope's value doesn't change (=== comparison) it won't emit.
|
|
51
|
+
*
|
|
52
|
+
* Useful for optimizing expensive operations driven by key values (e.g., sort keys).
|
|
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.
|
|
55
|
+
*
|
|
56
|
+
* Only works within a watch context (during another scope's execution).
|
|
57
|
+
* Always creates greedy scopes that batch updates via microtask queue.
|
|
58
|
+
* @template T The type of value returned by the callback.
|
|
59
|
+
* @param callback The function to compute the derived value.
|
|
60
|
+
* @param idOverride Optional custom ID for memoization when using multiple calc scopes.
|
|
61
|
+
* @returns The computed value, reusing existing scope if available.
|
|
62
|
+
*/
|
|
23
63
|
export declare function CalcScope<T>(callback: () => T, idOverride?: string): T;
|
|
24
64
|
export declare namespace ObservableScope {
|
|
65
|
+
/**
|
|
66
|
+
* Creates a new observable scope from a value function.
|
|
67
|
+
* @template T The type of value returned by the function.
|
|
68
|
+
* @param valueFunction Function that returns the scope's value. Can be async.
|
|
69
|
+
* @param greedy Whether updates should be batched via microtask queue. Defaults to false.
|
|
70
|
+
* @param force If true, always creates a dynamic scope even without dependencies. Defaults to false.
|
|
71
|
+
* @returns A new observable scope.
|
|
72
|
+
*/
|
|
25
73
|
function Create<T>(valueFunction: {
|
|
26
74
|
(): T | Promise<T>;
|
|
27
75
|
}, greedy?: boolean, force?: boolean): IObservableScope<T>;
|
|
76
|
+
/**
|
|
77
|
+
* Registers an emitter as a dependency for the current watch context.
|
|
78
|
+
* @param emitter The emitter to register as a dependency.
|
|
79
|
+
*/
|
|
28
80
|
function Register(emitter: Emitter): void;
|
|
81
|
+
/**
|
|
82
|
+
* Gets a scope's current value without registering as a dependency.
|
|
83
|
+
* @template T The type of value stored in the scope.
|
|
84
|
+
* @param scope The scope to peek at.
|
|
85
|
+
* @returns The scope's current value.
|
|
86
|
+
*/
|
|
29
87
|
function Peek<T>(scope: IObservableScope<T>): T;
|
|
88
|
+
/**
|
|
89
|
+
* Gets a scope's current value and registers as a dependency.
|
|
90
|
+
* @template T The type of value stored in the scope.
|
|
91
|
+
* @param scope The scope to get the value from.
|
|
92
|
+
* @returns The scope's current value.
|
|
93
|
+
*/
|
|
30
94
|
function Value<T>(scope: IObservableScope<T>): T;
|
|
95
|
+
/**
|
|
96
|
+
* Registers a scope as a dependency without retrieving its value.
|
|
97
|
+
* @template T The type of value stored in the scope.
|
|
98
|
+
* @param scope The scope to register as a dependency.
|
|
99
|
+
*/
|
|
31
100
|
function Touch<T>(scope: IObservableScope<T>): void;
|
|
101
|
+
/**
|
|
102
|
+
* Subscribes to changes on a dynamic scope.
|
|
103
|
+
* @template T The type of value stored in the scope.
|
|
104
|
+
* @param scope The scope to watch for changes.
|
|
105
|
+
* @param callback Function to invoke when the scope's value changes.
|
|
106
|
+
*/
|
|
32
107
|
function Watch<T>(scope: IObservableScope<T>, callback: EmitterCallback<[IObservableScope<T>]>): void;
|
|
108
|
+
/**
|
|
109
|
+
* Unsubscribes from changes on a dynamic scope.
|
|
110
|
+
* @template T The type of value stored in the scope.
|
|
111
|
+
* @param scope The scope to stop watching.
|
|
112
|
+
* @param callback The callback function to remove.
|
|
113
|
+
*/
|
|
33
114
|
function Unwatch<T>(scope: IObservableScope<T>, callback: EmitterCallback<[IObservableScope<T>]>): void;
|
|
115
|
+
/**
|
|
116
|
+
* Registers a callback to be invoked when the scope is destroyed.
|
|
117
|
+
* @param scope The scope to monitor for destruction.
|
|
118
|
+
* @param callback Function to invoke when the scope is destroyed.
|
|
119
|
+
*/
|
|
34
120
|
function OnDestroyed(scope: IObservableScope<unknown>, callback: EmitterCallback): void;
|
|
121
|
+
/**
|
|
122
|
+
* Marks a scope as dirty, triggering recomputation on next access or batch.
|
|
123
|
+
* @param scope The scope to mark for update.
|
|
124
|
+
*/
|
|
35
125
|
function Update(scope: IObservableScope<any>): void;
|
|
126
|
+
/**
|
|
127
|
+
* Destroys a scope, cleaning up all resources and dependencies.
|
|
128
|
+
* @template T The type of value stored in the scope.
|
|
129
|
+
* @param scope The scope to destroy.
|
|
130
|
+
*/
|
|
36
131
|
function Destroy<T>(scope: IObservableScope<T>): void;
|
|
132
|
+
/**
|
|
133
|
+
* Destroys multiple scopes, cleaning up their resources.
|
|
134
|
+
* @param scopes Array of scopes to destroy.
|
|
135
|
+
*/
|
|
37
136
|
function DestroyAll(scopes: IObservableScope<unknown>[]): void;
|
|
38
137
|
}
|
|
39
138
|
export {};
|
|
@@ -5,6 +5,15 @@ exports.CalcScope = CalcScope;
|
|
|
5
5
|
const array_1 = require("../../Utils/array");
|
|
6
6
|
const emitter_1 = require("../../Utils/emitter");
|
|
7
7
|
const functions_1 = require("../../Utils/functions");
|
|
8
|
+
const list_1 = require("../../Utils/list");
|
|
9
|
+
/**
|
|
10
|
+
* Creates a dynamic (reactive) observable scope.
|
|
11
|
+
* @template T The type of value stored in the scope.
|
|
12
|
+
* @param getFunction Function that returns the scope's value. May be async.
|
|
13
|
+
* @param greedy Whether updates should be batched via microtask queue.
|
|
14
|
+
* @param value Initial value for the scope (null for async functions).
|
|
15
|
+
* @returns A new dynamic observable scope.
|
|
16
|
+
*/
|
|
8
17
|
function CreateDynamicScope(getFunction, greedy, value) {
|
|
9
18
|
const async = (0, functions_1.IsAsync)(getFunction);
|
|
10
19
|
const scope = {
|
|
@@ -25,6 +34,13 @@ function CreateDynamicScope(getFunction, greedy, value) {
|
|
|
25
34
|
};
|
|
26
35
|
return scope;
|
|
27
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* Creates a static (non-reactive) observable scope.
|
|
39
|
+
* Static scopes are optimized for values that never change and don't need dependency tracking.
|
|
40
|
+
* @template T The type of value stored in the scope.
|
|
41
|
+
* @param initialValue The immutable value to store in the scope.
|
|
42
|
+
* @returns A new static observable scope.
|
|
43
|
+
*/
|
|
28
44
|
function CreateStaticScope(initialValue) {
|
|
29
45
|
return {
|
|
30
46
|
type: "static",
|
|
@@ -50,6 +66,11 @@ function OnSetQueued(scope) {
|
|
|
50
66
|
queueMicrotask(ProcessScopeQueue);
|
|
51
67
|
scopeQueue.push(scope);
|
|
52
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Marks a scope as dirty and triggers update behavior based on scope type.
|
|
71
|
+
* @param scope The scope to mark for update.
|
|
72
|
+
* @returns true if the scope is static or destroyed, false if queued or non-greedy scope emitted.
|
|
73
|
+
*/
|
|
53
74
|
function OnSet(scope) {
|
|
54
75
|
if (scope.type === "static" || scope.destroyed)
|
|
55
76
|
return true;
|
|
@@ -63,59 +84,136 @@ function OnSet(scope) {
|
|
|
63
84
|
emitter_1.Emitter.Emit(scope.emitter, scope);
|
|
64
85
|
return false;
|
|
65
86
|
}
|
|
66
|
-
function
|
|
67
|
-
if (
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
watchState.emitterIds.add(emitter[0]);
|
|
71
|
-
}
|
|
87
|
+
function RegisterSame(state, emitter) {
|
|
88
|
+
if (state.emitterIndex < state.emitters.length &&
|
|
89
|
+
state.emitters[state.emitterIndex] === emitter) {
|
|
90
|
+
state.emitterIndex++;
|
|
72
91
|
return;
|
|
73
92
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
93
|
+
state.emitters = state.emitters.slice(0, state.emitterIndex);
|
|
94
|
+
state.emitters.push(emitter);
|
|
95
|
+
state.emitterIndex = -1;
|
|
96
|
+
state.strategy = PUSH_STRATEGY;
|
|
97
|
+
}
|
|
98
|
+
function RegisterPush(state, emitter) {
|
|
99
|
+
state.emitters.push(emitter);
|
|
100
|
+
if (state.emitters.length > 50) {
|
|
101
|
+
const idSet = (state.emitterIds = new Set([state.emitters[0][0]]));
|
|
77
102
|
let writePos = 0;
|
|
78
|
-
for (let x = 1; x <
|
|
79
|
-
if (!idSet.has(
|
|
80
|
-
|
|
81
|
-
idSet.add(
|
|
103
|
+
for (let x = 1; x < state.emitters.length; x++) {
|
|
104
|
+
if (!idSet.has(state.emitters[x][0])) {
|
|
105
|
+
state.emitters[++writePos] = state.emitters[x];
|
|
106
|
+
idSet.add(state.emitters[x][0]);
|
|
82
107
|
}
|
|
83
108
|
}
|
|
84
109
|
writePos++;
|
|
85
|
-
if (writePos <
|
|
86
|
-
|
|
110
|
+
if (writePos < state.emitters.length)
|
|
111
|
+
state.emitters.splice(writePos);
|
|
112
|
+
state.strategy = DISTINCT_STRATEGY;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function RegisterDistinct(state, emitter) {
|
|
116
|
+
if (!state.emitterIds.has(emitter[0])) {
|
|
117
|
+
state.emitters.push(emitter);
|
|
118
|
+
state.emitterIds.add(emitter[0]);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function RegisterEmitter(emitter) {
|
|
122
|
+
if (watchState === null)
|
|
123
|
+
return;
|
|
124
|
+
switch (watchState.strategy) {
|
|
125
|
+
case SAME_STRATEGY:
|
|
126
|
+
RegisterSame(watchState, emitter);
|
|
127
|
+
break;
|
|
128
|
+
case PUSH_STRATEGY:
|
|
129
|
+
RegisterPush(watchState, emitter);
|
|
130
|
+
break;
|
|
131
|
+
case DISTINCT_STRATEGY:
|
|
132
|
+
RegisterDistinct(watchState, emitter);
|
|
133
|
+
break;
|
|
87
134
|
}
|
|
88
135
|
}
|
|
136
|
+
/**
|
|
137
|
+
* Registers a scope as a dependency for the current watch context.
|
|
138
|
+
* @param scope The scope to register as a dependency.
|
|
139
|
+
*/
|
|
89
140
|
function RegisterScope(scope) {
|
|
90
141
|
if (watchState === null || scope.type === "static")
|
|
91
142
|
return;
|
|
92
143
|
RegisterEmitter(scope.emitter);
|
|
93
144
|
}
|
|
145
|
+
/**
|
|
146
|
+
* Gets the current value of a scope, recomputing if dirty.
|
|
147
|
+
* @template T The type of value stored in the scope.
|
|
148
|
+
* @param scope The scope to get the value from.
|
|
149
|
+
* @returns The scope's current value.
|
|
150
|
+
*/
|
|
94
151
|
function GetScopeValue(scope) {
|
|
95
152
|
if (scope.type === "static" || !scope.dirty || scope.destroyed)
|
|
96
153
|
return scope.value;
|
|
97
154
|
ExecuteScope(scope);
|
|
98
155
|
return scope.value;
|
|
99
156
|
}
|
|
157
|
+
const SAME_STRATEGY = 1;
|
|
158
|
+
const PUSH_STRATEGY = 2;
|
|
159
|
+
const DISTINCT_STRATEGY = 3;
|
|
160
|
+
const SHRINK_STRATEGY = 4;
|
|
100
161
|
let watchState = null;
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
162
|
+
const watchPool = list_1.List.Create();
|
|
163
|
+
function CreateWatchState() {
|
|
164
|
+
return (list_1.List.Pop(watchPool) ?? {
|
|
165
|
+
emitterIndex: 0,
|
|
104
166
|
value: null,
|
|
105
|
-
emitters:
|
|
167
|
+
emitters: null,
|
|
106
168
|
emitterIds: null,
|
|
107
|
-
currentCalc:
|
|
169
|
+
currentCalc: null,
|
|
108
170
|
nextCalc: null,
|
|
109
|
-
|
|
171
|
+
strategy: PUSH_STRATEGY,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
function ReturnWatchState(state) {
|
|
175
|
+
state.emitterIndex = 0;
|
|
176
|
+
state.value = null;
|
|
177
|
+
state.emitters = null;
|
|
178
|
+
state.emitterIds = null;
|
|
179
|
+
state.currentCalc = null;
|
|
180
|
+
state.nextCalc = null;
|
|
181
|
+
state.strategy = PUSH_STRATEGY;
|
|
182
|
+
list_1.List.Push(watchPool, state);
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Executes a callback while tracking all scope and emitter dependencies.
|
|
186
|
+
* Creates a watch context that records what was accessed during execution.
|
|
187
|
+
* @param callback The function to execute while tracking dependencies.
|
|
188
|
+
* @param currentCalc Optional map of existing calc scopes to reuse.
|
|
189
|
+
* @returns The watch state containing tracked dependencies and result.
|
|
190
|
+
*/
|
|
191
|
+
function WatchFunction(callback, currentCalc, initialEmitters) {
|
|
192
|
+
const parent = watchState;
|
|
193
|
+
watchState = CreateWatchState();
|
|
194
|
+
watchState.emitters = initialEmitters ?? [];
|
|
195
|
+
watchState.currentCalc = currentCalc;
|
|
196
|
+
if (initialEmitters !== null)
|
|
197
|
+
watchState.strategy = SAME_STRATEGY;
|
|
110
198
|
watchState.value = callback();
|
|
111
199
|
const resultState = watchState;
|
|
112
200
|
watchState = parent;
|
|
201
|
+
if (resultState.strategy === SAME_STRATEGY &&
|
|
202
|
+
resultState.emitterIndex < resultState.emitters.length) {
|
|
203
|
+
resultState.emitters = resultState.emitters.slice(0, resultState.emitterIndex);
|
|
204
|
+
resultState.strategy = SHRINK_STRATEGY;
|
|
205
|
+
}
|
|
113
206
|
return resultState;
|
|
114
207
|
}
|
|
208
|
+
/**
|
|
209
|
+
* Recomputes a scope's value by re-executing its getFunction.
|
|
210
|
+
* Updates the scope's dependencies and emits if the value changed.
|
|
211
|
+
* @param scope The scope to recompute.
|
|
212
|
+
*/
|
|
115
213
|
function ExecuteScope(scope) {
|
|
116
214
|
scope.dirty = false;
|
|
117
|
-
const state = WatchFunction(scope.getFunction, scope.calcScopes);
|
|
118
|
-
UpdateEmitters(scope, state.emitters,
|
|
215
|
+
const state = WatchFunction(scope.getFunction, scope.calcScopes, scope.emitters);
|
|
216
|
+
UpdateEmitters(scope, state.emitters, state.strategy);
|
|
119
217
|
const calcScopes = state.currentCalc;
|
|
120
218
|
scope.calcScopes = state.nextCalc;
|
|
121
219
|
for (const key in calcScopes)
|
|
@@ -127,28 +225,55 @@ function ExecuteScope(scope) {
|
|
|
127
225
|
});
|
|
128
226
|
else
|
|
129
227
|
scope.value = state.value;
|
|
228
|
+
ReturnWatchState(state);
|
|
130
229
|
}
|
|
230
|
+
/**
|
|
231
|
+
* Creates a scope from a function, choosing between static and dynamic based on dependencies.
|
|
232
|
+
* @template T The type of value returned by the callback.
|
|
233
|
+
* @param callback The function to compute the scope's value.
|
|
234
|
+
* @param greedy Whether the scope should batch updates.
|
|
235
|
+
* @param allowStatic Whether to return a static scope if no dependencies are found.
|
|
236
|
+
* @returns A new observable scope.
|
|
237
|
+
*/
|
|
131
238
|
function ExecuteFunction(callback, greedy, allowStatic) {
|
|
132
239
|
const async = (0, functions_1.IsAsync)(callback);
|
|
133
|
-
const state = WatchFunction(callback);
|
|
134
|
-
if (!allowStatic || async || state.emitters
|
|
240
|
+
const state = WatchFunction(callback, null, null);
|
|
241
|
+
if (!allowStatic || async || state.emitters !== null) {
|
|
135
242
|
const scope = CreateDynamicScope(callback, greedy, async ? null : state.value);
|
|
136
243
|
scope.calcScopes = state.nextCalc;
|
|
137
|
-
UpdateEmitters(scope, state.emitters,
|
|
244
|
+
UpdateEmitters(scope, state.emitters, state.strategy);
|
|
138
245
|
if (async)
|
|
139
246
|
state.value.then(function (result) {
|
|
140
247
|
scope.value = result;
|
|
141
248
|
emitter_1.Emitter.Emit(scope.emitter, scope);
|
|
142
249
|
});
|
|
250
|
+
ReturnWatchState(state);
|
|
143
251
|
return scope;
|
|
144
252
|
}
|
|
145
|
-
|
|
253
|
+
const value = state.value;
|
|
254
|
+
ReturnWatchState(state);
|
|
255
|
+
return CreateStaticScope(value);
|
|
146
256
|
}
|
|
257
|
+
/**
|
|
258
|
+
* Creates a computed scope that acts as a gatekeeper for parent scope emissions.
|
|
259
|
+
* If this scope's value doesn't change (=== comparison) it won't emit.
|
|
260
|
+
*
|
|
261
|
+
* Useful for optimizing expensive operations driven by key values (e.g., sort keys).
|
|
262
|
+
* Scopes are memoized by ID and reused across multiple reads within a single parent scope evaluation.
|
|
263
|
+
* Defaults to "default" ID - provide custom IDs when using multiple calc scopes.
|
|
264
|
+
*
|
|
265
|
+
* Only works within a watch context (during another scope's execution).
|
|
266
|
+
* Always creates greedy scopes that batch updates via microtask queue.
|
|
267
|
+
* @template T The type of value returned by the callback.
|
|
268
|
+
* @param callback The function to compute the derived value.
|
|
269
|
+
* @param idOverride Optional custom ID for memoization when using multiple calc scopes.
|
|
270
|
+
* @returns The computed value, reusing existing scope if available.
|
|
271
|
+
*/
|
|
147
272
|
function CalcScope(callback, idOverride) {
|
|
148
273
|
if (watchState === null)
|
|
149
274
|
return callback();
|
|
150
275
|
const nextScopes = (watchState.nextCalc ??= {});
|
|
151
|
-
const id = idOverride ??
|
|
276
|
+
const id = idOverride ?? "default";
|
|
152
277
|
if (nextScopes[id]) {
|
|
153
278
|
RegisterScope(nextScopes[id]);
|
|
154
279
|
return GetScopeValue(nextScopes[id]);
|
|
@@ -160,33 +285,53 @@ function CalcScope(callback, idOverride) {
|
|
|
160
285
|
RegisterScope(nextScopes[id]);
|
|
161
286
|
return GetScopeValue(nextScopes[id]);
|
|
162
287
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
for (let x =
|
|
288
|
+
/**
|
|
289
|
+
* Updates a scope's dependency emitters using efficient diffing.
|
|
290
|
+
* Subscribes to new emitters and unsubscribes from removed ones.
|
|
291
|
+
* @param scope The scope to update dependencies for.
|
|
292
|
+
* @param right The new list of emitters to track.
|
|
293
|
+
* @param distinct Whether emitters are already unique (sorted and deduplicated).
|
|
294
|
+
*/
|
|
295
|
+
function UpdateEmitters(scope, right, strategy) {
|
|
296
|
+
switch (strategy) {
|
|
297
|
+
case SHRINK_STRATEGY: {
|
|
298
|
+
for (let x = right.length; x < scope.emitters.length; x++)
|
|
174
299
|
emitter_1.Emitter.Remove(scope.emitters[x], scope.setCallback);
|
|
175
|
-
|
|
300
|
+
break;
|
|
176
301
|
}
|
|
177
|
-
|
|
302
|
+
case PUSH_STRATEGY:
|
|
303
|
+
case DISTINCT_STRATEGY:
|
|
304
|
+
strategy === PUSH_STRATEGY
|
|
305
|
+
? emitter_1.Emitter.Distinct(right)
|
|
306
|
+
: emitter_1.Emitter.Sort(right);
|
|
307
|
+
if (scope.emitters === null || scope.emitters.length === 0) {
|
|
308
|
+
for (let x = 0; x < right.length; x++)
|
|
309
|
+
emitter_1.Emitter.On(right[x], scope.setCallback);
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
(0, array_1.ReconcileSortedEmitters)(scope.emitters, right, function (emitter) {
|
|
313
|
+
emitter_1.Emitter.On(emitter, scope.setCallback);
|
|
314
|
+
}, function (emitter) {
|
|
315
|
+
emitter_1.Emitter.Remove(emitter, scope.setCallback);
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
break;
|
|
178
319
|
}
|
|
179
|
-
(0, array_1.ReconcileSortedEmitters)(scope.emitters, right, function (emitter) {
|
|
180
|
-
emitter_1.Emitter.On(emitter, scope.setCallback);
|
|
181
|
-
}, function (emitter) {
|
|
182
|
-
emitter_1.Emitter.Remove(emitter, scope.setCallback);
|
|
183
|
-
});
|
|
184
320
|
scope.emitters = right;
|
|
185
321
|
}
|
|
322
|
+
/**
|
|
323
|
+
* Destroys multiple scopes, cleaning up their resources.
|
|
324
|
+
* @param scopes Array of scopes to destroy.
|
|
325
|
+
*/
|
|
186
326
|
function DestroyAllScopes(scopes) {
|
|
187
327
|
for (let x = 0; x < scopes.length; x++)
|
|
188
328
|
DestroyScope(scopes[x]);
|
|
189
329
|
}
|
|
330
|
+
/**
|
|
331
|
+
* Destroys a scope, cleaning up all resources and dependencies.
|
|
332
|
+
* Unsubscribes from emitters, destroys nested scopes, and clears references.
|
|
333
|
+
* @param scope The scope to destroy.
|
|
334
|
+
*/
|
|
190
335
|
function DestroyScope(scope) {
|
|
191
336
|
if (!scope || scope.type === "static")
|
|
192
337
|
return;
|
|
@@ -207,18 +352,42 @@ function DestroyScope(scope) {
|
|
|
207
352
|
}
|
|
208
353
|
var ObservableScope;
|
|
209
354
|
(function (ObservableScope) {
|
|
355
|
+
/**
|
|
356
|
+
* Creates a new observable scope from a value function.
|
|
357
|
+
* @template T The type of value returned by the function.
|
|
358
|
+
* @param valueFunction Function that returns the scope's value. Can be async.
|
|
359
|
+
* @param greedy Whether updates should be batched via microtask queue. Defaults to false.
|
|
360
|
+
* @param force If true, always creates a dynamic scope even without dependencies. Defaults to false.
|
|
361
|
+
* @returns A new observable scope.
|
|
362
|
+
*/
|
|
210
363
|
function Create(valueFunction, greedy = false, force = false) {
|
|
211
364
|
return ExecuteFunction(valueFunction, greedy, !force);
|
|
212
365
|
}
|
|
213
366
|
ObservableScope.Create = Create;
|
|
367
|
+
/**
|
|
368
|
+
* Registers an emitter as a dependency for the current watch context.
|
|
369
|
+
* @param emitter The emitter to register as a dependency.
|
|
370
|
+
*/
|
|
214
371
|
function Register(emitter) {
|
|
215
372
|
RegisterEmitter(emitter);
|
|
216
373
|
}
|
|
217
374
|
ObservableScope.Register = Register;
|
|
375
|
+
/**
|
|
376
|
+
* Gets a scope's current value without registering as a dependency.
|
|
377
|
+
* @template T The type of value stored in the scope.
|
|
378
|
+
* @param scope The scope to peek at.
|
|
379
|
+
* @returns The scope's current value.
|
|
380
|
+
*/
|
|
218
381
|
function Peek(scope) {
|
|
219
382
|
return GetScopeValue(scope);
|
|
220
383
|
}
|
|
221
384
|
ObservableScope.Peek = Peek;
|
|
385
|
+
/**
|
|
386
|
+
* Gets a scope's current value and registers as a dependency.
|
|
387
|
+
* @template T The type of value stored in the scope.
|
|
388
|
+
* @param scope The scope to get the value from.
|
|
389
|
+
* @returns The scope's current value.
|
|
390
|
+
*/
|
|
222
391
|
function Value(scope) {
|
|
223
392
|
if (!scope)
|
|
224
393
|
return undefined;
|
|
@@ -226,24 +395,46 @@ var ObservableScope;
|
|
|
226
395
|
return Peek(scope);
|
|
227
396
|
}
|
|
228
397
|
ObservableScope.Value = Value;
|
|
398
|
+
/**
|
|
399
|
+
* Registers a scope as a dependency without retrieving its value.
|
|
400
|
+
* @template T The type of value stored in the scope.
|
|
401
|
+
* @param scope The scope to register as a dependency.
|
|
402
|
+
*/
|
|
229
403
|
function Touch(scope) {
|
|
230
404
|
if (!scope)
|
|
231
405
|
return;
|
|
232
406
|
RegisterScope(scope);
|
|
233
407
|
}
|
|
234
408
|
ObservableScope.Touch = Touch;
|
|
409
|
+
/**
|
|
410
|
+
* Subscribes to changes on a dynamic scope.
|
|
411
|
+
* @template T The type of value stored in the scope.
|
|
412
|
+
* @param scope The scope to watch for changes.
|
|
413
|
+
* @param callback Function to invoke when the scope's value changes.
|
|
414
|
+
*/
|
|
235
415
|
function Watch(scope, callback) {
|
|
236
416
|
if (!scope || scope.type === "static")
|
|
237
417
|
return;
|
|
238
418
|
emitter_1.Emitter.On(scope.emitter, callback);
|
|
239
419
|
}
|
|
240
420
|
ObservableScope.Watch = Watch;
|
|
421
|
+
/**
|
|
422
|
+
* Unsubscribes from changes on a dynamic scope.
|
|
423
|
+
* @template T The type of value stored in the scope.
|
|
424
|
+
* @param scope The scope to stop watching.
|
|
425
|
+
* @param callback The callback function to remove.
|
|
426
|
+
*/
|
|
241
427
|
function Unwatch(scope, callback) {
|
|
242
428
|
if (!scope || scope.type === "static")
|
|
243
429
|
return;
|
|
244
430
|
emitter_1.Emitter.Remove(scope.emitter, callback);
|
|
245
431
|
}
|
|
246
432
|
ObservableScope.Unwatch = Unwatch;
|
|
433
|
+
/**
|
|
434
|
+
* Registers a callback to be invoked when the scope is destroyed.
|
|
435
|
+
* @param scope The scope to monitor for destruction.
|
|
436
|
+
* @param callback Function to invoke when the scope is destroyed.
|
|
437
|
+
*/
|
|
247
438
|
function OnDestroyed(scope, callback) {
|
|
248
439
|
if (scope.type === "static")
|
|
249
440
|
return;
|
|
@@ -251,16 +442,29 @@ var ObservableScope;
|
|
|
251
442
|
emitter_1.Emitter.On(scope.onDestroyed, callback);
|
|
252
443
|
}
|
|
253
444
|
ObservableScope.OnDestroyed = OnDestroyed;
|
|
445
|
+
/**
|
|
446
|
+
* Marks a scope as dirty, triggering recomputation on next access or batch.
|
|
447
|
+
* @param scope The scope to mark for update.
|
|
448
|
+
*/
|
|
254
449
|
function Update(scope) {
|
|
255
450
|
if (!scope)
|
|
256
451
|
return;
|
|
257
452
|
OnSet(scope);
|
|
258
453
|
}
|
|
259
454
|
ObservableScope.Update = Update;
|
|
455
|
+
/**
|
|
456
|
+
* Destroys a scope, cleaning up all resources and dependencies.
|
|
457
|
+
* @template T The type of value stored in the scope.
|
|
458
|
+
* @param scope The scope to destroy.
|
|
459
|
+
*/
|
|
260
460
|
function Destroy(scope) {
|
|
261
461
|
DestroyScope(scope);
|
|
262
462
|
}
|
|
263
463
|
ObservableScope.Destroy = Destroy;
|
|
464
|
+
/**
|
|
465
|
+
* Destroys multiple scopes, cleaning up their resources.
|
|
466
|
+
* @param scopes Array of scopes to destroy.
|
|
467
|
+
*/
|
|
264
468
|
function DestroyAll(scopes) {
|
|
265
469
|
DestroyAllScopes(scopes);
|
|
266
470
|
}
|
package/Utils/decorators.js
CHANGED
|
@@ -20,9 +20,7 @@ exports.Scope = Scope;
|
|
|
20
20
|
exports.Watch = Watch;
|
|
21
21
|
exports.Inject = Inject;
|
|
22
22
|
exports.Destroy = Destroy;
|
|
23
|
-
// import { Component } from "../Node/component";
|
|
24
23
|
const observableScope_1 = require("../Store/Tree/observableScope");
|
|
25
|
-
// import { ElementNodeRefTypes } from "../Node/nodeRef.types";
|
|
26
24
|
const observableNode_1 = require("../Store/Tree/observableNode");
|
|
27
25
|
const Store_1 = require("../Store");
|
|
28
26
|
/**
|
|
@@ -365,14 +363,6 @@ function WatchDecorator(target, propertyKey, descriptor, scopeFunction) {
|
|
|
365
363
|
observableScope_1.ObservableScope.Watch(scope, function (scope) {
|
|
366
364
|
instance[propertyKey](observableScope_1.ObservableScope.Value(scope));
|
|
367
365
|
});
|
|
368
|
-
/* const [value, scope] = ObservableScope.CreateIf(scopeFunctionWrapper, true);
|
|
369
|
-
if (scope) {
|
|
370
|
-
const propertyMap = GetScopeMapForInstance(this);
|
|
371
|
-
propertyMap[propertyKey as string] = [scope, undefined];
|
|
372
|
-
ObservableScope.Watch(scope, function (scope) {
|
|
373
|
-
(instance as any)[propertyKey](ObservableScope.Value(scope));
|
|
374
|
-
});
|
|
375
|
-
} */
|
|
376
366
|
instance[propertyKey](observableScope_1.ObservableScope.Value(scope));
|
|
377
367
|
return instance;
|
|
378
368
|
}
|
package/Utils/emitter.js
CHANGED
|
@@ -42,11 +42,6 @@ var Emitter;
|
|
|
42
42
|
function Distinct(emitters) {
|
|
43
43
|
if (emitters.length < 2)
|
|
44
44
|
return;
|
|
45
|
-
// emitters.length < 51 ? DistinctSmall(emitters) : DistinctLarge(emitters);
|
|
46
|
-
DistinctSmall(emitters);
|
|
47
|
-
}
|
|
48
|
-
Emitter.Distinct = Distinct;
|
|
49
|
-
function DistinctSmall(emitters) {
|
|
50
45
|
Sort(emitters);
|
|
51
46
|
let writePos = 0;
|
|
52
47
|
for (let x = 1; x < emitters.length; x++) {
|
|
@@ -58,20 +53,7 @@ var Emitter;
|
|
|
58
53
|
if (writePos < emitters.length)
|
|
59
54
|
emitters.splice(writePos);
|
|
60
55
|
}
|
|
61
|
-
|
|
62
|
-
let writePos = 0;
|
|
63
|
-
const ids = new Set();
|
|
64
|
-
for (let x = 0; x < emitters.length; x++) {
|
|
65
|
-
const id = emitters[x][0];
|
|
66
|
-
if (!ids.has(id)) {
|
|
67
|
-
ids.add(id);
|
|
68
|
-
emitters[writePos++] = emitters[x];
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
if (writePos < emitters.length)
|
|
72
|
-
emitters.splice(writePos);
|
|
73
|
-
Sort(emitters);
|
|
74
|
-
}
|
|
56
|
+
Emitter.Distinct = Distinct;
|
|
75
57
|
function Sort(emitters) {
|
|
76
58
|
if (emitters.length < 11)
|
|
77
59
|
(0, array_1.InsertionSortTuples)(emitters);
|