@lumino/signaling
Advanced tools
Comparing version 2.0.0-alpha.6 to 2.0.0-alpha.7
import { find, ArrayExt } from '@lumino/algorithm'; | ||
import { PromiseDelegate } from '@lumino/coreutils'; | ||
import { AttachedProperty } from '@lumino/properties'; | ||
@@ -60,5 +62,26 @@ // Copyright (c) Jupyter Development Team. | ||
constructor(sender) { | ||
/** | ||
* If `blocked` is not `0`, the signal will not emit. | ||
*/ | ||
this.blocked = 0; | ||
this.sender = sender; | ||
} | ||
/** | ||
* Block the signal during the execution of a callback. | ||
* | ||
* ### Notes | ||
* The callback function must be synchronous. | ||
* | ||
* @param fn The callback during which the signal is blocked | ||
*/ | ||
block(fn) { | ||
this.blocked++; | ||
try { | ||
fn(); | ||
} | ||
finally { | ||
this.blocked--; | ||
} | ||
} | ||
/** | ||
* Connect a slot to the signal. | ||
@@ -100,3 +123,5 @@ * | ||
emit(args) { | ||
Private.emit(this, args); | ||
if (!this.blocked) { | ||
Private.emit(this, args); | ||
} | ||
} | ||
@@ -109,2 +134,23 @@ } | ||
/** | ||
* Block all signals emitted by an object during | ||
* the execution of a callback. | ||
* | ||
* ### Notes | ||
* The callback function must be synchronous. | ||
* | ||
* @param sender The signals sender | ||
* @param fn The callback during which all signals are blocked | ||
*/ | ||
function blockAll(sender, fn) { | ||
const { blockedProperty } = Private; | ||
blockedProperty.set(sender, blockedProperty.get(sender) + 1); | ||
try { | ||
fn(); | ||
} | ||
finally { | ||
blockedProperty.set(sender, blockedProperty.get(sender) - 1); | ||
} | ||
} | ||
Signal.blockAll = blockAll; | ||
/** | ||
* Remove all connections between a sender and receiver. | ||
@@ -205,2 +251,89 @@ * | ||
/** | ||
* A concrete implementation of `IStream`. | ||
* | ||
* #### Example | ||
* ```typescript | ||
* import { IStream, Stream } from '@lumino/signaling'; | ||
* | ||
* class SomeClass { | ||
* | ||
* constructor(name: string) { | ||
* this.name = name; | ||
* } | ||
* | ||
* readonly name: string; | ||
* | ||
* get pings(): IStream<this, string> { | ||
* return this._pings; | ||
* } | ||
* | ||
* ping(value: string) { | ||
* this._pings.emit(value); | ||
* } | ||
* | ||
* private _pings = new Stream<this, string>(this); | ||
* } | ||
* | ||
* let m1 = new SomeClass('foo'); | ||
* | ||
* m1.pings.connect((_, value: string) => { | ||
* console.log('connect', value); | ||
* }); | ||
* | ||
* void (async () => { | ||
* for await (const ping of m1.pings) { | ||
* console.log('iterator', ping); | ||
* } | ||
* })(); | ||
* | ||
* m1.ping('alpha'); // logs: connect alpha | ||
* // logs: iterator alpha | ||
* m1.ping('beta'); // logs: connect beta | ||
* // logs: iterator beta | ||
* ``` | ||
*/ | ||
class Stream extends Signal { | ||
constructor() { | ||
super(...arguments); | ||
this._pending = new PromiseDelegate(); | ||
} | ||
/** | ||
* Return an async iterator that yields every emission. | ||
*/ | ||
async *[Symbol.asyncIterator]() { | ||
let pending = this._pending; | ||
while (true) { | ||
try { | ||
const { args, next } = await pending.promise; | ||
pending = next; | ||
yield args; | ||
} | ||
catch (_) { | ||
return; // Any promise rejection stops the iterator. | ||
} | ||
} | ||
} | ||
/** | ||
* Emit the signal, invoke the connected slots, and yield the emission. | ||
* | ||
* @param args - The args to pass to the connected slots. | ||
*/ | ||
emit(args) { | ||
if (!this.blocked) { | ||
const pending = this._pending; | ||
const next = (this._pending = new PromiseDelegate()); | ||
pending.resolve({ args, next }); | ||
super.emit(args); | ||
} | ||
} | ||
/** | ||
* Stop the stream's async iteration. | ||
*/ | ||
stop() { | ||
this._pending.promise.catch(() => undefined); | ||
this._pending.reject('stop'); | ||
this._pending = new PromiseDelegate(); | ||
} | ||
} | ||
/** | ||
* The namespace for the module implementation details. | ||
@@ -409,2 +542,5 @@ */ | ||
function emit(signal, args) { | ||
if (Private.blockedProperty.get(signal.sender) > 0) { | ||
return; | ||
} | ||
// If there are no receivers, there is nothing to do. | ||
@@ -510,5 +646,12 @@ let receivers = receiversForSender.get(signal.sender); | ||
} | ||
/** | ||
* A property indicating a sender has been blocked if its value is not 0. | ||
*/ | ||
Private.blockedProperty = new AttachedProperty({ | ||
name: 'blocked', | ||
create: () => 0 | ||
}); | ||
})(Private || (Private = {})); | ||
export { Signal }; | ||
export { Signal, Stream }; | ||
//# sourceMappingURL=index.es6.js.map |
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@lumino/algorithm')) : | ||
typeof define === 'function' && define.amd ? define(['exports', '@lumino/algorithm'], factory) : | ||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.lumino_signaling = {}, global.lumino_algorithm)); | ||
})(this, (function (exports, algorithm) { 'use strict'; | ||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@lumino/algorithm'), require('@lumino/coreutils'), require('@lumino/properties')) : | ||
typeof define === 'function' && define.amd ? define(['exports', '@lumino/algorithm', '@lumino/coreutils', '@lumino/properties'], factory) : | ||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.lumino_signaling = {}, global.lumino_algorithm, global.lumino_coreutils, global.lumino_properties)); | ||
})(this, (function (exports, algorithm, coreutils, properties) { 'use strict'; | ||
@@ -64,5 +64,26 @@ // Copyright (c) Jupyter Development Team. | ||
constructor(sender) { | ||
/** | ||
* If `blocked` is not `0`, the signal will not emit. | ||
*/ | ||
this.blocked = 0; | ||
this.sender = sender; | ||
} | ||
/** | ||
* Block the signal during the execution of a callback. | ||
* | ||
* ### Notes | ||
* The callback function must be synchronous. | ||
* | ||
* @param fn The callback during which the signal is blocked | ||
*/ | ||
block(fn) { | ||
this.blocked++; | ||
try { | ||
fn(); | ||
} | ||
finally { | ||
this.blocked--; | ||
} | ||
} | ||
/** | ||
* Connect a slot to the signal. | ||
@@ -104,3 +125,5 @@ * | ||
emit(args) { | ||
Private.emit(this, args); | ||
if (!this.blocked) { | ||
Private.emit(this, args); | ||
} | ||
} | ||
@@ -113,2 +136,23 @@ } | ||
/** | ||
* Block all signals emitted by an object during | ||
* the execution of a callback. | ||
* | ||
* ### Notes | ||
* The callback function must be synchronous. | ||
* | ||
* @param sender The signals sender | ||
* @param fn The callback during which all signals are blocked | ||
*/ | ||
function blockAll(sender, fn) { | ||
const { blockedProperty } = Private; | ||
blockedProperty.set(sender, blockedProperty.get(sender) + 1); | ||
try { | ||
fn(); | ||
} | ||
finally { | ||
blockedProperty.set(sender, blockedProperty.get(sender) - 1); | ||
} | ||
} | ||
Signal.blockAll = blockAll; | ||
/** | ||
* Remove all connections between a sender and receiver. | ||
@@ -209,2 +253,89 @@ * | ||
/** | ||
* A concrete implementation of `IStream`. | ||
* | ||
* #### Example | ||
* ```typescript | ||
* import { IStream, Stream } from '@lumino/signaling'; | ||
* | ||
* class SomeClass { | ||
* | ||
* constructor(name: string) { | ||
* this.name = name; | ||
* } | ||
* | ||
* readonly name: string; | ||
* | ||
* get pings(): IStream<this, string> { | ||
* return this._pings; | ||
* } | ||
* | ||
* ping(value: string) { | ||
* this._pings.emit(value); | ||
* } | ||
* | ||
* private _pings = new Stream<this, string>(this); | ||
* } | ||
* | ||
* let m1 = new SomeClass('foo'); | ||
* | ||
* m1.pings.connect((_, value: string) => { | ||
* console.log('connect', value); | ||
* }); | ||
* | ||
* void (async () => { | ||
* for await (const ping of m1.pings) { | ||
* console.log('iterator', ping); | ||
* } | ||
* })(); | ||
* | ||
* m1.ping('alpha'); // logs: connect alpha | ||
* // logs: iterator alpha | ||
* m1.ping('beta'); // logs: connect beta | ||
* // logs: iterator beta | ||
* ``` | ||
*/ | ||
class Stream extends Signal { | ||
constructor() { | ||
super(...arguments); | ||
this._pending = new coreutils.PromiseDelegate(); | ||
} | ||
/** | ||
* Return an async iterator that yields every emission. | ||
*/ | ||
async *[Symbol.asyncIterator]() { | ||
let pending = this._pending; | ||
while (true) { | ||
try { | ||
const { args, next } = await pending.promise; | ||
pending = next; | ||
yield args; | ||
} | ||
catch (_) { | ||
return; // Any promise rejection stops the iterator. | ||
} | ||
} | ||
} | ||
/** | ||
* Emit the signal, invoke the connected slots, and yield the emission. | ||
* | ||
* @param args - The args to pass to the connected slots. | ||
*/ | ||
emit(args) { | ||
if (!this.blocked) { | ||
const pending = this._pending; | ||
const next = (this._pending = new coreutils.PromiseDelegate()); | ||
pending.resolve({ args, next }); | ||
super.emit(args); | ||
} | ||
} | ||
/** | ||
* Stop the stream's async iteration. | ||
*/ | ||
stop() { | ||
this._pending.promise.catch(() => undefined); | ||
this._pending.reject('stop'); | ||
this._pending = new coreutils.PromiseDelegate(); | ||
} | ||
} | ||
/** | ||
* The namespace for the module implementation details. | ||
@@ -413,2 +544,5 @@ */ | ||
function emit(signal, args) { | ||
if (Private.blockedProperty.get(signal.sender) > 0) { | ||
return; | ||
} | ||
// If there are no receivers, there is nothing to do. | ||
@@ -514,5 +648,13 @@ let receivers = receiversForSender.get(signal.sender); | ||
} | ||
/** | ||
* A property indicating a sender has been blocked if its value is not 0. | ||
*/ | ||
Private.blockedProperty = new properties.AttachedProperty({ | ||
name: 'blocked', | ||
create: () => 0 | ||
}); | ||
})(Private || (Private = {})); | ||
exports.Signal = Signal; | ||
exports.Stream = Stream; | ||
@@ -519,0 +661,0 @@ Object.defineProperty(exports, '__esModule', { value: true }); |
@@ -1,2 +0,2 @@ | ||
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("@lumino/algorithm")):"function"==typeof define&&define.amd?define(["exports","@lumino/algorithm"],n):n((e="undefined"!=typeof globalThis?globalThis:e||self).lumino_signaling={},e.lumino_algorithm)}(this,(function(e,n){"use strict";class t{constructor(e){this.sender=e}connect(e,n){return i.connect(this,e,n)}disconnect(e,n){return i.disconnect(this,e,n)}emit(e){i.emit(this,e)}}var i;!function(e){e.disconnectBetween=function(e,n){i.disconnectBetween(e,n)},e.disconnectSender=function(e){i.disconnectSender(e)},e.disconnectReceiver=function(e){i.disconnectReceiver(e)},e.disconnectAll=function(e){i.disconnectAll(e)},e.clearData=function(e){i.disconnectAll(e)},e.getExceptionHandler=function(){return i.exceptionHandler},e.setExceptionHandler=function(e){let n=i.exceptionHandler;return i.exceptionHandler=e,n}}(t||(t={})),function(e){function t(e){let n=o.get(e);if(n&&0!==n.length){for(const e of n){if(!e.signal)continue;let n=e.thisArg||e.slot;e.signal=null,f(c.get(n))}f(n)}}function i(e){let n=c.get(e);if(n&&0!==n.length){for(const e of n){if(!e.signal)continue;let n=e.signal.sender;e.signal=null,f(o.get(n))}f(n)}}e.exceptionHandler=e=>{console.error(e)},e.connect=function(e,n,t){t=t||void 0;let i=o.get(e.sender);if(i||(i=[],o.set(e.sender,i)),s(i,e,n,t))return!1;let l=t||n,r=c.get(l);r||(r=[],c.set(l,r));let u={signal:e,slot:n,thisArg:t};return i.push(u),r.push(u),!0},e.disconnect=function(e,n,t){t=t||void 0;let i=o.get(e.sender);if(!i||0===i.length)return!1;let l=s(i,e,n,t);if(!l)return!1;let r=t||n,u=c.get(r);return l.signal=null,f(i),f(u),!0},e.disconnectBetween=function(e,n){let t=o.get(e);if(!t||0===t.length)return;let i=c.get(n);if(i&&0!==i.length){for(const n of i)n.signal&&n.signal.sender===e&&(n.signal=null);f(t),f(i)}},e.disconnectSender=t,e.disconnectReceiver=i,e.disconnectAll=function(e){t(e),i(e)},e.emit=function(e,n){let t=o.get(e.sender);if(t&&0!==t.length)for(let i=0,o=t.length;i<o;++i){let o=t[i];o.signal===e&&u(o,n)}};const o=new WeakMap,c=new WeakMap,l=new Set,r="function"==typeof requestAnimationFrame?requestAnimationFrame:setImmediate;function s(e,t,i,o){return n.find(e,(e=>e.signal===t&&e.slot===i&&e.thisArg===o))}function u(n,t){let{signal:i,slot:o,thisArg:c}=n;try{o.call(c,i.sender,t)}catch(n){e.exceptionHandler(n)}}function f(e){0===l.size&&r(d),l.add(e)}function d(){l.forEach(a),l.clear()}function a(e){n.ArrayExt.removeAllWhere(e,g)}function g(e){return null===e.signal}}(i||(i={})),e.Signal=t,Object.defineProperty(e,"__esModule",{value:!0})})); | ||
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("@lumino/algorithm"),require("@lumino/coreutils"),require("@lumino/properties")):"function"==typeof define&&define.amd?define(["exports","@lumino/algorithm","@lumino/coreutils","@lumino/properties"],n):n((e="undefined"!=typeof globalThis?globalThis:e||self).lumino_signaling={},e.lumino_algorithm,e.lumino_coreutils,e.lumino_properties)}(this,(function(e,n,t,i){"use strict";class o{constructor(e){this.blocked=0,this.sender=e}block(e){this.blocked++;try{e()}finally{this.blocked--}}connect(e,n){return l.connect(this,e,n)}disconnect(e,n){return l.disconnect(this,e,n)}emit(e){this.blocked||l.emit(this,e)}}!function(e){e.blockAll=function(e,n){const{blockedProperty:t}=l;t.set(e,t.get(e)+1);try{n()}finally{t.set(e,t.get(e)-1)}},e.disconnectBetween=function(e,n){l.disconnectBetween(e,n)},e.disconnectSender=function(e){l.disconnectSender(e)},e.disconnectReceiver=function(e){l.disconnectReceiver(e)},e.disconnectAll=function(e){l.disconnectAll(e)},e.clearData=function(e){l.disconnectAll(e)},e.getExceptionHandler=function(){return l.exceptionHandler},e.setExceptionHandler=function(e){let n=l.exceptionHandler;return l.exceptionHandler=e,n}}(o||(o={}));class r extends o{constructor(){super(...arguments),this._pending=new t.PromiseDelegate}async*[Symbol.asyncIterator](){let e=this._pending;for(;;)try{const{args:n,next:t}=await e.promise;e=t,yield n}catch(e){return}}emit(e){if(!this.blocked){const n=this._pending,i=this._pending=new t.PromiseDelegate;n.resolve({args:e,next:i}),super.emit(e)}}stop(){this._pending.promise.catch((()=>{})),this._pending.reject("stop"),this._pending=new t.PromiseDelegate}}var l;!function(e){function t(e){let n=r.get(e);if(n&&0!==n.length){for(const e of n){if(!e.signal)continue;let n=e.thisArg||e.slot;e.signal=null,a(l.get(n))}a(n)}}function o(e){let n=l.get(e);if(n&&0!==n.length){for(const e of n){if(!e.signal)continue;let n=e.signal.sender;e.signal=null,a(r.get(n))}a(n)}}e.exceptionHandler=e=>{console.error(e)},e.connect=function(e,n,t){t=t||void 0;let i=r.get(e.sender);if(i||(i=[],r.set(e.sender,i)),u(i,e,n,t))return!1;let o=t||n,c=l.get(o);c||(c=[],l.set(o,c));let s={signal:e,slot:n,thisArg:t};return i.push(s),c.push(s),!0},e.disconnect=function(e,n,t){t=t||void 0;let i=r.get(e.sender);if(!i||0===i.length)return!1;let o=u(i,e,n,t);if(!o)return!1;let c=t||n,s=l.get(c);return o.signal=null,a(i),a(s),!0},e.disconnectBetween=function(e,n){let t=r.get(e);if(!t||0===t.length)return;let i=l.get(n);if(i&&0!==i.length){for(const n of i)n.signal&&n.signal.sender===e&&(n.signal=null);a(t),a(i)}},e.disconnectSender=t,e.disconnectReceiver=o,e.disconnectAll=function(e){t(e),o(e)},e.emit=function(n,t){if(e.blockedProperty.get(n.sender)>0)return;let i=r.get(n.sender);if(i&&0!==i.length)for(let e=0,o=i.length;e<o;++e){let o=i[e];o.signal===n&&d(o,t)}};const r=new WeakMap,l=new WeakMap,c=new Set,s="function"==typeof requestAnimationFrame?requestAnimationFrame:setImmediate;function u(e,t,i,o){return n.find(e,(e=>e.signal===t&&e.slot===i&&e.thisArg===o))}function d(n,t){let{signal:i,slot:o,thisArg:r}=n;try{o.call(r,i.sender,t)}catch(n){e.exceptionHandler(n)}}function a(e){0===c.size&&s(f),c.add(e)}function f(){c.forEach(g),c.clear()}function g(e){n.ArrayExt.removeAllWhere(e,p)}function p(e){return null===e.signal}e.blockedProperty=new i.AttachedProperty({name:"blocked",create:()=>0})}(l||(l={})),e.Signal=o,e.Stream=r,Object.defineProperty(e,"__esModule",{value:!0})})); | ||
//# sourceMappingURL=index.min.js.map |
{ | ||
"name": "@lumino/signaling", | ||
"version": "2.0.0-alpha.6", | ||
"version": "2.0.0-alpha.7", | ||
"description": "Lumino Signals and Slots", | ||
@@ -38,3 +38,4 @@ "homepage": "https://github.com/jupyterlab/lumino", | ||
"test:firefox-headless": "cd tests && karma start --browsers=FirefoxHeadless", | ||
"test:ie": "cd tests && karma start --browsers=IE", | ||
"test:webkit": "cd tests && karma start --browsers=Webkit", | ||
"test:webkit-headless": "cd tests && karma start --browsers=WebkitHeadless", | ||
"watch": "tsc --build --watch" | ||
@@ -47,3 +48,5 @@ }, | ||
"dependencies": { | ||
"@lumino/algorithm": "^2.0.0-alpha.6" | ||
"@lumino/algorithm": "^2.0.0-alpha.7", | ||
"@lumino/coreutils": "^2.0.0-alpha.7", | ||
"@lumino/properties": "^2.0.0-alpha.7" | ||
}, | ||
@@ -61,6 +64,7 @@ "devDependencies": { | ||
"karma-firefox-launcher": "^2.1.1", | ||
"karma-ie-launcher": "^1.0.0", | ||
"karma-mocha": "^2.0.1", | ||
"karma-mocha-reporter": "^2.2.5", | ||
"karma-webkit-launcher": "^1.0.2", | ||
"mocha": "^9.0.3", | ||
"playwright": "^1.26.0", | ||
"postcss": "^8.4.14", | ||
@@ -67,0 +71,0 @@ "rimraf": "^3.0.2", |
167
src/index.ts
@@ -11,2 +11,4 @@ // Copyright (c) Jupyter Development Team. | ||
import { ArrayExt, find } from '@lumino/algorithm'; | ||
import { PromiseDelegate } from '@lumino/coreutils'; | ||
import { AttachedProperty } from '@lumino/properties'; | ||
@@ -36,2 +38,12 @@ /** | ||
/** | ||
* Block the signal during the execution of a callback. | ||
* | ||
* ### Notes | ||
* The callback function must be synchronous. | ||
* | ||
* @param fn The callback during which the signal is blocked | ||
*/ | ||
block(fn: () => void): void; | ||
/** | ||
* Connect a slot to the signal. | ||
@@ -79,2 +91,7 @@ * | ||
/** | ||
* An object that is both a signal and an async iterable. | ||
*/ | ||
export interface IStream<T, U> extends ISignal<T, U>, AsyncIterable<U> {} | ||
/** | ||
* A concrete implementation of `ISignal`. | ||
@@ -144,2 +161,19 @@ * | ||
/** | ||
* Block the signal during the execution of a callback. | ||
* | ||
* ### Notes | ||
* The callback function must be synchronous. | ||
* | ||
* @param fn The callback during which the signal is blocked | ||
*/ | ||
block(fn: () => void): void { | ||
this.blocked++; | ||
try { | ||
fn(); | ||
} finally { | ||
this.blocked--; | ||
} | ||
} | ||
/** | ||
* Connect a slot to the signal. | ||
@@ -183,4 +217,11 @@ * | ||
emit(args: U): void { | ||
Private.emit(this, args); | ||
if (!this.blocked) { | ||
Private.emit(this, args); | ||
} | ||
} | ||
/** | ||
* If `blocked` is not `0`, the signal will not emit. | ||
*/ | ||
protected blocked = 0; | ||
} | ||
@@ -193,2 +234,22 @@ | ||
/** | ||
* Block all signals emitted by an object during | ||
* the execution of a callback. | ||
* | ||
* ### Notes | ||
* The callback function must be synchronous. | ||
* | ||
* @param sender The signals sender | ||
* @param fn The callback during which all signals are blocked | ||
*/ | ||
export function blockAll(sender: unknown, fn: () => void): void { | ||
const { blockedProperty } = Private; | ||
blockedProperty.set(sender, blockedProperty.get(sender) + 1); | ||
try { | ||
fn(); | ||
} finally { | ||
blockedProperty.set(sender, blockedProperty.get(sender) - 1); | ||
} | ||
} | ||
/** | ||
* Remove all connections between a sender and receiver. | ||
@@ -296,2 +357,89 @@ * | ||
/** | ||
* A concrete implementation of `IStream`. | ||
* | ||
* #### Example | ||
* ```typescript | ||
* import { IStream, Stream } from '@lumino/signaling'; | ||
* | ||
* class SomeClass { | ||
* | ||
* constructor(name: string) { | ||
* this.name = name; | ||
* } | ||
* | ||
* readonly name: string; | ||
* | ||
* get pings(): IStream<this, string> { | ||
* return this._pings; | ||
* } | ||
* | ||
* ping(value: string) { | ||
* this._pings.emit(value); | ||
* } | ||
* | ||
* private _pings = new Stream<this, string>(this); | ||
* } | ||
* | ||
* let m1 = new SomeClass('foo'); | ||
* | ||
* m1.pings.connect((_, value: string) => { | ||
* console.log('connect', value); | ||
* }); | ||
* | ||
* void (async () => { | ||
* for await (const ping of m1.pings) { | ||
* console.log('iterator', ping); | ||
* } | ||
* })(); | ||
* | ||
* m1.ping('alpha'); // logs: connect alpha | ||
* // logs: iterator alpha | ||
* m1.ping('beta'); // logs: connect beta | ||
* // logs: iterator beta | ||
* ``` | ||
*/ | ||
export class Stream<T, U> extends Signal<T, U> implements IStream<T, U> { | ||
/** | ||
* Return an async iterator that yields every emission. | ||
*/ | ||
async *[Symbol.asyncIterator](): AsyncIterableIterator<U> { | ||
let pending = this._pending; | ||
while (true) { | ||
try { | ||
const { args, next } = await pending.promise; | ||
pending = next; | ||
yield args; | ||
} catch (_) { | ||
return; // Any promise rejection stops the iterator. | ||
} | ||
} | ||
} | ||
/** | ||
* Emit the signal, invoke the connected slots, and yield the emission. | ||
* | ||
* @param args - The args to pass to the connected slots. | ||
*/ | ||
emit(args: U): void { | ||
if (!this.blocked) { | ||
const pending = this._pending; | ||
const next = (this._pending = new PromiseDelegate()); | ||
pending.resolve({ args, next }); | ||
super.emit(args); | ||
} | ||
} | ||
/** | ||
* Stop the stream's async iteration. | ||
*/ | ||
stop(): void { | ||
this._pending.promise.catch(() => undefined); | ||
this._pending.reject('stop'); | ||
this._pending = new PromiseDelegate(); | ||
} | ||
private _pending: Private.Pending<U> = new PromiseDelegate(); | ||
} | ||
/** | ||
* The namespace for the module implementation details. | ||
@@ -301,2 +449,7 @@ */ | ||
/** | ||
* A pending promise in a promise chain underlying a stream. | ||
*/ | ||
export type Pending<U> = PromiseDelegate<{ args: U; next: Pending<U> }>; | ||
/** | ||
* The signal exception handler function. | ||
@@ -535,2 +688,6 @@ */ | ||
export function emit<T, U>(signal: Signal<T, U>, args: U): void { | ||
if (Private.blockedProperty.get(signal.sender) > 0) { | ||
return; | ||
} | ||
// If there are no receivers, there is nothing to do. | ||
@@ -676,2 +833,10 @@ let receivers = receiversForSender.get(signal.sender); | ||
} | ||
/** | ||
* A property indicating a sender has been blocked if its value is not 0. | ||
*/ | ||
export const blockedProperty = new AttachedProperty<unknown, number>({ | ||
name: 'blocked', | ||
create: () => 0 | ||
}); | ||
} |
@@ -23,2 +23,11 @@ /** | ||
/** | ||
* Block the signal during the execution of a callback. | ||
* | ||
* ### Notes | ||
* The callback function must be synchronous. | ||
* | ||
* @param fn The callback during which the signal is blocked | ||
*/ | ||
block(fn: () => void): void; | ||
/** | ||
* Connect a slot to the signal. | ||
@@ -64,2 +73,7 @@ * | ||
/** | ||
* An object that is both a signal and an async iterable. | ||
*/ | ||
export interface IStream<T, U> extends ISignal<T, U>, AsyncIterable<U> { | ||
} | ||
/** | ||
* A concrete implementation of `ISignal`. | ||
@@ -125,2 +139,11 @@ * | ||
/** | ||
* Block the signal during the execution of a callback. | ||
* | ||
* ### Notes | ||
* The callback function must be synchronous. | ||
* | ||
* @param fn The callback during which the signal is blocked | ||
*/ | ||
block(fn: () => void): void; | ||
/** | ||
* Connect a slot to the signal. | ||
@@ -158,2 +181,6 @@ * | ||
emit(args: U): void; | ||
/** | ||
* If `blocked` is not `0`, the signal will not emit. | ||
*/ | ||
protected blocked: number; | ||
} | ||
@@ -165,2 +192,13 @@ /** | ||
/** | ||
* Block all signals emitted by an object during | ||
* the execution of a callback. | ||
* | ||
* ### Notes | ||
* The callback function must be synchronous. | ||
* | ||
* @param sender The signals sender | ||
* @param fn The callback during which all signals are blocked | ||
*/ | ||
function blockAll(sender: unknown, fn: () => void): void; | ||
/** | ||
* Remove all connections between a sender and receiver. | ||
@@ -241,1 +279,62 @@ * | ||
} | ||
/** | ||
* A concrete implementation of `IStream`. | ||
* | ||
* #### Example | ||
* ```typescript | ||
* import { IStream, Stream } from '@lumino/signaling'; | ||
* | ||
* class SomeClass { | ||
* | ||
* constructor(name: string) { | ||
* this.name = name; | ||
* } | ||
* | ||
* readonly name: string; | ||
* | ||
* get pings(): IStream<this, string> { | ||
* return this._pings; | ||
* } | ||
* | ||
* ping(value: string) { | ||
* this._pings.emit(value); | ||
* } | ||
* | ||
* private _pings = new Stream<this, string>(this); | ||
* } | ||
* | ||
* let m1 = new SomeClass('foo'); | ||
* | ||
* m1.pings.connect((_, value: string) => { | ||
* console.log('connect', value); | ||
* }); | ||
* | ||
* void (async () => { | ||
* for await (const ping of m1.pings) { | ||
* console.log('iterator', ping); | ||
* } | ||
* })(); | ||
* | ||
* m1.ping('alpha'); // logs: connect alpha | ||
* // logs: iterator alpha | ||
* m1.ping('beta'); // logs: connect beta | ||
* // logs: iterator beta | ||
* ``` | ||
*/ | ||
export declare class Stream<T, U> extends Signal<T, U> implements IStream<T, U> { | ||
/** | ||
* Return an async iterator that yields every emission. | ||
*/ | ||
[Symbol.asyncIterator](): AsyncIterableIterator<U>; | ||
/** | ||
* Emit the signal, invoke the connected slots, and yield the emission. | ||
* | ||
* @param args - The args to pass to the connected slots. | ||
*/ | ||
emit(args: U): void; | ||
/** | ||
* Stop the stream's async iteration. | ||
*/ | ||
stop(): void; | ||
private _pending; | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
175932
2407
3
24
+ Added@lumino/coreutils@2.2.0(transitive)
+ Added@lumino/properties@2.0.2(transitive)