j-templates 7.0.74 → 7.0.76

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DiffTreeFactory = DiffTreeFactory;
4
+ /**
5
+ * Factory function that creates a DiffTree class.
6
+ * Can operate in worker mode for async operations.
7
+ * @param jsonDiffFactory - Optional factory for JSON diff utilities
8
+ * @param worker - If true, sets up worker message handling
9
+ * @returns DiffTree constructor
10
+ */
4
11
  function DiffTreeFactory(jsonDiffFactory, worker) {
5
12
  const { JsonDiff, JsonType, JsonDeepClone } = jsonDiffFactory();
6
13
  const ctx = this;
@@ -35,6 +42,13 @@ function DiffTreeFactory(jsonDiffFactory, worker) {
35
42
  }
36
43
  };
37
44
  }
45
+ /**
46
+ * Flattens nested objects/arrays, extracting keyed objects to root.
47
+ * @param root - Root object to store flattened values
48
+ * @param value - Value to flatten
49
+ * @param keyFunc - Function to extract key from objects
50
+ * @returns The root object with flattened values
51
+ */
38
52
  function FlattenValue(root, value, keyFunc) {
39
53
  const type = JsonType(value);
40
54
  switch (type) {
@@ -54,6 +68,12 @@ function DiffTreeFactory(jsonDiffFactory, worker) {
54
68
  }
55
69
  return root;
56
70
  }
71
+ /**
72
+ * Retrieves a value from a source object using a dot-separated path.
73
+ * @param source - The source object
74
+ * @param path - Dot-separated path to the value (empty string returns source)
75
+ * @returns The value at the specified path
76
+ */
57
77
  function GetPathValue(source, path) {
58
78
  if (path === "")
59
79
  return source;
@@ -63,6 +83,12 @@ function DiffTreeFactory(jsonDiffFactory, worker) {
63
83
  curr = curr[parts[x]];
64
84
  return curr;
65
85
  }
86
+ /**
87
+ * Sets a value in a source object at the specified path.
88
+ * @param source - The source object
89
+ * @param path - Array of path segments (strings for keys, numbers for indices)
90
+ * @param value - The value to set
91
+ */
66
92
  function SetPathValue(source, path, value) {
67
93
  if (path.length === 0)
68
94
  return;
@@ -72,6 +98,14 @@ function DiffTreeFactory(jsonDiffFactory, worker) {
72
98
  curr = curr[path[x]];
73
99
  curr[path[x]] = value;
74
100
  }
101
+ /**
102
+ * Resolves a path to its keyed root object if applicable.
103
+ * Searches up the path to find an object with a key from keyFunc.
104
+ * @param source - The source object
105
+ * @param path - Dot-separated path
106
+ * @param keyFunc - Function to extract key from objects
107
+ * @returns The resolved path (possibly shortened to root key)
108
+ */
75
109
  function ResolveKeyPath(source, path, keyFunc) {
76
110
  const parts = path.split(".");
77
111
  const pathValues = new Array(parts.length - 1);
@@ -90,6 +124,15 @@ function DiffTreeFactory(jsonDiffFactory, worker) {
90
124
  }
91
125
  return path;
92
126
  }
127
+ /**
128
+ * Updates the source with a new value at the specified path and computes diffs.
129
+ * Also updates any keyed objects that were nested in the value.
130
+ * @param source - The source object to update
131
+ * @param path - Dot-separated path to update
132
+ * @param value - The new value
133
+ * @param keyFunc - Optional function to extract keys from objects
134
+ * @returns Diff results showing all changes made
135
+ */
93
136
  function UpdateSource(source, path, value, keyFunc) {
94
137
  const diffResult = [];
95
138
  if (keyFunc) {
@@ -115,20 +158,45 @@ function DiffTreeFactory(jsonDiffFactory, worker) {
115
158
  }
116
159
  return diffResult;
117
160
  }
161
+ /**
162
+ * Internal diff tree implementation.
163
+ * Maintains root state and computes diffs for path/value updates.
164
+ * @private
165
+ */
118
166
  class DiffTree {
167
+ /**
168
+ * Creates a DiffTree instance.
169
+ * @param keyFunc - Optional function to extract a key from objects
170
+ */
119
171
  constructor(keyFunc) {
120
172
  this.keyFunc = keyFunc;
121
173
  this.rootState = {};
122
174
  }
175
+ /**
176
+ * Computes diffs for a batch of path/value pairs.
177
+ * @param data - Array of objects with path and value properties
178
+ * @returns Combined diff results
179
+ */
123
180
  DiffBatch(data) {
124
181
  const results = data
125
182
  .map(({ path, value }) => this.DiffPath(path, value))
126
183
  .flat(1);
127
184
  return results;
128
185
  }
186
+ /**
187
+ * Computes the diff between a new value and the current value at a path.
188
+ * @param path - Dot-separated path to the value
189
+ * @param value - The new value to compare
190
+ * @returns Diff results showing changes
191
+ */
129
192
  DiffPath(path, value) {
130
193
  return UpdateSource(this.rootState, path, value, this.keyFunc);
131
194
  }
195
+ /**
196
+ * Retrieves the current value at a path.
197
+ * @param path - Dot-separated path to the value
198
+ * @returns The value at the specified path
199
+ */
132
200
  GetPath(path) {
133
201
  return GetPathValue(this.rootState, path);
134
202
  }
@@ -1,11 +1,49 @@
1
1
  import { JsonDiffResult } from "../../Utils/json";
2
+ /**
3
+ * Base class for observable data store management.
4
+ * Stores root objects as ObservableNode instances and manages updates through diff operations.
5
+ *
6
+ * @see StoreSync
7
+ * @see StoreAsync
8
+ */
2
9
  export declare class Store {
3
10
  protected keyFunc?: (value: any) => string | undefined;
4
11
  private rootMap;
5
12
  private createNode;
13
+ /**
14
+ * Creates an instance of Store.
15
+ * @param keyFunc Optional function to generate a key for a given data value.
16
+ * When provided, enables alias functionality where values can reference other root objects.
17
+ */
6
18
  constructor(keyFunc?: (value: any) => string | undefined);
19
+ /**
20
+ * Retrieves a value from the store by id.
21
+ * @template O - The type of the value to retrieve
22
+ * @param id - The id/key of the value
23
+ * @returns The value or undefined if not found
24
+ */
7
25
  Get<O>(id: string): O | undefined;
26
+ /**
27
+ * Retrieves a value from the store by id, with a default value if not found.
28
+ * @template O - The type of the value to retrieve
29
+ * @param id - The id/key of the value
30
+ * @param defaultValue - The default value to return if id doesn't exist
31
+ * @returns The value or the default value
32
+ */
8
33
  Get<O>(id: string, defaultValue: O): O;
34
+ /**
35
+ * Updates the root map with diff results by grouping changes by root path.
36
+ * @param results - Array of diff results to apply
37
+ * @protected
38
+ */
9
39
  protected UpdateRootMap(results: JsonDiffResult): void;
40
+ /**
41
+ * Updates a specific root object with diff results.
42
+ * Creates the root object if it doesn't exist.
43
+ * @param rootPath - The path of the root object
44
+ * @param results - Array of diff results to apply to this root object
45
+ * @throws If unable to initialize root path with the given results
46
+ * @private
47
+ */
10
48
  private UpdateRootObject;
11
49
  }
@@ -2,7 +2,19 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Store = void 0;
4
4
  const observableNode_1 = require("../Tree/observableNode");
5
+ /**
6
+ * Base class for observable data store management.
7
+ * Stores root objects as ObservableNode instances and manages updates through diff operations.
8
+ *
9
+ * @see StoreSync
10
+ * @see StoreAsync
11
+ */
5
12
  class Store {
13
+ /**
14
+ * Creates an instance of Store.
15
+ * @param keyFunc Optional function to generate a key for a given data value.
16
+ * When provided, enables alias functionality where values can reference other root objects.
17
+ */
6
18
  constructor(keyFunc) {
7
19
  this.keyFunc = keyFunc;
8
20
  this.rootMap = new Map();
@@ -30,6 +42,11 @@ class Store {
30
42
  }
31
43
  return result[id];
32
44
  }
45
+ /**
46
+ * Updates the root map with diff results by grouping changes by root path.
47
+ * @param results - Array of diff results to apply
48
+ * @protected
49
+ */
33
50
  UpdateRootMap(results) {
34
51
  for (let x = 0; x < results.length;) {
35
52
  const root = results[x].path[0];
@@ -40,6 +57,14 @@ class Store {
40
57
  this.UpdateRootObject(rootGroup[0].path[0], rootGroup);
41
58
  }
42
59
  }
60
+ /**
61
+ * Updates a specific root object with diff results.
62
+ * Creates the root object if it doesn't exist.
63
+ * @param rootPath - The path of the root object
64
+ * @param results - Array of diff results to apply to this root object
65
+ * @throws If unable to initialize root path with the given results
66
+ * @private
67
+ */
43
68
  UpdateRootObject(rootPath, results) {
44
69
  const rootObject = this.rootMap.get(rootPath);
45
70
  if (rootObject === undefined) {
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ObservableNode = exports.GET_TO_JSON = exports.GET_OBSERVABLE_VALUE = exports.IS_OBSERVABLE_NODE = void 0;
4
4
  const json_1 = require("../../Utils/json");
5
- const jsonType_1 = require("../../Utils/jsonType");
5
+ const json_2 = require("../../Utils/json");
6
6
  const observableScope_1 = require("./observableScope");
7
7
  /**
8
8
  * Symbol to identify observable nodes.
@@ -48,7 +48,7 @@ function ownKeys(value) {
48
48
  function ownKeysArray(value) {
49
49
  return Object.keys(value);
50
50
  }
51
- function UnwrapProxy(value, type = (0, jsonType_1.JsonType)(value)) {
51
+ function UnwrapProxy(value, type = (0, json_2.JsonType)(value)) {
52
52
  if (type === "value")
53
53
  return value;
54
54
  if (value[exports.IS_OBSERVABLE_NODE])
@@ -72,7 +72,7 @@ function CreateProxyFactory(alias) {
72
72
  return CreateProxyFromValue(value);
73
73
  }
74
74
  function ToJsonCopy(value) {
75
- const type = (0, jsonType_1.JsonType)(value);
75
+ const type = (0, json_2.JsonType)(value);
76
76
  switch (type) {
77
77
  case "array": {
78
78
  const typedValue = value;
@@ -195,7 +195,7 @@ function CreateProxyFactory(alias) {
195
195
  function ObjectProxySetter(object, prop, value) {
196
196
  if (readOnly)
197
197
  throw `Object is readonly`;
198
- const jsonType = (0, jsonType_1.JsonType)(value);
198
+ const jsonType = (0, json_2.JsonType)(value);
199
199
  if (jsonType === "value") {
200
200
  value !== object[prop] && SetPropertyValue(object, prop, value);
201
201
  }
@@ -242,7 +242,7 @@ function CreateProxyFactory(alias) {
242
242
  return observableScope_1.ObservableScope.Value(leafScopes[prop]);
243
243
  }
244
244
  function CreateProxyFromValue(value) {
245
- const type = (0, jsonType_1.JsonType)(value);
245
+ const type = (0, json_2.JsonType)(value);
246
246
  switch (type) {
247
247
  case "object": {
248
248
  let proxy = proxyCache.get(value) ?? CreateObjectProxy(value);
@@ -2,7 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ObservableScope = void 0;
4
4
  exports.CalcScope = CalcScope;
5
- const bitSet_1 = require("../../Utils/bitSet");
6
5
  const emitter_1 = require("../../Utils/emitter");
7
6
  const functions_1 = require("../../Utils/functions");
8
7
  /**
@@ -45,11 +44,6 @@ function CreateStaticScope(initialValue) {
45
44
  value: initialValue,
46
45
  };
47
46
  }
48
- /**
49
- * Queue of scopes pending batched update processing.
50
- * Scopes are added when their dependencies change and greedy batching is enabled.
51
- * The queue is processed in a microtask to batch multiple updates efficiently.
52
- */
53
47
  let scopeQueue = [];
54
48
  /**
55
49
  * Processes all queued scopes, recomputing dirty scopes and emitting changes.
@@ -94,78 +88,67 @@ function OnSet() {
94
88
  emitter_1.Emitter.Emit(this.emitter, this);
95
89
  }
96
90
  /**
97
- * Strategy where emitters are accessed in the same order as the previous execution.
98
- * This allows for efficient reconciliation by tracking which emitters were accessed
99
- * at the same positions in the array.
91
+ * Registers an emitter using SAME_STRATEGY.
92
+ * If the emitter is already registered at the current index, increments the index.
93
+ * Otherwise, switches to PUSH_STRATEGY and appends the emitter.
94
+ * @param state The current watch state.
95
+ * @param emitter The emitter to register.
100
96
  */
101
- const SAME_STRATEGY = 1;
97
+ function RegisterSame(state, emitter) {
98
+ if (state.emitterIndex < state.emitters.length &&
99
+ state.emitters[state.emitterIndex] === emitter) {
100
+ state.emitterIndex++;
101
+ return;
102
+ }
103
+ state.emitters = state.emitters.slice(0, state.emitterIndex);
104
+ state.strategy = PUSH_STRATEGY;
105
+ RegisterPush(state, emitter);
106
+ }
102
107
  /**
103
- * Strategy where new emitters are pushed to the array when accessed.
104
- * Used when the access pattern changes from the previous execution.
108
+ * Registers an emitter using PUSH_STRATEGY.
109
+ * Switches to DISTINCT_STRATEGY when the emitter count exceeds 50 to optimize memory.
110
+ * @param state The current watch state.
111
+ * @param emitter The emitter to register.
105
112
  */
106
- const PUSH_STRATEGY = 2;
107
- function GetBitSetFor(emitters) {
108
- const bitSet = bitSet_1.BitSetPool.Get(BIT_SET_POOL);
109
- for (let x = 0; x < emitters.length; x++)
110
- bitSet_1.BitSet.set(bitSet, emitters[x][0]);
111
- return bitSet;
113
+ function RegisterPush(state, emitter) {
114
+ if (state.emitters.length > 10) {
115
+ state.strategy = DISTINCT_STRATEGY;
116
+ state.emitterSet = new Set(state.emitters);
117
+ RegisterDistinct(state, emitter);
118
+ }
119
+ else if (!state.emitters.includes(emitter))
120
+ state.emitters.push(emitter);
112
121
  }
113
122
  /**
114
- * Registers an emitter as a dependency during a watch operation.
115
- *
116
- * This function tracks which emitters are accessed while executing a scope's getFunction.
117
- * It uses two strategies for efficiency:
118
- *
119
- * - **SAME_STRATEGY**: When emitters are accessed in the same order as the previous execution,
120
- * it tracks this via emitterIndex and skips array operations. Only switches to PUSH_STRATEGY
121
- * when the order changes.
122
- *
123
- * - **PUSH_STRATEGY**: When access order differs or is new, emitters are pushed to the array.
124
- * The BitSet prevents duplicates (same emitter accessed multiple times).
125
- *
126
- * The function does nothing if called outside a watch context (watchState is null).
127
- *
128
- * @param emitter The emitter to register as a dependency. Must have a unique ID at index 0.
123
+ * Registers an emitter using DISTINCT_STRATEGY.
124
+ * Only adds emitters that haven't been registered yet, using an ID set for O(1) lookup.
125
+ * @param state The current watch state.
126
+ * @param emitter The emitter to register.
127
+ */
128
+ function RegisterDistinct(state, emitter) {
129
+ if (!state.emitterSet.has(emitter)) {
130
+ state.emitters.push(emitter);
131
+ state.emitterSet.add(emitter);
132
+ }
133
+ }
134
+ /**
135
+ * Routes an emitter to the appropriate registration strategy based on current watch state.
136
+ * Does nothing if not within a watch context.
137
+ * @param emitter The emitter to register.
129
138
  */
130
139
  function RegisterEmitter(emitter) {
131
140
  if (watchState === null)
132
141
  return;
133
142
  switch (watchState.strategy) {
134
- case SAME_STRATEGY: {
135
- if (watchState.emitterIndex < watchState.emitters.length &&
136
- watchState.emitters[watchState.emitterIndex][0] === emitter[0]) {
137
- watchState.emitterIndex++;
138
- // BitSet.set(watchState.emitterIds, emitter[0]);
139
- }
140
- else {
141
- watchState.strategy = PUSH_STRATEGY;
142
- watchState.emitters = watchState.emitters.slice(0, watchState.emitterIndex);
143
- RegisterEmitter(emitter);
144
- }
143
+ case SAME_STRATEGY:
144
+ RegisterSame(watchState, emitter);
145
145
  break;
146
- }
147
- case PUSH_STRATEGY: {
148
- switch (watchState.emitters.length) {
149
- case 0: {
150
- watchState.emitters.push(emitter);
151
- break;
152
- }
153
- case 1: {
154
- if (watchState.emitters[0][0] !== emitter[0])
155
- watchState.emitters.push(emitter);
156
- break;
157
- }
158
- default: {
159
- if (watchState.emitters[watchState.emitters.length - 1][0] !== emitter[0]) {
160
- watchState.emitterIds ??= GetBitSetFor(watchState.emitters);
161
- if (bitSet_1.BitSet.add(watchState.emitterIds, emitter[0]))
162
- watchState.emitters.push(emitter);
163
- }
164
- break;
165
- }
166
- }
146
+ case PUSH_STRATEGY:
147
+ RegisterPush(watchState, emitter);
148
+ break;
149
+ case DISTINCT_STRATEGY:
150
+ RegisterDistinct(watchState, emitter);
167
151
  break;
168
- }
169
152
  }
170
153
  }
171
154
  /**
@@ -190,16 +173,14 @@ function GetScopeValue(scope) {
190
173
  return scope.value;
191
174
  }
192
175
  /**
193
- * Global watch state representing the current dependency tracking context.
194
- * This is set during scope execution and tracks which emitters/scopes are accessed.
195
- * Nested watch contexts are supported via the parent reference pattern.
176
+ * Strategy constants for optimizing emitter registration during watch operations.
177
+ * Each strategy represents a different approach to tracking and deduplicating dependencies.
196
178
  */
179
+ const SAME_STRATEGY = 1;
180
+ const PUSH_STRATEGY = 2;
181
+ const DISTINCT_STRATEGY = 3;
182
+ const SHRINK_STRATEGY = 4;
197
183
  let watchState = null;
198
- /**
199
- * Pool for recycling BitSet objects to reduce garbage collection overhead.
200
- * BitSets are borrowed during watch operations and returned after use.
201
- */
202
- const BIT_SET_POOL = bitSet_1.BitSetPool.Create();
203
184
  /**
204
185
  * Executes a callback while tracking all scope and emitter dependencies.
205
186
  * Creates a watch context that records what was accessed during execution.
@@ -211,16 +192,21 @@ function WatchFunction(callback, currentCalc, initialEmitters) {
211
192
  const parent = watchState;
212
193
  watchState = {
213
194
  emitterIndex: 0,
214
- strategy: initialEmitters === null ? PUSH_STRATEGY : SAME_STRATEGY,
215
195
  value: null,
216
196
  emitters: initialEmitters ?? [],
217
- emitterIds: null, // BitSetPool.Get(BIT_SET_POOL),
197
+ emitterSet: null,
218
198
  currentCalc,
219
199
  nextCalc: null,
200
+ strategy: initialEmitters === null ? PUSH_STRATEGY : SAME_STRATEGY,
220
201
  };
221
202
  watchState.value = callback();
222
203
  const resultState = watchState;
223
204
  watchState = parent;
205
+ if (resultState.strategy === SAME_STRATEGY &&
206
+ resultState.emitterIndex < resultState.emitters.length) {
207
+ resultState.emitters = resultState.emitters.slice(0, resultState.emitterIndex);
208
+ resultState.strategy = SHRINK_STRATEGY;
209
+ }
224
210
  return resultState;
225
211
  }
226
212
  /**
@@ -231,11 +217,7 @@ function WatchFunction(callback, currentCalc, initialEmitters) {
231
217
  function ExecuteScope(scope) {
232
218
  scope.dirty = false;
233
219
  const state = WatchFunction(scope.getFunction, scope.calcScopes, scope.emitters);
234
- if (state.strategy === SAME_STRATEGY &&
235
- state.emitterIndex < state.emitters.length)
236
- state.emitters = state.emitters.slice(0, state.emitterIndex);
237
220
  UpdateEmitters(scope, state);
238
- state.emitterIds && bitSet_1.BitSetPool.Return(BIT_SET_POOL, state.emitterIds);
239
221
  const calcScopes = state.currentCalc;
240
222
  scope.calcScopes = state.nextCalc;
241
223
  for (const key in calcScopes)
@@ -263,7 +245,6 @@ function ExecuteFunction(callback, greedy, allowStatic) {
263
245
  const scope = CreateDynamicScope(callback, greedy, async ? null : state.value);
264
246
  scope.calcScopes = state.nextCalc;
265
247
  UpdateEmitters(scope, state);
266
- state.emitterIds && bitSet_1.BitSetPool.Return(BIT_SET_POOL, state.emitterIds);
267
248
  if (async)
268
249
  state.value.then(function (result) {
269
250
  scope.value = result;
@@ -294,7 +275,7 @@ function CalcScope(callback, idOverride) {
294
275
  return callback();
295
276
  const nextScopes = (watchState.nextCalc ??= {});
296
277
  const id = idOverride ?? "default";
297
- if (Object.hasOwn(nextScopes, id)) {
278
+ if (nextScopes[id]) {
298
279
  RegisterScope(nextScopes[id]);
299
280
  return GetScopeValue(nextScopes[id]);
300
281
  }
@@ -306,31 +287,45 @@ function CalcScope(callback, idOverride) {
306
287
  return GetScopeValue(nextScopes[id]);
307
288
  }
308
289
  /**
309
- * Updates a scope's emitter subscriptions based on the new watch state.
310
- * Efficiently reconciles old and new emitter lists starting from emitterIndex.
311
- *
312
- * Emitters before emitterIndex are in the same position and don't need updates.
313
- * Emitters at/after emitterIndex are removed if no longer accessed or added if newly accessed.
314
- *
315
- * @param scope The scope to update emitter subscriptions for.
316
- * @param state The watch state containing the new emitter list.
290
+ * Updates a scope's dependency emitters using efficient diffing.
291
+ * Subscribes to new emitters and unsubscribes from removed ones.
292
+ * @param scope The scope to update dependencies for.
293
+ * @param right The new list of emitters to track.
294
+ * @param distinct Whether emitters are already unique (sorted and deduplicated).
317
295
  */
318
296
  function UpdateEmitters(scope, state) {
319
- const currentEmitters = scope.emitters;
320
- const nextEmitters = state.emitters;
321
- const nextEmitterIds = state.emitterIds;
322
- const sameIndex = state.emitterIndex;
323
- if (currentEmitters !== null) {
324
- for (let x = sameIndex; x < currentEmitters.length; x++) {
325
- if (nextEmitterIds === null || !bitSet_1.BitSet.remove(nextEmitterIds, currentEmitters[x][0]))
326
- emitter_1.Emitter.Remove(currentEmitters[x], scope.setCallback);
327
- }
297
+ if (scope.emitters === null) {
298
+ for (let x = 0; x < state.emitters.length; x++)
299
+ emitter_1.Emitter.On(state.emitters[x], scope.setCallback);
300
+ scope.emitters = state.emitters;
301
+ return;
328
302
  }
329
- for (let x = sameIndex; x < nextEmitters.length; x++) {
330
- if (nextEmitterIds === null || bitSet_1.BitSet.has(nextEmitterIds, nextEmitters[x][0]))
331
- emitter_1.Emitter.On(nextEmitters[x], scope.setCallback);
303
+ switch (state.strategy) {
304
+ case SHRINK_STRATEGY: {
305
+ for (let x = state.emitters.length; x < scope.emitters.length; x++)
306
+ emitter_1.Emitter.Remove(scope.emitters[x], scope.setCallback);
307
+ break;
308
+ }
309
+ case PUSH_STRATEGY: {
310
+ for (let x = state.emitterIndex; x < scope.emitters.length; x++)
311
+ if (!state.emitters.includes(scope.emitters[x], state.emitterIndex))
312
+ emitter_1.Emitter.Remove(scope.emitters[x], scope.setCallback);
313
+ for (let x = state.emitterIndex; x < state.emitters.length; x++)
314
+ if (!scope.emitters.includes(state.emitters[x], state.emitterIndex))
315
+ emitter_1.Emitter.On(state.emitters[x], scope.setCallback);
316
+ break;
317
+ }
318
+ case DISTINCT_STRATEGY: {
319
+ for (let x = state.emitterIndex; x < scope.emitters.length; x++)
320
+ if (!state.emitterSet.delete(scope.emitters[x]))
321
+ emitter_1.Emitter.Remove(scope.emitters[x], scope.setCallback);
322
+ for (let x = state.emitterIndex; x < state.emitters.length; x++)
323
+ if (state.emitterSet.has(state.emitters[x]))
324
+ emitter_1.Emitter.On(state.emitters[x], scope.setCallback);
325
+ break;
326
+ }
332
327
  }
333
- scope.emitters = nextEmitters;
328
+ scope.emitters = state.emitters;
334
329
  }
335
330
  /**
336
331
  * Destroys multiple scopes, cleaning up their resources.
@@ -348,7 +343,7 @@ function DestroyAllScopes(scopes) {
348
343
  function DestroyScope(scope) {
349
344
  if (!scope || scope.type === "static")
350
345
  return;
351
- emitter_1.Emitter.Destroy(scope.emitter);
346
+ // Emitter.Destroy(scope.emitter);
352
347
  for (const key in scope.calcScopes)
353
348
  DestroyScope(scope.calcScopes[key]);
354
349
  scope.calcScopes = null;
@@ -362,7 +357,6 @@ function DestroyScope(scope) {
362
357
  scope.setCallback = null;
363
358
  scope.destroyed = true;
364
359
  scope.onDestroyed && emitter_1.Emitter.Emit(scope.onDestroyed, scope);
365
- scope.onDestroyed && emitter_1.Emitter.Destroy(scope.onDestroyed);
366
360
  }
367
361
  var ObservableScope;
368
362
  (function (ObservableScope) {
@@ -1,8 +1,28 @@
1
+ /**
2
+ * A queue that executes async callbacks sequentially, one at a time.
3
+ */
1
4
  export declare class AsyncQueue {
2
5
  private running;
3
6
  private queue;
7
+ /**
8
+ * Adds a callback to the queue and returns a promise that resolves when it executes.
9
+ * @template T - The type the callback promise resolves to
10
+ * @param callback - Async function to queue
11
+ * @returns Promise that resolves with the callback's result when executed
12
+ */
4
13
  Next<T>(callback: () => Promise<T>): Promise<T>;
14
+ /**
15
+ * Clears the queue and stops execution.
16
+ */
5
17
  Stop(): void;
18
+ /**
19
+ * Starts queue execution if not already running.
20
+ * @private
21
+ */
6
22
  private Start;
23
+ /**
24
+ * Executes the next callback in the queue recursively until empty.
25
+ * @private
26
+ */
7
27
  private ExecuteQueue;
8
28
  }
@@ -2,11 +2,20 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AsyncQueue = void 0;
4
4
  const list_1 = require("./list");
5
+ /**
6
+ * A queue that executes async callbacks sequentially, one at a time.
7
+ */
5
8
  class AsyncQueue {
6
9
  constructor() {
7
10
  this.running = false;
8
11
  this.queue = list_1.List.Create();
9
12
  }
13
+ /**
14
+ * Adds a callback to the queue and returns a promise that resolves when it executes.
15
+ * @template T - The type the callback promise resolves to
16
+ * @param callback - Async function to queue
17
+ * @returns Promise that resolves with the callback's result when executed
18
+ */
10
19
  Next(callback) {
11
20
  const ret = new Promise((resolve, reject) => {
12
21
  list_1.List.Add(this.queue, async function () {
@@ -22,15 +31,26 @@ class AsyncQueue {
22
31
  this.Start();
23
32
  return ret;
24
33
  }
34
+ /**
35
+ * Clears the queue and stops execution.
36
+ */
25
37
  Stop() {
26
38
  list_1.List.Clear(this.queue);
27
39
  }
40
+ /**
41
+ * Starts queue execution if not already running.
42
+ * @private
43
+ */
28
44
  Start() {
29
45
  if (this.running)
30
46
  return;
31
47
  this.running = true;
32
48
  this.ExecuteQueue();
33
49
  }
50
+ /**
51
+ * Executes the next callback in the queue recursively until empty.
52
+ * @private
53
+ */
34
54
  async ExecuteQueue() {
35
55
  const callback = list_1.List.Pop(this.queue);
36
56
  if (callback !== undefined) {