typed-signals
Advanced tools
Comparing version
import { Collector } from "./Collector"; | ||
import { SignalConnection } from "./SignalConnection"; | ||
/** | ||
* Options for the connect method | ||
*/ | ||
export type ConnectOptions = { | ||
/** Handlers with a higher order value will be called later. */ | ||
order?: number; | ||
/** Handlers with isPublic=false will not be removed when signal.disconnectAll is called. Disconnect manually or via SignalConnections */ | ||
isPublic?: boolean; | ||
}; | ||
/** | ||
* A signal is a way to publish and subscribe to events. | ||
@@ -25,6 +34,6 @@ * | ||
* @param callback This callback will be run when emit() is called. | ||
* @param order Handlers with a higher order value will be called later. | ||
* @param options Configure options for the connection | ||
*/ | ||
connect(callback: THandler, order?: number): SignalConnection; | ||
private decrementConnectionCount; | ||
connect(callback: THandler, { order, isPublic }?: ConnectOptions): SignalConnection; | ||
private onUnlink; | ||
/** | ||
@@ -31,0 +40,0 @@ * Unsubscribe from this signal with the original callback instance. |
@@ -6,2 +6,4 @@ "use strict"; | ||
const SignalLink_1 = require("./SignalLink"); | ||
// eslint-disable-next-line @typescript-eslint/no-empty-function | ||
const headOptions = { order: 0, isPublic: true, onUnlink() { } }; | ||
/** | ||
@@ -14,6 +16,9 @@ * A signal is a way to publish and subscribe to events. | ||
constructor() { | ||
this.head = new SignalLink_1.SignalLink(); | ||
this.head = new SignalLink_1.SignalLink(null, null, headOptions); | ||
this.hasNewLinks = false; | ||
this.emitDepth = 0; | ||
this.connectionsCount = 0; | ||
this.onUnlink = () => { | ||
this.connectionsCount--; | ||
}; | ||
} | ||
@@ -36,7 +41,7 @@ /** | ||
* @param callback This callback will be run when emit() is called. | ||
* @param order Handlers with a higher order value will be called later. | ||
* @param options Configure options for the connection | ||
*/ | ||
connect(callback, order = 0) { | ||
connect(callback, { order = 0, isPublic = true } = {}) { | ||
this.connectionsCount++; | ||
const link = this.head.insert(callback, order); | ||
const link = this.head.insert({ callback, order, isPublic, onUnlink: this.onUnlink }); | ||
if (this.emitDepth > 0) { | ||
@@ -46,7 +51,4 @@ this.hasNewLinks = true; | ||
} | ||
return new SignalConnection_1.SignalConnectionImpl(link, () => this.decrementConnectionCount()); | ||
return new SignalConnection_1.SignalConnectionImpl(link); | ||
} | ||
decrementConnectionCount() { | ||
this.connectionsCount--; | ||
} | ||
/** | ||
@@ -61,3 +63,2 @@ * Unsubscribe from this signal with the original callback instance. | ||
if (link.callback === callback) { | ||
this.decrementConnectionCount(); | ||
link.unlink(); | ||
@@ -73,6 +74,9 @@ return true; | ||
disconnectAll() { | ||
while (this.head.next !== this.head) { | ||
this.head.next.unlink(); | ||
let { next } = this.head; | ||
while (next !== this.head) { | ||
if (next.isPublic) { | ||
next.unlink(); | ||
} | ||
next = next.next; | ||
} | ||
this.connectionsCount = 0; | ||
} | ||
@@ -79,0 +83,0 @@ /** |
@@ -23,8 +23,6 @@ import { SignalLink } from "./SignalLink"; | ||
private link; | ||
private parentCleanup; | ||
/** | ||
* @param link The actual link of the connection. | ||
* @param parentCleanup Callback to cleanup the parent signal when a connection is disconnected | ||
*/ | ||
constructor(link: SignalLink<THandler>, parentCleanup: () => void); | ||
constructor(link: SignalLink<THandler>); | ||
disconnect(): boolean; | ||
@@ -31,0 +29,0 @@ set enabled(enable: boolean); |
@@ -11,28 +11,16 @@ "use strict"; | ||
* @param link The actual link of the connection. | ||
* @param parentCleanup Callback to cleanup the parent signal when a connection is disconnected | ||
*/ | ||
constructor(link, parentCleanup) { | ||
constructor(link) { | ||
this.link = link; | ||
this.parentCleanup = parentCleanup; | ||
} | ||
disconnect() { | ||
if (this.link !== null) { | ||
this.link.unlink(); | ||
this.link = null; | ||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
this.parentCleanup(); | ||
this.parentCleanup = null; | ||
return true; | ||
} | ||
return false; | ||
return this.link.unlink(); | ||
} | ||
set enabled(enable) { | ||
if (this.link) | ||
this.link.setEnabled(enable); | ||
this.link.setEnabled(enable); | ||
} | ||
get enabled() { | ||
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain | ||
return this.link !== null && this.link.isEnabled(); | ||
return this.link.isEnabled(); | ||
} | ||
} | ||
exports.SignalConnectionImpl = SignalConnectionImpl; |
@@ -0,1 +1,7 @@ | ||
type SignalLinkOptions<THandler extends (...args: any[]) => any> = { | ||
order: number; | ||
isPublic: boolean; | ||
onUnlink(): void; | ||
callback?: THandler; | ||
}; | ||
/** | ||
@@ -11,8 +17,11 @@ * SignalLink implements a doubly-linked ring with nodes containing the signal handlers. | ||
prev: SignalLink<THandler>; | ||
callback: THandler | null; | ||
constructor(prev?: SignalLink<THandler> | null, next?: SignalLink<THandler> | null, order?: number); | ||
callback?: THandler; | ||
readonly isPublic: boolean; | ||
private onUnlink; | ||
constructor(prev: SignalLink<THandler> | null, next: SignalLink<THandler> | null, options: SignalLinkOptions<THandler>); | ||
isEnabled(): boolean; | ||
setEnabled(flag: boolean): void; | ||
unlink(): void; | ||
insert(callback: THandler, order: number): SignalLink<THandler>; | ||
unlink(): boolean; | ||
insert(options: SignalLinkOptions<THandler>): SignalLink<THandler>; | ||
} | ||
export {}; |
@@ -9,9 +9,11 @@ "use strict"; | ||
class SignalLink { | ||
constructor(prev = null, next = null, order = 0) { | ||
constructor(prev, next, options) { | ||
this.enabled = true; | ||
this.newLink = false; | ||
this.callback = null; | ||
this.prev = prev !== null && prev !== void 0 ? prev : this; | ||
this.next = next !== null && next !== void 0 ? next : this; | ||
this.order = order; | ||
this.order = options.order; | ||
this.isPublic = options.isPublic; | ||
this.callback = options.callback; | ||
this.onUnlink = options.onUnlink; | ||
} | ||
@@ -25,7 +27,13 @@ isEnabled() { | ||
unlink() { | ||
this.callback = null; | ||
this.next.prev = this.prev; | ||
this.prev.next = this.next; | ||
if (this.callback) { | ||
delete this.callback; | ||
this.next.prev = this.prev; | ||
this.prev.next = this.next; | ||
this.onUnlink(); | ||
return true; | ||
} | ||
return false; | ||
} | ||
insert(callback, order) { | ||
insert(options) { | ||
const { order } = options; | ||
let after = this.prev; | ||
@@ -37,4 +45,3 @@ while (after !== this) { | ||
} | ||
const link = new SignalLink(after, after.next, order); | ||
link.callback = callback; | ||
const link = new SignalLink(after, after.next, options); | ||
after.next = link; | ||
@@ -41,0 +48,0 @@ link.next.prev = link; |
{ | ||
"name": "typed-signals", | ||
"version": "2.5.0", | ||
"version": "3.0.0", | ||
"description": "A type checked signal library for TypeScript (and JavaScript)", | ||
@@ -43,16 +43,19 @@ "keywords": [ | ||
"devDependencies": { | ||
"@lusito/eslint-config": "^2.0.0", | ||
"@lusito/prettier-config": "^2.0.0", | ||
"@lusito/stylelint-config": "^2.0.0", | ||
"@types/jest": "^27.5.1", | ||
"@lusito/eslint-config": "^3.0.1", | ||
"@lusito/prettier-config": "^3.0.0", | ||
"@lusito/stylelint-config": "^3.0.0", | ||
"@types/jest": "^29.5.12", | ||
"copyfiles": "^2.4.1", | ||
"coveralls": "^3.1.1", | ||
"eslint-plugin-jest": "^26.3.0", | ||
"jest": "^28.1.0", | ||
"rimraf": "^3.0.2", | ||
"sort-package-json": "^1.57.0", | ||
"ts-jest": "^28.0.3", | ||
"typedoc": "0.22.15", | ||
"typescript": "^4.6.4" | ||
"eslint-plugin-jest": "^28.5.0", | ||
"jest": "^29.7.0", | ||
"rimraf": "^5.0.7", | ||
"sort-package-json": "^2.10.0", | ||
"ts-jest": "^29.1.3", | ||
"typedoc": "0.25.13", | ||
"typescript": "^5.4.5" | ||
}, | ||
"volta": { | ||
"node": "20.13.1" | ||
} | ||
} |
34466
0.83%628
2.45%