@esportsplus/reactivity 0.15.0 → 0.16.1

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,23 @@ const read = (node) => {
328
332
  return node.value;
329
333
  };
330
334
  const root = (fn) => {
331
- let d = root.disposables, o = observer;
335
+ let c, d = root.disposables, o = observer, s = scope, self = null, tracking = fn.length, value;
332
336
  observer = null;
333
337
  root.disposables = 0;
334
- let value = fn();
338
+ if (tracking) {
339
+ scope = self = { cleanup: null };
340
+ value = fn(c = () => dispose(self));
341
+ }
342
+ else {
343
+ scope = null;
344
+ value = fn();
345
+ }
335
346
  observer = o;
336
347
  root.disposables = d;
348
+ scope = s;
349
+ if (c) {
350
+ onCleanup(c);
351
+ }
337
352
  return value;
338
353
  };
339
354
  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.1",
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,34 @@ const read = <T>(node: Signal<T> | Computed<T>): T => {
457
464
  return node.value;
458
465
  };
459
466
 
460
- const root = <T>(fn: () => T) => {
461
- let d = root.disposables,
462
- o = observer;
467
+ const root = <T>(fn: (dispose?: VoidFunction) => T) => {
468
+ let c,
469
+ d = root.disposables,
470
+ o = observer,
471
+ s = scope,
472
+ self: Computed<unknown> | null = null,
473
+ tracking = fn.length,
474
+ value: T;
463
475
 
464
476
  observer = null;
465
477
  root.disposables = 0;
466
478
 
467
- let value = fn();
479
+ if (tracking) {
480
+ scope = self = { cleanup: null } as Computed<unknown>;
481
+ value = fn( c = () => dispose(self!) );
482
+ }
483
+ else {
484
+ scope = null;
485
+ value = fn();
486
+ }
468
487
 
469
488
  observer = o;
470
489
  root.disposables = d;
490
+ scope = s;
491
+
492
+ if (c) {
493
+ onCleanup(c);
494
+ }
471
495
 
472
496
  return value;
473
497
  };