whenmap 0.0.1 → 0.1.0-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.
package/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ BSD 2-Clause License
2
+
3
+ Copyright (c) 2025, Shane Holloway
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ * Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ * Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/README.md ADDED
@@ -0,0 +1,55 @@
1
+ # WhenMap
2
+
3
+ `WhenMap` is an extension of `Map` that contains only promise instances,
4
+ inspired by [`customElements.whenDefined()`][CER].
5
+ WhenMap is particularly useful for decoupling uses of a value from code that
6
+ initalizes the value.
7
+
8
+ [CER]: https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/whenDefined
9
+
10
+ ## Use
11
+
12
+ ```javascript
13
+ import { WhenMap } from 'whenmap'
14
+
15
+ let whenmap = new WhenMap()
16
+
17
+ let p_ready = whenmap.when('example_key')
18
+ p_ready.then(v => console.log('Ready!', {v}))
19
+
20
+ whenmap.set('example_key', example_init())
21
+
22
+ async function example_init() {
23
+ // async initialize process
24
+ return {example: 42}
25
+ }
26
+ ```
27
+
28
+ ## WhenMap API
29
+ - `whenmap.when(key)` returns a promise for the key. The promise
30
+ may or may not be resolved.
31
+
32
+ - `whenmap.get(key)` is an alias for `whenmap.when(key)`
33
+
34
+ - `whenmap.set(key, value)` resolves the promise for the specified key, returning `this`.
35
+
36
+ - `whenmap.has(key)` returns
37
+ `false` for untracked keys,
38
+ `true` for resolved tracked keys, and
39
+ `1` for unresolved tracked keys.
40
+
41
+ - `whenmap.delete(key)` resolves a tracked key as `undefined` before removing it.
42
+
43
+ - `whenmap.clear()` resolves any outstanding tracked keys as `undefined` before
44
+ clearing all tracked keys.
45
+
46
+ ## Install
47
+
48
+ ```bash
49
+ $ npm install whenmap
50
+ ```
51
+
52
+ ## License
53
+
54
+ [BSD 2-clause](LICENSE)
55
+
package/esm/whenmap.js CHANGED
@@ -1,127 +1,40 @@
1
- function whenmap(opt) {
2
- return _whenmap(_whenmap_entry_, opt)}
3
-
4
-
5
- function _whenmap(_entry_proto_, opt) {
6
- const _subs = opt?.subscribers ?? new Map();
7
-
8
- const _db = opt?.db ?? new Map();
9
- const _at = key => {
10
- let entry = _db.get(key);
11
- if (undefined === entry) {
12
- _db.set(key, entry=_entry_proto_.init(key, _emit));}
13
- return entry};
14
-
15
- return {
16
- __proto__: null
17
-
18
- , // avoid lazy init for has() query
19
- has: key => !! _db.get(key)?.assigned
20
-
21
- , get: key => _at(key).promise
22
- , when: key => _at(key).promise
23
-
24
- , async set_when(key, value) {
25
- _at(key); // reference in the db
26
- this.set(key, value = await value);
27
- return value}
28
-
29
- , set(key, value) {
30
- let entry = _at(key);
31
- entry.resolve(value);
32
- return this}
33
-
34
- , delete(key) {
35
- let entry = _db.get(key);
36
- entry?.fin() && _emit(key);
37
- return _db.delete(key)}
38
-
39
- , clear() {
40
- let tuples = [... _db.entries()];
41
- _db.clear();
42
-
43
- for (let [,entry] of tuples) {
44
- entry.fin();}
45
-
46
- for (let [key] of tuples) {
47
- _emit(key);} }
48
-
49
-
50
- , keys: () => _db.keys()
51
- , *values() {for (let [,entry] of _db) {yield entry.promise;} }
52
- , *entries() {for (let [key, entry] of _db) {yield [key, entry.promise];} }
53
- , [Symbol.iterator]() {return this.entries()}
54
-
55
- , value_stream_at(key, signal) {
56
- return _at(key).when_stream(signal)}
57
-
58
- , async * entry_stream_at(key, signal) {
59
- for await (let value of _at(key).when_stream(signal)) {
60
- yield [key, value];} }
61
-
62
- , async subscribe_at(key, emit_fn, signal) {
63
- for await (let value of _at(key).when_stream(signal)) {
64
- emit_fn(key, value);} }
65
-
66
- , subscribe(key_or_fn, ...args) {
67
- if (key_or_fn.call) {
68
- _subs.set(key_or_fn, args[0]);}
69
- else if (key_or_fn.trim) {
70
- this.subscribe_at(key_or_fn, ...args);}
71
- else throw TypeError()
72
- return this} }
73
-
74
-
75
- function _emit(key, value) {
76
- for (let [emit_fn, signal] of _subs) {
77
- if (! signal?.aborted) {
78
- emit_fn(key, value);}
79
- else _subs.delete(emit_fn);} } }
80
-
81
-
82
- const _whenmap_entry_ ={
83
- assigned: false
84
- , done: false
85
-
86
- , init(key, _emit) {
87
- _emit = _emit.bind(null, key);
88
- let self ={
89
- __proto__: this, key
90
- , cycle(value) {
91
- let $ = this.$, _dn = Promise.withResolvers()
92
- ; (this.$ = _dn).promise.then(_emit);
93
- return $} };
94
-
95
- self.cycle();
96
- return self}
97
-
98
- , cycle() {
99
- let _dp = this.$
100
- ;(this.$ = Promise.withResolvers())
101
- .promise.then(this._emit);
102
- return _dp}
103
-
104
- , fin() {
105
- this.done = true;
106
- let _dp = this.$;
107
- this.$ = null;
108
- _dp?.resolve();
1
+ const _when_fns = new WeakMap();
2
+
3
+ class WhenMap extends Map {
4
+ has(key) {
5
+ let p = super.get(key);
6
+ return p ? _when_fns.has(p) ? 1 : true : false}
7
+
8
+ get get() {return this.when}
9
+ when(key) {
10
+ let p = super.get(key), f;
11
+ if (! p) {
12
+ p = new Promise(fn => f=fn);
13
+ _when_fns.set(p, f);
14
+ super.set(key, p);}
15
+ return p}
16
+
17
+ set(key, val) {
18
+ // resolve promise
19
+ _pop_when(this.when(key))?.(val);
109
20
  return this}
110
21
 
111
- , resolve(value) {
112
- this.promise = Promise.resolve(value);
113
- this.assigned = true;
114
- this.cycle().resolve(value);}
22
+ delete(key) {
23
+ // resolve outstanding promise, if exists
24
+ _pop_when(super.get(key))?.();
25
+ return super.delete(key)}
115
26
 
116
- , async * when_stream(signal) {
117
- yield this.promise;
27
+ clear() {
28
+ // resolve all outstanding promises
29
+ for (let p of this.values()) {
30
+ _pop_when(p)?.();}
31
+ super.clear();} }
118
32
 
119
- while (1) {
120
- if (this.done || signal?.aborted) {return}
121
- let value = await this.$.promise;
122
33
 
123
- if (this.done || signal?.aborted) {return}
124
- yield value;} } };
34
+ function _pop_when(p) {
35
+ let f = _when_fns.get(p);
36
+ _when_fns.delete(p);
37
+ return f}
125
38
 
126
- export { _whenmap, whenmap as default, whenmap };
39
+ export { WhenMap, WhenMap as default };
127
40
  //# sourceMappingURL=whenmap.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"whenmap.js","sources":["../code/whenmap.jsy"],"sourcesContent":["export function whenmap(opt) ::\n return _whenmap(_whenmap_entry_, opt)\nexport default whenmap\n\n\nexport function _whenmap(_entry_proto_, opt) ::\n const _subs = opt?.subscribers ?? new Map()\n\n const _db = opt?.db ?? new Map()\n const _at = key => ::\n let entry = _db.get(key)\n if undefined === entry ::\n _db.set(key, entry=_entry_proto_.init(key, _emit))\n return entry\n\n return @{}\n __proto__: null\n\n // avoid lazy init for has() query\n has: key => !! _db.get(key)?.assigned\n\n get: key => _at(key).promise\n when: key => _at(key).promise\n\n async set_when(key, value) ::\n _at(key) // reference in the db\n this.set(key, value = await value) \n return value\n\n set(key, value) ::\n let entry = _at(key)\n entry.resolve(value)\n return this\n\n delete(key) ::\n let entry = _db.get(key)\n entry?.fin() && _emit(key)\n return _db.delete(key)\n\n clear() ::\n let tuples = [... _db.entries()]\n _db.clear()\n\n for let [,entry] of tuples ::\n entry.fin()\n\n for let [key] of tuples ::\n _emit(key)\n\n\n keys: () => _db.keys()\n *values() :: for let [,entry] of _db :: yield entry.promise\n *entries() :: for let [key, entry] of _db :: yield [key, entry.promise]\n [Symbol.iterator]() :: return this.entries()\n\n value_stream_at(key, signal) ::\n return _at(key).when_stream(signal)\n\n async * entry_stream_at(key, signal) ::\n for await let value of _at(key).when_stream(signal) ::\n yield [key, value]\n\n async subscribe_at(key, emit_fn, signal) ::\n for await let value of _at(key).when_stream(signal) ::\n emit_fn(key, value)\n\n subscribe(key_or_fn, ...args) ::\n if key_or_fn.call ::\n _subs.set(key_or_fn, args[0])\n else if key_or_fn.trim ::\n this.subscribe_at(key_or_fn, ...args)\n else throw TypeError()\n return this\n\n\n function _emit(key, value) ::\n for let [emit_fn, signal] of _subs ::\n if ! signal?.aborted ::\n emit_fn(key, value)\n else _subs.delete(emit_fn)\n\n\nconst _whenmap_entry_ = @{}\n assigned: false\n done: false\n\n init(key, _emit) ::\n _emit = _emit.bind(null, key)\n let self = @{}\n __proto__: this, key\n cycle(value) ::\n let $ = this.$, _dn = Promise.withResolvers()\n ; (this.$ = _dn).promise.then(_emit)\n return $\n\n self.cycle()\n return self\n\n cycle() ::\n let _dp = this.$\n ;(this.$ = Promise.withResolvers())\n .promise.then(this._emit)\n return _dp\n\n fin() ::\n this.done = true\n let _dp = this.$\n this.$ = null\n _dp?.resolve()\n return this\n\n resolve(value) ::\n this.promise = Promise.resolve(value)\n this.assigned = true\n this.cycle().resolve(value)\n\n async * when_stream(signal) ::\n yield this.promise\n\n while 1 ::\n if this.done || signal?.aborted :: return\n let value = await this.$.promise\n\n if this.done || signal?.aborted :: return\n yield value\n\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"whenmap.js","sources":["../code/whenmap.jsy"],"sourcesContent":["const _when_fns = new WeakMap()\n\nexport class WhenMap extends Map ::\n has(key) ::\n let p = super.get(key)\n return p ? _when_fns.has(p) ? 1 : true : false\n\n get get() :: return this.when\n when(key) ::\n let p = super.get(key), f\n if ! p ::\n p = new Promise(fn => f=fn)\n _when_fns.set(p, f)\n super.set(key, p)\n return p\n\n set(key, val) ::\n // resolve promise\n _pop_when(this.when(key))?.(val)\n return this\n\n delete(key) ::\n // resolve outstanding promise, if exists\n _pop_when(super.get(key))?.()\n return super.delete(key)\n\n clear() ::\n // resolve all outstanding promises\n for let p of this.values() ::\n _pop_when(p)?.()\n super.clear()\n\nexport default WhenMap\n\n\nfunction _pop_when(p) ::\n let f = _when_fns.get(p)\n _when_fns.delete(p)\n return f\n\n"],"names":[],"mappings":"AAAA,MAAA,SAAA,GAAA,IAAA,OAAA;;AAEA,MAAA,OAAA,SAAA,GAAA,CAAA;AACE,EAAA,GAAA,CAAA,GAAA,EAAA;AACE,IAAA,IAAA,CAAA,GAAA,KAAA,CAAA,GAAA,CAAA,GAAA;AACA,IAAA,OAAA,CAAA,GAAA,SAAA,CAAA,GAAA,CAAA,CAAA,CAAA,GAAA,CAAA,GAAA,IAAA,GAAA,KAAA;;EAEF,IAAY,GAAA,GAAA,CAAA,OAAA,IAAA,CAAA,IAAA;AACZ,EAAA,IAAA,CAAA,GAAA,EAAA;AACE,IAAA,IAAA,CAAA,GAAA,KAAA,CAAA,GAAA,CAAA,GAAA,CAAA,EAAA;AACG,IAAA,IAAA,EAAA,CAAA,EAAA;AACD,MAAA,CAAA,GAAA,IAAA,OAAA,CAAA,EAAA,IAAA,CAAA,CAAA,EAAA;AACA,MAAA,SAAA,CAAA,GAAA,CAAA,CAAA,EAAA,CAAA;AACA,MAAA,KAAA,CAAA,GAAA,CAAA,GAAA,EAAA,CAAA,EAAA;AACF,IAAA,OAAA,CAAA;;AAEF,EAAA,GAAA,CAAA,GAAA,EAAA,GAAA,EAAA;;AAEE,IAAA,SAAA,CAAA,IAAA,CAAA,IAAA,CAAA,GAAA,CAAA,CAAA,GAAA,GAAA;AACA,IAAA,OAAA,IAAA;;AAEF,EAAA,MAAA,CAAA,GAAA,EAAA;;AAEE,IAAA,SAAA,CAAA,KAAA,CAAA,GAAA,CAAA,GAAA,CAAA,CAAA;AACA,IAAA,OAAA,KAAA,CAAA,MAAA,CAAA,GAAA,CAAA;;AAEF,EAAA,KAAA,GAAA;;AAEK,IAAA,KAAA,IAAA,CAAA,IAAA,IAAA,CAAA,MAAA,EAAA,EAAA;AACD,MAAA,SAAA,CAAA,CAAA,CAAA,KAAA;AACF,IAAA,KAAA,CAAA,KAAA,GAAA,CAAA;;;AAKJ,SAAA,SAAA,CAAA,CAAA,EAAA;AACE,EAAA,IAAA,CAAA,GAAA,SAAA,CAAA,GAAA,CAAA,CAAA;AACA,EAAA,SAAA,CAAA,MAAA,CAAA,CAAA;AACA,EAAA,OAAA,CAAA;;;;"}
@@ -1 +1 @@
1
- function e(e){return t(r,e)}function t(e,t){const r=t?.subscribers??new Map,s=t?.db??new Map,i=t=>{let r=s.get(t);return void 0===r&&s.set(t,r=e.init(t,n)),r};return{__proto__:null,has:e=>!!s.get(e)?.assigned,get:e=>i(e).promise,when:e=>i(e).promise,async set_when(e,t){return i(e),this.set(e,t=await t),t},set(e,t){return i(e).resolve(t),this},delete(e){let t=s.get(e);return t?.fin()&&n(e),s.delete(e)},clear(){let e=[...s.entries()];s.clear();for(let[,t]of e)t.fin();for(let[t]of e)n(t)},keys:()=>s.keys(),*values(){for(let[,e]of s)yield e.promise},*entries(){for(let[e,t]of s)yield[e,t.promise]},[Symbol.iterator](){return this.entries()},value_stream_at:(e,t)=>i(e).when_stream(t),async*entry_stream_at(e,t){for await(let r of i(e).when_stream(t))yield[e,r]},async subscribe_at(e,t,r){for await(let s of i(e).when_stream(r))t(e,s)},subscribe(e,...t){if(e.call)r.set(e,t[0]);else{if(!e.trim)throw TypeError();this.subscribe_at(e,...t)}return this}};function n(e,t){for(let[s,i]of r)i?.aborted?r.delete(s):s(e,t)}}const r={assigned:!1,done:!1,init(e,t){t=t.bind(null,e);let r={__proto__:this,key:e,cycle(e){let r=this.$,s=Promise.withResolvers();return(this.$=s).promise.then(t),r}};return r.cycle(),r},cycle(){let e=this.$;return(this.$=Promise.withResolvers()).promise.then(this._emit),e},fin(){this.done=!0;let e=this.$;return this.$=null,e?.resolve(),this},resolve(e){this.promise=Promise.resolve(e),this.assigned=!0,this.cycle().resolve(e)},async*when_stream(e){for(yield this.promise;;){if(this.done||e?.aborted)return;let t=await this.$.promise;if(this.done||e?.aborted)return;yield t}}};export{t as _whenmap,e as default,e as whenmap};
1
+ const e=new WeakMap;class t extends Map{has(t){let r=super.get(t);return!!r&&(!e.has(r)||1)}get get(){return this.when}when(t){let r,s=super.get(t);return s||(s=new Promise((e=>r=e)),e.set(s,r),super.set(t,s)),s}set(e,t){return r(this.when(e))?.(t),this}delete(e){return r(super.get(e))?.(),super.delete(e)}clear(){for(let e of this.values())r(e)?.();super.clear()}}function r(t){let r=e.get(t);return e.delete(t),r}export{t as WhenMap,t as default};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "whenmap",
3
- "version": "0.0.1",
3
+ "version": "0.1.0-0",
4
4
  "description": "",
5
5
  "license": "BSD-2-Clause",
6
6
  "author": "Shane Holloway <shane.holloway@ieee.org>",
@@ -17,7 +17,7 @@
17
17
  ],
18
18
  "type": "module",
19
19
  "exports": {
20
- ".": "./esm/index.js",
20
+ ".": "./esm/whenmap.js",
21
21
  "./esm": "./esm"
22
22
  },
23
23
  "imports": {
package/esm/index.js DELETED
@@ -1,4 +0,0 @@
1
- export { _whenmap, whenmap } from './whenmap.js';
2
- export { whencall, whencall_first, whencall_stream, whenmap_watch, whenstream } from './observe_when.js';
3
- export { _whenmap_pxy_, as_whenmap_proxy } from './whenmap_proxy.js';
4
- //# sourceMappingURL=index.js.map
package/esm/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
package/esm/index.min.js DELETED
@@ -1 +0,0 @@
1
- export{_whenmap,whenmap}from"./whenmap.min.js";export{whencall,whencall_first,whencall_stream,whenmap_watch,whenstream}from"./observe_when.min.js";export{_whenmap_pxy_,as_whenmap_proxy}from"./whenmap_proxy.min.js";
@@ -1,74 +0,0 @@
1
- function whenmap_watch(when_tgt, opt={}) {
2
- let { refs, assigns, on_update, signal } = opt;
3
- return {
4
- __proto__: null
5
- , has: key => (_watch(key), when_tgt.has(key))
6
- , get: key => (_watch(key), when_tgt.get(key))
7
- , when: key => (_watch(key), when_tgt.when(key))
8
- , set: (key, value) => (assigns?.add(key), when_tgt.set(key,v))
9
- , set_when: (key, value) => (assigns?.add(key), when_tgt.set_when(key,v))}
10
-
11
- function _watch(key) {
12
- if (on_update && !refs?.has(key)) {
13
- refs ??= new Set(); // lazy init if not present
14
- when_tgt.subscribe(key, on_update, signal);}
15
-
16
- refs?.add(key);} }
17
-
18
- async function * whenstream(when_db, opt_ctx={}) {
19
- var _dp_update, _cache = new Map();
20
-
21
- function on_update(key, value) {
22
- let prev = _cache.get(key);
23
- if (prev===undefined && !_cache.has(key)) {
24
- //First assignment; avoid re-triggering update
25
- _cache.set(key, value);}
26
- else if (value !== prev) {
27
- //Subsequent assignment; do triggering update
28
- _cache.set(key, value);
29
- _dp_update.resolve(true); }// trigger composite update
30
- else ; }//Identical assignment; avoid re-triggering update
31
-
32
-
33
- // wrap when_db in a watch observer
34
- when_db = whenmap_watch(when_db,{
35
- __proto__: opt_ctx, on_update} );
36
-
37
- let when_tgt = opt_ctx.with_whenmap
38
- ? opt_ctx.with_whenmap(when_db) // allow wrapping the when_db; e.g. as a Proxy()
39
- : when_db; // or passthrough
40
-
41
- const {signal, pre_tick, tick, post_tick} = opt_ctx;
42
- while (! signal?.aborted) {
43
- //some dependency updated
44
- await _dp_update?.promise
45
-
46
- // wait throttled; e.g. requestAnimationFrame
47
- ; pre_tick && await pre_tick();
48
-
49
- //reset watcher
50
- _dp_update = Promise.withResolvers()
51
-
52
- ; tick && await tick();
53
-
54
- // return when_tgt because something changed
55
- yield when_tgt
56
-
57
- ; post_tick && await post_tick();} }
58
-
59
- async function whencall(when_db, opt_ctx={}) {
60
- for await (let r of whencall_stream(when_db, opt_ctx)) {} }
61
-
62
- async function whencall_first(when_db, opt_ctx={}) {
63
- for await (let r of whencall_stream(when_db, opt_ctx)) {
64
- return r} }
65
-
66
- async function * whencall_stream(when_db, opt_ctx={}) {
67
- const name = opt_ctx.name;
68
- for await (let db of whenstream(when_db, opt_ctx)) {
69
- let result = await opt_ctx.update(db, name);
70
- if (name) {result = when_db.set(name, result);}
71
- yield result;} }
72
-
73
- export { whencall, whencall_first, whencall_stream, whenmap_watch, whenstream };
74
- //# sourceMappingURL=observe_when.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"observe_when.js","sources":["../code/whenmap_watch.jsy","../code/whenstream.jsy","../code/whencall.jsy"],"sourcesContent":["export function whenmap_watch(when_tgt, opt={}) ::\n let { refs, assigns, on_update, signal } = opt\n return @{}\n __proto__: null\n has: key => (_watch(key), when_tgt.has(key))\n get: key => (_watch(key), when_tgt.get(key))\n when: key => (_watch(key), when_tgt.when(key))\n set: (key, value) => (assigns?.add(key), when_tgt.set(key,v))\n set_when: (key, value) => (assigns?.add(key), when_tgt.set_when(key,v))\n\n function _watch(key) ::\n if on_update && !refs?.has(key) ::\n refs ??= new Set() // lazy init if not present\n when_tgt.subscribe(key, on_update, signal)\n\n refs?.add(key)\n\n","import {whenmap_watch} from './whenmap_watch.jsy'\n\nexport async function * whenstream(when_db, opt_ctx={}) ::\n var _dp_update, _cache = new Map()\n\n function on_update(key, value) ::\n let prev = _cache.get(key)\n if prev===undefined && !_cache.has(key) ::\n //First assignment; avoid re-triggering update\n _cache.set(key, value)\n else if value !== prev ::\n //Subsequent assignment; do triggering update\n _cache.set(key, value)\n _dp_update.resolve(true) // trigger composite update\n else :: //Identical assignment; avoid re-triggering update\n\n\n // wrap when_db in a watch observer\n when_db = whenmap_watch @ when_db, @{}\n __proto__: opt_ctx, on_update\n\n let when_tgt = opt_ctx.with_whenmap\n ? opt_ctx.with_whenmap(when_db) // allow wrapping the when_db; e.g. as a Proxy()\n : when_db // or passthrough\n\n const {signal, pre_tick, tick, post_tick} = opt_ctx\n while ! signal?.aborted ::\n //some dependency updated\n await _dp_update?.promise\n\n // wait throttled; e.g. requestAnimationFrame\n ; pre_tick && await pre_tick()\n\n //reset watcher\n _dp_update = Promise.withResolvers()\n\n ; tick && await tick()\n\n // return when_tgt because something changed\n yield when_tgt\n\n ; post_tick && await post_tick()\n\n\n","import {whenstream} from './whenstream.jsy'\n\nexport async function whencall(when_db, opt_ctx={}) ::\n for await let r of whencall_stream(when_db, opt_ctx) ::\n\nexport async function whencall_first(when_db, opt_ctx={}) ::\n for await let r of whencall_stream(when_db, opt_ctx) ::\n return r\n\nexport async function * whencall_stream(when_db, opt_ctx={}) ::\n const name = opt_ctx.name\n for await let db of whenstream(when_db, opt_ctx) ::\n let result = await opt_ctx.update(db, name)\n if name :: result = when_db.set(name, result)\n yield result\n\n"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- function t(t,e={}){let{refs:a,assigns:n,on_update:s,signal:i}=e;return{__proto__:null,has:e=>(o(e),t.has(e)),get:e=>(o(e),t.get(e)),when:e=>(o(e),t.when(e)),set:(e,a)=>(n?.add(e),t.set(e,v)),set_when:(e,a)=>(n?.add(e),t.set_when(e,v))};function o(e){s&&!a?.has(e)&&(a??=new Set,t.subscribe(e,s,i)),a?.add(e)}}async function*e(e,a={}){var n,s=new Map;e=t(e,{__proto__:a,on_update:function(t,e){let a=s.get(t);void 0!==a||s.has(t)?e!==a&&(s.set(t,e),n.resolve(!0)):s.set(t,e)}});let i=a.with_whenmap?a.with_whenmap(e):e;const{signal:o,pre_tick:r,tick:w,post_tick:c}=a;for(;!o?.aborted;)await(n?.promise),r&&await r(),n=Promise.withResolvers(),w&&await w(),yield i,c&&await c()}async function a(t,e={}){for await(let a of s(t,e));}async function n(t,e={}){for await(let a of s(t,e))return a}async function*s(t,a={}){const n=a.name;for await(let s of e(t,a)){let e=await a.update(s,n);n&&(e=t.set(n,e)),yield e}}export{a as whencall,n as whencall_first,s as whencall_stream,t as whenmap_watch,e as whenstream};
@@ -1,10 +0,0 @@
1
- const _whenmap_pxy_ ={
2
- has: (map_db, key) => key !== 'then' ? map_db.has(key) : null
3
- , get: (map_db, key) => key !== 'then' ? map_db.when(key) : null
4
- , set: (map_db, key, value) => key !== 'then' ? map_db.set_when(key, value) : null};
5
-
6
- const as_whenmap_proxy = when_db =>
7
- new Proxy(when_db, _whenmap_pxy_);
8
-
9
- export { _whenmap_pxy_, as_whenmap_proxy, as_whenmap_proxy as default };
10
- //# sourceMappingURL=whenmap_proxy.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"whenmap_proxy.js","sources":["../code/whenmap_proxy.jsy"],"sourcesContent":["export const _whenmap_pxy_ = @{}\n has: (map_db, key) => key !== 'then' ? map_db.has(key) : null\n get: (map_db, key) => key !== 'then' ? map_db.when(key) : null\n set: (map_db, key, value) => key !== 'then' ? map_db.set_when(key, value) : null\n\nexport const as_whenmap_proxy = when_db =>\n new Proxy(when_db, _whenmap_pxy_)\n\nexport default as_whenmap_proxy\n"],"names":[],"mappings":"AAAA,MAAA,aAAA,EAAA;AACE,EAAA,GAAA,EAAA,CAAA,MAAA,EAAA,GAAA,KAAA,GAAA,KAA8B,MAAM,GAAA,MAAA,CAAA,GAAA,CAAA,GAAA,CAAA,GAAA;AACpC,EAAA,GAAA,EAAA,CAAA,MAAA,EAAA,GAAA,KAAA,GAAA,KAA8B,MAAM,GAAA,MAAA,CAAA,IAAA,CAAA,GAAA,CAAA,GAAA;AACpC,EAAA,GAAA,EAAA,CAAA,MAAA,EAAA,GAAA,EAAA,KAAA,KAAA,GAAA,KAAqC,MAAM,GAAA,MAAA,CAAA,QAAA,CAAA,GAAA,EAAA,KAAA,CAAA,GAAA,IAAA;;AAE7C,MAAA,gBAAA,GAAA,OAAA;AACC,CAAA,IAAA,KAAA,CAAA,OAAA,EAAA,aAAA;;;;"}
@@ -1 +0,0 @@
1
- const e={has:(e,n)=>"then"!==n?e.has(n):null,get:(e,n)=>"then"!==n?e.when(n):null,set:(e,n,t)=>"then"!==n?e.set_when(n,t):null},n=n=>new Proxy(n,e);export{e as _whenmap_pxy_,n as as_whenmap_proxy,n as default};