@esportsplus/reactivity 0.15.0 → 0.16.0

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.
@@ -3,20 +3,24 @@ import { onCleanup, root } from '../system.js';
3
3
  import array from './array.js';
4
4
  import object from './object.js';
5
5
  export default (input) => {
6
- let value;
7
- return root(() => {
6
+ let dispose = false, value = root(() => {
7
+ let response;
8
8
  if (isArray(input)) {
9
- value = array(input);
9
+ response = array(input);
10
10
  }
11
11
  else if (isObject(input)) {
12
- value = object(input);
12
+ response = object(input);
13
13
  }
14
- if (value) {
14
+ if (response) {
15
15
  if (root.disposables) {
16
- onCleanup(() => value.dispose());
16
+ dispose = true;
17
17
  }
18
- return value;
18
+ return response;
19
19
  }
20
20
  throw new Error(`@esportsplus/reactivity: 'reactive' received invalid input - ${JSON.stringify(input)}`);
21
21
  });
22
+ if (dispose) {
23
+ onCleanup(() => value.dispose());
24
+ }
25
+ return value;
22
26
  };
package/build/system.d.ts CHANGED
@@ -7,7 +7,7 @@ declare const isSignal: (value: unknown) => value is Signal<unknown>;
7
7
  declare const onCleanup: (fn: VoidFunction) => typeof fn;
8
8
  declare const read: <T>(node: Signal<T> | Computed<T>) => T;
9
9
  declare const root: {
10
- <T>(fn: () => T): T;
10
+ <T>(fn: (dispose?: VoidFunction) => T): T;
11
11
  disposables: number;
12
12
  };
13
13
  declare const set: <T>(signal: Signal<T>, value: T) => void;
package/build/system.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { isArray, isObject } from '@esportsplus/utilities';
2
2
  import { COMPUTED, SIGNAL, STABILIZER_IDLE, STABILIZER_RESCHEDULE, STABILIZER_RUNNING, STABILIZER_SCHEDULED, STATE_CHECK, STATE_DIRTY, STATE_IN_HEAP, STATE_NONE, STATE_NOTIFY_MASK, STATE_RECOMPUTING } from './constants.js';
3
- let depth = 0, heap = new Array(64), heap_i = 0, heap_n = 0, microtask = queueMicrotask, notified = false, observer = null, stabilizer = STABILIZER_IDLE, version = 0;
3
+ let depth = 0, heap = new Array(64), heap_i = 0, heap_n = 0, microtask = queueMicrotask, notified = false, observer = null, scope = null, stabilizer = STABILIZER_IDLE, version = 0;
4
4
  function cleanup(computed) {
5
5
  if (!computed.cleanup) {
6
6
  return;
@@ -262,6 +262,9 @@ const computed = (fn) => {
262
262
  else {
263
263
  recompute(self, false);
264
264
  root.disposables++;
265
+ if (scope) {
266
+ onCleanup(() => dispose(self));
267
+ }
265
268
  }
266
269
  return self;
267
270
  };
@@ -289,18 +292,19 @@ const isSignal = (value) => {
289
292
  return isObject(value) && SIGNAL in value;
290
293
  };
291
294
  const onCleanup = (fn) => {
292
- if (!observer) {
295
+ let parent = observer || scope;
296
+ if (!parent) {
293
297
  return fn;
294
298
  }
295
- let cleanup = observer.cleanup;
299
+ let cleanup = parent.cleanup;
296
300
  if (!cleanup) {
297
- observer.cleanup = fn;
301
+ parent.cleanup = fn;
298
302
  }
299
303
  else if (isArray(cleanup)) {
300
304
  cleanup.push(fn);
301
305
  }
302
306
  else {
303
- observer.cleanup = [cleanup, fn];
307
+ parent.cleanup = [cleanup, fn];
304
308
  }
305
309
  return fn;
306
310
  };
@@ -328,12 +332,14 @@ const read = (node) => {
328
332
  return node.value;
329
333
  };
330
334
  const root = (fn) => {
331
- let d = root.disposables, o = observer;
335
+ let d = root.disposables, o = observer, s = scope, self = null, tracking = fn.length;
332
336
  observer = null;
333
337
  root.disposables = 0;
334
- let value = fn();
338
+ scope = tracking ? (self = { cleanup: null }) : null;
339
+ let value = fn(tracking ? () => dispose(self) : undefined);
335
340
  observer = o;
336
341
  root.disposables = d;
342
+ scope = s;
337
343
  return value;
338
344
  };
339
345
  root.disposables = 0;
package/package.json CHANGED
@@ -12,7 +12,7 @@
12
12
  "private": false,
13
13
  "type": "module",
14
14
  "types": "build/index.d.ts",
15
- "version": "0.15.0",
15
+ "version": "0.16.0",
16
16
  "scripts": {
17
17
  "build": "tsc && tsc-alias",
18
18
  "-": "-"
@@ -20,24 +20,31 @@ type Input<T> =
20
20
 
21
21
 
22
22
  export default <T>(input: Input<T>): API<T> => {
23
- let value: API<T> | undefined;
24
-
25
- return root(() => {
26
- if (isArray(input)) {
27
- value = array(input) as API<T>;
28
- }
29
- else if (isObject(input)) {
30
- value = object(input) as API<T>;
31
- }
32
-
33
- if (value) {
34
- if (root.disposables) {
35
- onCleanup(() => value!.dispose());
23
+ let dispose = false,
24
+ value = root(() => {
25
+ let response: API<T> | undefined;
26
+
27
+ if (isArray(input)) {
28
+ response = array(input) as API<T>;
29
+ }
30
+ else if (isObject(input)) {
31
+ response = object(input) as API<T>;
32
+ }
33
+
34
+ if (response) {
35
+ if (root.disposables) {
36
+ dispose = true;
37
+ }
38
+
39
+ return response;
36
40
  }
37
41
 
38
- return value;
39
- }
42
+ throw new Error(`@esportsplus/reactivity: 'reactive' received invalid input - ${JSON.stringify(input)}`);
43
+ });
44
+
45
+ if (dispose) {
46
+ onCleanup(() => value.dispose());
47
+ }
40
48
 
41
- throw new Error(`@esportsplus/reactivity: 'reactive' received invalid input - ${JSON.stringify(input)}`);
42
- });
49
+ return value;
43
50
  };
package/src/system.ts CHANGED
@@ -14,6 +14,7 @@ let depth = 0,
14
14
  microtask = queueMicrotask,
15
15
  notified = false,
16
16
  observer: Computed<unknown> | null = null,
17
+ scope: Computed<unknown> | null = null,
17
18
  stabilizer = STABILIZER_IDLE,
18
19
  version = 0;
19
20
 
@@ -370,6 +371,10 @@ const computed = <T>(fn: Computed<T>['fn']): Computed<T> => {
370
371
  else {
371
372
  recompute(self, false);
372
373
  root.disposables++;
374
+
375
+ if (scope) {
376
+ onCleanup(() => dispose(self));
377
+ }
373
378
  }
374
379
 
375
380
  return self;
@@ -408,20 +413,22 @@ const isSignal = (value: unknown): value is Signal<unknown> => {
408
413
  };
409
414
 
410
415
  const onCleanup = (fn: VoidFunction): typeof fn => {
411
- if (!observer) {
416
+ let parent = observer || scope;
417
+
418
+ if (!parent) {
412
419
  return fn;
413
420
  }
414
421
 
415
- let cleanup = observer.cleanup;
422
+ let cleanup = parent.cleanup;
416
423
 
417
424
  if (!cleanup) {
418
- observer.cleanup = fn;
425
+ parent.cleanup = fn;
419
426
  }
420
427
  else if (isArray(cleanup)) {
421
428
  cleanup.push(fn);
422
429
  }
423
430
  else {
424
- observer.cleanup = [cleanup, fn];
431
+ parent.cleanup = [cleanup, fn];
425
432
  }
426
433
 
427
434
  return fn;
@@ -457,17 +464,22 @@ const read = <T>(node: Signal<T> | Computed<T>): T => {
457
464
  return node.value;
458
465
  };
459
466
 
460
- const root = <T>(fn: () => T) => {
467
+ const root = <T>(fn: (dispose?: VoidFunction) => T) => {
461
468
  let d = root.disposables,
462
- o = observer;
469
+ o = observer,
470
+ s = scope,
471
+ self: Computed<unknown> | null = null,
472
+ tracking = fn.length;
463
473
 
464
474
  observer = null;
465
475
  root.disposables = 0;
476
+ scope = tracking ? (self = { cleanup: null } as Computed<unknown>) : null;
466
477
 
467
- let value = fn();
478
+ let value = fn( tracking ? () => dispose(self!) : undefined);
468
479
 
469
480
  observer = o;
470
481
  root.disposables = d;
482
+ scope = s;
471
483
 
472
484
  return value;
473
485
  };