@esmj/signals 0.0.2 → 0.0.4

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/dist/index.d.mts CHANGED
@@ -25,11 +25,18 @@ class Watcher extends Observable {
25
25
 
26
26
  this.pipe((observable) => {
27
27
  const originalSubscribe = observable.subscribe.bind(observable);
28
+ const originalUnsubscribe = observable.unsubscribe.bind(observable);
29
+
28
30
  observable.subscribe = (observer) => {
29
31
  originalSubscribe(observer);
30
32
  this.#pendings.add(observer);
31
33
  };
32
34
 
35
+ observable.unsubscribe = (observer) => {
36
+ originalUnsubscribe(observer);
37
+ this.#pendings.delete(observer);
38
+ };
39
+
33
40
  return observable;
34
41
  });
35
42
  }
@@ -38,6 +45,8 @@ class Watcher extends Observable {
38
45
  if (typeof signal.next !== 'function') {
39
46
  signal.next = () => {
40
47
  return untrack(() => {
48
+ this.#pendings.add(signal);
49
+
41
50
  this.#notify();
42
51
  });
43
52
  };
@@ -52,6 +61,8 @@ class Watcher extends Observable {
52
61
  const originalNext = signal.next.bind(signal);
53
62
  signal.next = () => {
54
63
  return untrack(() => {
64
+ this.#pendings.add(signal);
65
+
55
66
  originalNext();
56
67
 
57
68
  this.#notify();
@@ -64,7 +75,20 @@ class Watcher extends Observable {
64
75
  }
65
76
 
66
77
  getPending() {
67
- return Array.from(this.#pendings);
78
+ const pendings = Array.from(this.#pendings).map((pending) => {
79
+ const originalGet = pending.get.bind(pending);
80
+
81
+ pending.get = () => {
82
+ return untrack(() => {
83
+ this.#pendings.delete(pending);
84
+ return originalGet();
85
+ });
86
+ };
87
+
88
+ return pending;
89
+ });
90
+
91
+ return pendings;
68
92
  }
69
93
 
70
94
  unwatch(signal) {
@@ -79,14 +103,14 @@ let w = null;
79
103
  function createWatcher(notify) {
80
104
  w = new Watcher(notify);
81
105
  }
82
-
106
+ let timer = null;
83
107
  createWatcher(() => {
84
108
  // TODO performance improvement
85
- setTimeout(() => {
109
+
110
+ clearTimeout(timer);
111
+ timer = setTimeout(() => {
86
112
  getPending().forEach((pending) => {
87
- untrack(() => {
88
- pending.get();
89
- });
113
+ pending.get();
90
114
  });
91
115
  }, 0);
92
116
  });
@@ -117,6 +141,8 @@ class Computed extends Observer {
117
141
  this.#callback = callback;
118
142
  this.#options = options;
119
143
 
144
+ this.debug = options?.debug;
145
+
120
146
  this.get = this.get.bind(this);
121
147
  }
122
148
 
@@ -208,7 +234,7 @@ function computed(callback, options) {
208
234
  return instance;
209
235
  }
210
236
 
211
- function effect(callback) {
237
+ function effect(callback, options) {
212
238
  let destructor;
213
239
 
214
240
  let c = computed(
@@ -216,7 +242,7 @@ function effect(callback) {
216
242
  destructor?.();
217
243
  destructor = callback();
218
244
  },
219
- { equals: () => false },
245
+ { equals: () => false, debug: 'effect', ...options },
220
246
  );
221
247
  c.get();
222
248
 
package/dist/index.d.ts CHANGED
@@ -25,11 +25,18 @@ class Watcher extends Observable {
25
25
 
26
26
  this.pipe((observable) => {
27
27
  const originalSubscribe = observable.subscribe.bind(observable);
28
+ const originalUnsubscribe = observable.unsubscribe.bind(observable);
29
+
28
30
  observable.subscribe = (observer) => {
29
31
  originalSubscribe(observer);
30
32
  this.#pendings.add(observer);
31
33
  };
32
34
 
35
+ observable.unsubscribe = (observer) => {
36
+ originalUnsubscribe(observer);
37
+ this.#pendings.delete(observer);
38
+ };
39
+
33
40
  return observable;
34
41
  });
35
42
  }
@@ -38,6 +45,8 @@ class Watcher extends Observable {
38
45
  if (typeof signal.next !== 'function') {
39
46
  signal.next = () => {
40
47
  return untrack(() => {
48
+ this.#pendings.add(signal);
49
+
41
50
  this.#notify();
42
51
  });
43
52
  };
@@ -52,6 +61,8 @@ class Watcher extends Observable {
52
61
  const originalNext = signal.next.bind(signal);
53
62
  signal.next = () => {
54
63
  return untrack(() => {
64
+ this.#pendings.add(signal);
65
+
55
66
  originalNext();
56
67
 
57
68
  this.#notify();
@@ -64,7 +75,20 @@ class Watcher extends Observable {
64
75
  }
65
76
 
66
77
  getPending() {
67
- return Array.from(this.#pendings);
78
+ const pendings = Array.from(this.#pendings).map((pending) => {
79
+ const originalGet = pending.get.bind(pending);
80
+
81
+ pending.get = () => {
82
+ return untrack(() => {
83
+ this.#pendings.delete(pending);
84
+ return originalGet();
85
+ });
86
+ };
87
+
88
+ return pending;
89
+ });
90
+
91
+ return pendings;
68
92
  }
69
93
 
70
94
  unwatch(signal) {
@@ -79,14 +103,14 @@ let w = null;
79
103
  function createWatcher(notify) {
80
104
  w = new Watcher(notify);
81
105
  }
82
-
106
+ let timer = null;
83
107
  createWatcher(() => {
84
108
  // TODO performance improvement
85
- setTimeout(() => {
109
+
110
+ clearTimeout(timer);
111
+ timer = setTimeout(() => {
86
112
  getPending().forEach((pending) => {
87
- untrack(() => {
88
- pending.get();
89
- });
113
+ pending.get();
90
114
  });
91
115
  }, 0);
92
116
  });
@@ -117,6 +141,8 @@ class Computed extends Observer {
117
141
  this.#callback = callback;
118
142
  this.#options = options;
119
143
 
144
+ this.debug = options?.debug;
145
+
120
146
  this.get = this.get.bind(this);
121
147
  }
122
148
 
@@ -208,7 +234,7 @@ function computed(callback, options) {
208
234
  return instance;
209
235
  }
210
236
 
211
- function effect(callback) {
237
+ function effect(callback, options) {
212
238
  let destructor;
213
239
 
214
240
  let c = computed(
@@ -216,7 +242,7 @@ function effect(callback) {
216
242
  destructor?.();
217
243
  destructor = callback();
218
244
  },
219
- { equals: () => false },
245
+ { equals: () => false, debug: 'effect', ...options },
220
246
  );
221
247
  c.get();
222
248
 
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- 'use strict';var observable=require('@esmj/observable');var r=null;function h(n){let t=r;r=null;let e=n();return r=t,e}var x=Symbol("internal observable"),c=Symbol("original next"),f=class extends observable.Observable{#t=new Set;#e=null;constructor(t){super(),this.#e=t,this.pipe(e=>{let s=e.subscribe.bind(e);return e.subscribe=i=>{s(i),this.#t.add(i);},e});}watch(t){if(typeof t.next!="function"&&(t.next=()=>h(()=>{this.#e();}),t.next[c]=void 0),t instanceof o&&t.next[c]===void 0){let e=t.next.bind(t);t.next=()=>h(()=>{e(),this.#e();}),t.next[c]=e;}return this.subscribe(t)}getPending(){return Array.from(this.#t)}unwatch(t){return t.next=t.next[c],this.unsubscribe(t)}},u=null;function w(n){u=new f(n);}w(()=>{setTimeout(()=>{y().forEach(n=>{h(()=>{n.get();});});},0);});function y(){return u.getPending()}function g(n){return u.watch(n)}function m(n){return u.unwatch(n)}var o=class extends observable.Observer{#t=!0;#e=null;#n=null;#r=this.#u();#s=null;#i=null;constructor(t,e){super(),this.#s=t,this.#i=e,this.get=this.get.bind(this);}#o(){Array.from(this.#r.dependencies.values()).forEach(({unsubscribe:t})=>{t();}),this.#r.dependencies.clear();}#u(){return {dependencies:new Map,observer:this}}#h(){this.#e=r,r=this.#r;}#f(){r=this.#e;}next(){this.#t=!0,this.#n[x].next();}get(){return this.#n||(this.#n=d(this.#c(),this.#i)),this.#t&&this.#c(),this.#n.get()}#c(){this.#t=!1,this.#o(),this.#h();let t;try{t=this.#s();}catch(e){t=e;}if(this.#f(),t instanceof Promise&&(t=t.then(e=>e).catch(e=>{throw e})),this.#n&&this.#n.set(t),t instanceof Error)throw t;return t}};function E(n,t){return new o(n,t)}function P(n){let t,e=E(()=>{t?.(),t=n();},{equals:()=>!1});return e.get(),g(e),()=>{t?.(),m(e);}}function d(n,t={}){let e=t?.equals??Object.is,s=new observable.Observable;function i(){if(typeof r=="object"&&r!==null&&r.dependencies.set(s,s.subscribe(r.observer)),n instanceof Error)throw n;return n}function b(l){return e(n,l)||(n=l,s.next()),n}return {get:i,set:b,[x]:s}}var S=d;exports.computed=E;exports.createSignal=d;exports.createWatcher=w;exports.effect=P;exports.getPending=y;exports.state=S;exports.untrack=h;exports.unwatch=m;exports.watch=g;
1
+ 'use strict';var observable=require('@esmj/observable');var i=null;function f(n){let t=i;i=null;let e=n();return i=t,e}var b=Symbol("internal observable"),c=Symbol("original next"),d=class extends observable.Observable{#t=new Set;#e=null;constructor(t){super(),this.#e=t,this.pipe(e=>{let r=e.subscribe.bind(e),h=e.unsubscribe.bind(e);return e.subscribe=s=>{r(s),this.#t.add(s);},e.unsubscribe=s=>{h(s),this.#t.delete(s);},e});}watch(t){if(typeof t.next!="function"&&(t.next=()=>f(()=>{this.#t.add(t),this.#e();}),t.next[c]=void 0),t instanceof u&&t.next[c]===void 0){let e=t.next.bind(t);t.next=()=>f(()=>{this.#t.add(t),e(),this.#e();}),t.next[c]=e;}return this.subscribe(t)}getPending(){return Array.from(this.#t).map(e=>{let r=e.get.bind(e);return e.get=()=>f(()=>(this.#t.delete(e),r())),e})}unwatch(t){return t.next=t.next[c],this.unsubscribe(t)}},o=null;function g(n){o=new d(n);}var a=null;g(()=>{clearTimeout(a),a=setTimeout(()=>{m().forEach(n=>{n.get();});},0);});function m(){return o.getPending()}function y(n){return o.watch(n)}function E(n){return o.unwatch(n)}var u=class extends observable.Observer{#t=!0;#e=null;#n=null;#r=this.#o();#i=null;#s=null;constructor(t,e){super(),this.#i=t,this.#s=e,this.debug=e?.debug,this.get=this.get.bind(this);}#u(){Array.from(this.#r.dependencies.values()).forEach(({unsubscribe:t})=>{t();}),this.#r.dependencies.clear();}#o(){return {dependencies:new Map,observer:this}}#h(){this.#e=i,i=this.#r;}#f(){i=this.#e;}next(){this.#t=!0,this.#n[b].next();}get(){return this.#n||(this.#n=p(this.#c(),this.#s)),this.#t&&this.#c(),this.#n.get()}#c(){this.#t=!1,this.#u(),this.#h();let t;try{t=this.#i();}catch(e){t=e;}if(this.#f(),t instanceof Promise&&(t=t.then(e=>e).catch(e=>{throw e})),this.#n&&this.#n.set(t),t instanceof Error)throw t;return t}};function N(n,t){return new u(n,t)}function S(n,t){let e,r=N(()=>{e?.(),e=n();},{equals:()=>!1,debug:"effect",...t});return r.get(),y(r),()=>{e?.(),E(r);}}function p(n,t={}){let e=t?.equals??Object.is,r=new observable.Observable;function h(){if(typeof i=="object"&&i!==null&&i.dependencies.set(r,r.subscribe(i.observer)),n instanceof Error)throw n;return n}function s(l){return e(n,l)||(n=l,r.next()),n}return {get:h,set:s,[b]:r}}var A=p;exports.computed=N;exports.createSignal=p;exports.createWatcher=g;exports.effect=S;exports.getPending=m;exports.state=A;exports.untrack=f;exports.unwatch=E;exports.watch=y;
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import {Observable,Observer}from'@esmj/observable';var r=null;function h(n){let t=r;r=null;let e=n();return r=t,e}var x=Symbol("internal observable"),c=Symbol("original next"),f=class extends Observable{#t=new Set;#e=null;constructor(t){super(),this.#e=t,this.pipe(e=>{let s=e.subscribe.bind(e);return e.subscribe=i=>{s(i),this.#t.add(i);},e});}watch(t){if(typeof t.next!="function"&&(t.next=()=>h(()=>{this.#e();}),t.next[c]=void 0),t instanceof o&&t.next[c]===void 0){let e=t.next.bind(t);t.next=()=>h(()=>{e(),this.#e();}),t.next[c]=e;}return this.subscribe(t)}getPending(){return Array.from(this.#t)}unwatch(t){return t.next=t.next[c],this.unsubscribe(t)}},u=null;function w(n){u=new f(n);}w(()=>{setTimeout(()=>{y().forEach(n=>{h(()=>{n.get();});});},0);});function y(){return u.getPending()}function g(n){return u.watch(n)}function m(n){return u.unwatch(n)}var o=class extends Observer{#t=!0;#e=null;#n=null;#r=this.#u();#s=null;#i=null;constructor(t,e){super(),this.#s=t,this.#i=e,this.get=this.get.bind(this);}#o(){Array.from(this.#r.dependencies.values()).forEach(({unsubscribe:t})=>{t();}),this.#r.dependencies.clear();}#u(){return {dependencies:new Map,observer:this}}#h(){this.#e=r,r=this.#r;}#f(){r=this.#e;}next(){this.#t=!0,this.#n[x].next();}get(){return this.#n||(this.#n=d(this.#c(),this.#i)),this.#t&&this.#c(),this.#n.get()}#c(){this.#t=!1,this.#o(),this.#h();let t;try{t=this.#s();}catch(e){t=e;}if(this.#f(),t instanceof Promise&&(t=t.then(e=>e).catch(e=>{throw e})),this.#n&&this.#n.set(t),t instanceof Error)throw t;return t}};function E(n,t){return new o(n,t)}function P(n){let t,e=E(()=>{t?.(),t=n();},{equals:()=>!1});return e.get(),g(e),()=>{t?.(),m(e);}}function d(n,t={}){let e=t?.equals??Object.is,s=new Observable;function i(){if(typeof r=="object"&&r!==null&&r.dependencies.set(s,s.subscribe(r.observer)),n instanceof Error)throw n;return n}function b(l){return e(n,l)||(n=l,s.next()),n}return {get:i,set:b,[x]:s}}var S=d;export{E as computed,d as createSignal,w as createWatcher,P as effect,y as getPending,S as state,h as untrack,m as unwatch,g as watch};
1
+ import {Observable,Observer}from'@esmj/observable';var i=null;function f(n){let t=i;i=null;let e=n();return i=t,e}var b=Symbol("internal observable"),c=Symbol("original next"),d=class extends Observable{#t=new Set;#e=null;constructor(t){super(),this.#e=t,this.pipe(e=>{let r=e.subscribe.bind(e),h=e.unsubscribe.bind(e);return e.subscribe=s=>{r(s),this.#t.add(s);},e.unsubscribe=s=>{h(s),this.#t.delete(s);},e});}watch(t){if(typeof t.next!="function"&&(t.next=()=>f(()=>{this.#t.add(t),this.#e();}),t.next[c]=void 0),t instanceof u&&t.next[c]===void 0){let e=t.next.bind(t);t.next=()=>f(()=>{this.#t.add(t),e(),this.#e();}),t.next[c]=e;}return this.subscribe(t)}getPending(){return Array.from(this.#t).map(e=>{let r=e.get.bind(e);return e.get=()=>f(()=>(this.#t.delete(e),r())),e})}unwatch(t){return t.next=t.next[c],this.unsubscribe(t)}},o=null;function g(n){o=new d(n);}var a=null;g(()=>{clearTimeout(a),a=setTimeout(()=>{m().forEach(n=>{n.get();});},0);});function m(){return o.getPending()}function y(n){return o.watch(n)}function E(n){return o.unwatch(n)}var u=class extends Observer{#t=!0;#e=null;#n=null;#r=this.#o();#i=null;#s=null;constructor(t,e){super(),this.#i=t,this.#s=e,this.debug=e?.debug,this.get=this.get.bind(this);}#u(){Array.from(this.#r.dependencies.values()).forEach(({unsubscribe:t})=>{t();}),this.#r.dependencies.clear();}#o(){return {dependencies:new Map,observer:this}}#h(){this.#e=i,i=this.#r;}#f(){i=this.#e;}next(){this.#t=!0,this.#n[b].next();}get(){return this.#n||(this.#n=p(this.#c(),this.#s)),this.#t&&this.#c(),this.#n.get()}#c(){this.#t=!1,this.#u(),this.#h();let t;try{t=this.#i();}catch(e){t=e;}if(this.#f(),t instanceof Promise&&(t=t.then(e=>e).catch(e=>{throw e})),this.#n&&this.#n.set(t),t instanceof Error)throw t;return t}};function N(n,t){return new u(n,t)}function S(n,t){let e,r=N(()=>{e?.(),e=n();},{equals:()=>!1,debug:"effect",...t});return r.get(),y(r),()=>{e?.(),E(r);}}function p(n,t={}){let e=t?.equals??Object.is,r=new Observable;function h(){if(typeof i=="object"&&i!==null&&i.dependencies.set(r,r.subscribe(i.observer)),n instanceof Error)throw n;return n}function s(l){return e(n,l)||(n=l,r.next()),n}return {get:h,set:s,[b]:r}}var A=p;export{N as computed,p as createSignal,g as createWatcher,S as effect,m as getPending,A as state,f as untrack,E as unwatch,y as watch};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@esmj/signals",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "Tiny reactive signals.",
5
5
  "keywords": [
6
6
  "signals",
@@ -20,7 +20,7 @@
20
20
  "typings": "dist/index.d.ts",
21
21
  "scripts": {
22
22
  "lint:cmd": "eslint -c ./.eslintrc.js --ignore-path ./.prettierignore --no-eslintrc",
23
- "lint": "npm run lint:cmd -- 'src/**/*.ts'",
23
+ "lint": "npm run lint:cmd -- 'src/**/*.mjs' 'src/*.mjs'",
24
24
  "lint:fix": "npm run lint -- --fix",
25
25
  "dev": "node_modules/.bin/tsup --dts --watch --onSuccess 'node ./dist/index.mjs'",
26
26
  "test": "node --test",
@@ -79,6 +79,6 @@
79
79
  "tsup": "^8.3.5"
80
80
  },
81
81
  "dependencies": {
82
- "@esmj/observable": "^0.1.1"
82
+ "@esmj/observable": "^0.2.2"
83
83
  }
84
84
  }