async-reactivity 2.0.16 → 2.0.18

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.
@@ -0,0 +1,22 @@
1
+ import Listener from "./listener.js";
2
+ export default class AsyncListener extends Listener {
3
+ promiseResolve;
4
+ constructor(start, stop) {
5
+ let promiseResolve;
6
+ super(new Promise(resolve => {
7
+ promiseResolve = resolve;
8
+ }), start, stop);
9
+ this.promiseResolve = promiseResolve;
10
+ }
11
+ set value(_value) {
12
+ if (this.promiseResolve) {
13
+ _value.then(this.promiseResolve);
14
+ this.promiseResolve = undefined;
15
+ this._value = _value; // prevent invalidate
16
+ }
17
+ super.value = _value;
18
+ }
19
+ get value() {
20
+ return super.value;
21
+ }
22
+ }
package/lib/index.js CHANGED
@@ -2,4 +2,5 @@ export { default as Computed } from './computed.js';
2
2
  export { default as Ref } from './ref.js';
3
3
  export { default as Watcher } from './watcher.js';
4
4
  export { default as Listener } from './listener.js';
5
+ export { default as AsyncListener } from './asyncListener.js';
5
6
  export { default as defaultIsEqual } from './defaultIsEqual.js';
package/lib/listener.js CHANGED
@@ -18,9 +18,11 @@ export default class Listener extends Ref {
18
18
  }
19
19
  removeDependent(dependent) {
20
20
  super.removeDependent(dependent);
21
- if (this.dependents.size === 0) {
22
- this.listening = false;
23
- this.stop();
24
- }
21
+ Promise.resolve().then(() => {
22
+ if (this.dependents.size === 0) {
23
+ this.listening = false;
24
+ this.stop();
25
+ }
26
+ });
25
27
  }
26
28
  }
@@ -1,7 +1,7 @@
1
1
  import 'mocha';
2
2
  import assert from 'assert';
3
3
  import { mock } from 'node:test';
4
- import { Watcher, Listener } from './index.js';
4
+ import { Watcher, Listener, Computed, Ref } from './index.js';
5
5
  describe('listener', function () {
6
6
  it('wait for dependent', function () {
7
7
  assert.doesNotThrow(() => {
@@ -62,4 +62,17 @@ describe('listener', function () {
62
62
  await new Promise((resolve) => setTimeout(resolve, 15));
63
63
  assert.strictEqual(onChange.mock.callCount(), 3);
64
64
  });
65
+ it('keep listening when recomputing', async function () {
66
+ let gate = 0;
67
+ const listener = new Listener(1, () => {
68
+ gate++;
69
+ }, () => { });
70
+ const a = new Ref(5);
71
+ const b = new Computed(value => value(a) + value(listener));
72
+ b.value;
73
+ assert.strictEqual(gate, 1);
74
+ a.value = 6;
75
+ b.value;
76
+ assert.strictEqual(gate, 1);
77
+ });
65
78
  });
@@ -0,0 +1,22 @@
1
+ import Listener from "./listener.js";
2
+ export default class AsyncListener extends Listener {
3
+ promiseResolve;
4
+ constructor(start, stop) {
5
+ let promiseResolve;
6
+ super(new Promise(resolve => {
7
+ promiseResolve = resolve;
8
+ }), start, stop);
9
+ this.promiseResolve = promiseResolve;
10
+ }
11
+ set value(_value) {
12
+ if (this.promiseResolve) {
13
+ _value.then(this.promiseResolve);
14
+ this.promiseResolve = undefined;
15
+ this._value = _value; // prevent invalidate
16
+ }
17
+ super.value = _value;
18
+ }
19
+ get value() {
20
+ return super.value;
21
+ }
22
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "async-reactivity",
3
- "version": "2.0.16",
3
+ "version": "2.0.18",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "types": "types/index.d.ts",
@@ -23,8 +23,8 @@
23
23
  "license": "ISC",
24
24
  "devDependencies": {
25
25
  "@types/mocha": "^10.0.8",
26
- "@types/node": "^20.14.15",
26
+ "@types/node": "^22.13.11",
27
27
  "mocha": "^10.7.3",
28
- "typescript": "^5.6.2"
28
+ "typescript": "^5.8.2"
29
29
  }
30
30
  }
@@ -0,0 +1,26 @@
1
+ import Listener from "./listener.js";
2
+
3
+ export default class AsyncListener<T> extends Listener<Promise<T>> {
4
+ private promiseResolve?: (value: T) => void;
5
+
6
+ constructor(start: () => void, stop: () => void) {
7
+ let promiseResolve;
8
+ super(new Promise<T>(resolve => {
9
+ promiseResolve = resolve;
10
+ }), start, stop);
11
+ this.promiseResolve = promiseResolve;
12
+ }
13
+
14
+ public set value(_value: Promise<T>) {
15
+ if (this.promiseResolve) {
16
+ _value.then(this.promiseResolve);
17
+ this.promiseResolve = undefined;
18
+ this._value = _value; // prevent invalidate
19
+ }
20
+ super.value = _value;
21
+ }
22
+
23
+ public get value(): Promise<T> {
24
+ return super.value!;
25
+ }
26
+ }
package/src/index.ts CHANGED
@@ -4,4 +4,5 @@ export { default as Watcher } from './watcher.js';
4
4
  export { default as Dependency } from './dependency.js';
5
5
  export { default as Dependent } from './dependent.js';
6
6
  export { default as Listener } from './listener.js';
7
+ export { default as AsyncListener } from './asyncListener.js';
7
8
  export { default as defaultIsEqual } from './defaultIsEqual.js';
@@ -1,7 +1,7 @@
1
1
  import 'mocha';
2
2
  import assert from 'assert';
3
3
  import { mock } from 'node:test';
4
- import { Watcher, Listener } from './index.js';
4
+ import { Watcher, Listener, Computed, Ref } from './index.js';
5
5
 
6
6
  describe('listener', function () {
7
7
  it('wait for dependent', function () {
@@ -98,4 +98,26 @@ describe('listener', function () {
98
98
 
99
99
  assert.strictEqual(onChange.mock.callCount(), 3);
100
100
  });
101
+
102
+ it('keep listening when recomputing', async function() {
103
+ let gate = 0;
104
+ const listener = new Listener(
105
+ 1,
106
+ () => {
107
+ gate++;
108
+ },
109
+ () => {}
110
+ );
111
+
112
+ const a = new Ref(5);
113
+
114
+ const b = new Computed(value => value(a) + value(listener));
115
+
116
+ b.value;
117
+ assert.strictEqual(gate, 1);
118
+
119
+ a.value = 6;
120
+ b.value;
121
+ assert.strictEqual(gate, 1);
122
+ });
101
123
  });
package/src/listener.ts CHANGED
@@ -24,9 +24,11 @@ export default class Listener<T extends TBase, TBase = T> extends Ref<T> {
24
24
 
25
25
  public removeDependent(dependent: Dependent): void {
26
26
  super.removeDependent(dependent);
27
- if (this.dependents.size === 0) {
28
- this.listening = false;
29
- this.stop();
30
- }
27
+ Promise.resolve().then(() => {
28
+ if (this.dependents.size === 0) {
29
+ this.listening = false;
30
+ this.stop();
31
+ }
32
+ })
31
33
  }
32
34
  }
@@ -0,0 +1,8 @@
1
+ import Listener from "./listener.js";
2
+ export default class AsyncListener<T> extends Listener<Promise<T>> {
3
+ private promiseResolve?;
4
+ constructor(start: () => void, stop: () => void);
5
+ set value(_value: Promise<T>);
6
+ get value(): Promise<T>;
7
+ }
8
+ //# sourceMappingURL=asyncListener.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asyncListener.d.ts","sourceRoot":"","sources":["../src/asyncListener.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,eAAe,CAAC;AAErC,MAAM,CAAC,OAAO,OAAO,aAAa,CAAC,CAAC,CAAE,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAC9D,OAAO,CAAC,cAAc,CAAC,CAAqB;gBAEhC,KAAK,EAAE,MAAM,IAAI,EAAE,IAAI,EAAE,MAAM,IAAI;IAQ/C,IAAW,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAOlC;IAED,IAAW,KAAK,IAAI,OAAO,CAAC,CAAC,CAAC,CAE7B;CACJ"}
package/types/index.d.ts CHANGED
@@ -4,5 +4,6 @@ export { default as Watcher } from './watcher.js';
4
4
  export { default as Dependency } from './dependency.js';
5
5
  export { default as Dependent } from './dependent.js';
6
6
  export { default as Listener } from './listener.js';
7
+ export { default as AsyncListener } from './asyncListener.js';
7
8
  export { default as defaultIsEqual } from './defaultIsEqual.js';
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,WAAW,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChG,OAAO,EAAE,OAAO,IAAI,GAAG,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,WAAW,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChG,OAAO,EAAE,OAAO,IAAI,GAAG,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,qBAAqB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"listener.d.ts","sourceRoot":"","sources":["../src/listener.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,GAAG,MAAM,UAAU,CAAC;AAG3B,MAAM,CAAC,OAAO,OAAO,QAAQ,CAAC,CAAC,SAAS,KAAK,EAAE,KAAK,GAAG,CAAC,CAAE,SAAQ,GAAG,CAAC,CAAC,CAAC;IACpE,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,SAAS,CAAS;gBAEd,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,IAAI,EAAE,IAAI,EAAE,MAAM,IAAI,EAAE,OAAO,oCAAwB;IAOpF,YAAY,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAQxC,eAAe,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;CAOrD"}
1
+ {"version":3,"file":"listener.d.ts","sourceRoot":"","sources":["../src/listener.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,GAAG,MAAM,UAAU,CAAC;AAG3B,MAAM,CAAC,OAAO,OAAO,QAAQ,CAAC,CAAC,SAAS,KAAK,EAAE,KAAK,GAAG,CAAC,CAAE,SAAQ,GAAG,CAAC,CAAC,CAAC;IACpE,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,SAAS,CAAS;gBAEd,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,IAAI,EAAE,IAAI,EAAE,MAAM,IAAI,EAAE,OAAO,oCAAwB;IAOpF,YAAY,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAQxC,eAAe,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;CASrD"}
@@ -0,0 +1,8 @@
1
+ import Listener from "./listener.js";
2
+ export default class AsyncListener<T> extends Listener<Promise<T>> {
3
+ private promiseResolve?;
4
+ constructor(start: () => void, stop: () => void);
5
+ set value(_value: Promise<T>);
6
+ get value(): Promise<T>;
7
+ }
8
+ //# sourceMappingURL=syncListener.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syncListener.d.ts","sourceRoot":"","sources":["../src/syncListener.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,eAAe,CAAC;AAErC,MAAM,CAAC,OAAO,OAAO,aAAa,CAAC,CAAC,CAAE,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAC9D,OAAO,CAAC,cAAc,CAAC,CAAqB;gBAEhC,KAAK,EAAE,MAAM,IAAI,EAAE,IAAI,EAAE,MAAM,IAAI;IAQ/C,IAAW,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAOlC;IAED,IAAW,KAAK,IAAI,OAAO,CAAC,CAAC,CAAC,CAE7B;CACJ"}