Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

mini-signals

Package Overview
Dependencies
Maintainers
1
Versions
17
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mini-signals - npm Package Compare versions

Comparing version 2.0.0-1 to 2.0.0-2

30

dist/mini-signals.d.ts
type CallBack<T extends any[]> = (...x: T) => void;
declare const MiniSignalSymbol: unique symbol;
declare const MINI_SIGNAL_KEY: unique symbol;
type MiniSignalNodeRef<T, S> = {
[MINI_SIGNAL_KEY]: Symbol;
} & {
__brand: S;
} & {
__type: T;
};
type MiniSignalNode<T extends any[]> = {

@@ -7,12 +14,13 @@ fn: CallBack<T>;

prev?: MiniSignalNode<T>;
[MiniSignalSymbol]?: symbol;
};
type MiniSignalRef<T extends any[], S extends any> = WeakRef<MiniSignalNode<T>> & S;
export declare class MiniSignal<T extends any[] = any[], S extends any = {
[MiniSignalSymbol]: true;
}> {
export declare class MiniSignal<T extends any[] = any[], S extends any = Symbol | string> {
/**
* A Symbol that is used to guarantee the uniqueness of the MiniSignal
* instance.
*/
private readonly _symbol;
private _refMap;
private _head?;
private _tail?;
private readonly symbol;
private dispatching;
private _dispatching;
hasListeners(): boolean;

@@ -26,7 +34,7 @@ /**

*/
add(fn: CallBack<T>): MiniSignalRef<T, S>;
add(fn: CallBack<T>): MiniSignalNodeRef<T, S>;
/**
* Remove binding object.
*/
detach(ref: MiniSignalRef<T, S>): this;
detach(sym: MiniSignalNodeRef<T, S>): this;
/**

@@ -39,3 +47,5 @@ * Detach all listeners.

private _addNode;
private _createRef;
protected _getRef(sym: MiniSignalNodeRef<T, S>): MiniSignalNode<T> | undefined;
}
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MiniSignal = void 0;
const MiniSignalSymbol = Symbol('MiniSignalSymbol');
const MINI_SIGNAL_KEY = Symbol('SIGNAL');
function isMiniSignalNodeRef(obj) {
return typeof obj === 'object' && MINI_SIGNAL_KEY in obj;
}
class MiniSignal {
constructor() {
/**
* A Symbol that is used to guarantee the uniqueness of the MiniSignal
* instance.
*/
this._symbol = Symbol('MiniSignal');
this._refMap = new WeakMap();
this._head = undefined;
this._tail = undefined;
this.symbol = Symbol('MiniSignal');
this.dispatching = false;
this._dispatching = false;
}
hasListeners() {
return !(this._head == null);
return this._head != null;
}

@@ -19,3 +27,3 @@ /**

dispatch(...args) {
if (this.dispatching) {
if (this._dispatching) {
throw new Error('MiniSignal#dispatch(): Signal already dispatching.');

@@ -26,3 +34,3 @@ }

return false;
this.dispatching = true;
this._dispatching = true;
while (node != null) {

@@ -32,3 +40,3 @@ node.fn(...args);

}
this.dispatching = false;
this._dispatching = false;
return true;

@@ -43,6 +51,3 @@ }

}
return this._addNode({
fn,
[MiniSignalSymbol]: this.symbol
});
return this._createRef(this._addNode({ fn }));
}

@@ -52,11 +57,13 @@ /**

*/
detach(ref) {
if (!(ref instanceof WeakRef)) {
throw new Error('MiniSignal#detach(): First arg must be a MiniSignalNode object.');
detach(sym) {
if (!isMiniSignalNodeRef(sym)) {
throw new Error('MiniSignal#detach(): First arg must be a MiniSignal listener reference.');
}
const node = ref.deref();
if (!node || !node[MiniSignalSymbol])
return this;
if (node[MiniSignalSymbol] !== this.symbol)
return this; // Error?
if (sym[MINI_SIGNAL_KEY] !== this._symbol) {
throw new Error('MiniSignal#detach(): MiniSignal listener does not belong to this MiniSignal.');
}
const node = this._refMap.get(sym);
if (!node)
return this; // already detached
this._refMap.delete(sym);
this._disconnectNode(node);

@@ -74,2 +81,3 @@ this._destroyNode(node);

this._head = this._tail = undefined;
this._refMap = new WeakMap();
while (n != null) {

@@ -84,3 +92,2 @@ this._destroyNode(n);

node.prev = undefined;
node[MiniSignalSymbol] = undefined;
}

@@ -108,3 +115,2 @@ _disconnectNode(node) {

}
node[MiniSignalSymbol] = undefined;
}

@@ -122,5 +128,13 @@ _addNode(node) {

}
return new WeakRef(node);
return node;
}
_createRef(node) {
const sym = { [MINI_SIGNAL_KEY]: this._symbol };
this._refMap.set(sym, node);
return sym;
}
_getRef(sym) {
return this._refMap.get(sym);
}
}
exports.MiniSignal = MiniSignal;

@@ -279,11 +279,11 @@ "use strict";

e.detach();
}).throws('MiniSignal#detach(): First arg must be a MiniSignalNode object.');
}).throws('MiniSignal#detach(): First arg must be a MiniSignal listener reference.');
(0, chai_1.expect)(() => {
// @ts-expect-error testing error
e.detach(1);
}).throws('MiniSignal#detach(): First arg must be a MiniSignalNode object.');
}).throws('MiniSignal#detach(): First arg must be a MiniSignal listener reference.');
(0, chai_1.expect)(() => {
// @ts-expect-error testing error
e.detach(bar);
}).throws('MiniSignal#detach(): First arg must be a MiniSignalNode object.');
}).throws('MiniSignal#detach(): First arg must be a MiniSignal listener reference.');
});

@@ -385,3 +385,5 @@ it('should only remove the event with the specified node', () => {

const binding = e.add(foo);
e2.detach(binding);
(0, chai_1.expect)(() => {
e2.detach(binding);
}).throws('MiniSignal#detach(): MiniSignal listener does not belong to this MiniSignal.');
(0, chai_1.expect)(e.hasListeners());

@@ -427,30 +429,115 @@ });

describe('Garbage Collection', () => {
it('should not leak memory', () => __awaiter(void 0, void 0, void 0, function* () {
const e = new mini_signals_1.MiniSignal();
const w = e.add(() => {
/* */
it('should clean up when signal is destroyed', () => __awaiter(void 0, void 0, void 0, function* () {
let e = new mini_signals_1.MiniSignal();
const eR = new WeakRef(e);
let fn = () => {
noop(e, w);
};
const fR = new WeakRef(fn);
const w = e.add(fn);
e.add(fn);
e.add(noop);
e.add(() => {
fn();
noop();
});
(0, chai_1.expect)(w.deref()).to.exist;
e.add(() => {
fn();
noop();
e.detach(w);
});
(0, chai_1.expect)(fR.deref()).to.exist;
e.dispatch();
(0, chai_1.expect)(w.deref()).to.exist;
// Removing references in this scope should mark nodes GC
fn = null;
e = null;
yield new Promise(resolve => setTimeout(resolve, 0));
global.gc();
(0, chai_1.expect)(fR.deref()).to.be.undefined;
(0, chai_1.expect)(eR.deref()).to.be.undefined;
// Only the node reference should be left
(0, chai_1.expect)(w).to.exist;
}));
it('should not leak memory after detach', () => __awaiter(void 0, void 0, void 0, function* () {
let e = new mini_signals_1.MiniSignal();
const eR = new WeakRef(e);
let fn = () => {
noop(e, fn);
};
const fR = new WeakRef(fn);
const w = e.add(fn);
fn = null;
(0, chai_1.expect)(fR.deref()).to.exist;
e.dispatch();
(0, chai_1.expect)(fR.deref()).to.exist;
e.detach(w);
yield new Promise(resolve => setTimeout(resolve, 0));
global.gc();
(0, chai_1.expect)(w.deref()).to.be.undefined;
(0, chai_1.expect)(fR.deref()).to.be.undefined;
// should not throw an error when detaching gc ref
e.detach(w);
(0, chai_1.expect)(eR.deref()).to.exist;
// Also cleans up the signal
e = null;
yield new Promise(resolve => setTimeout(resolve, 0));
global.gc();
(0, chai_1.expect)(eR.deref()).to.be.undefined;
// Only the node reference should be left
(0, chai_1.expect)(w).to.exist;
}));
it('can clean up after itself when using add', () => __awaiter(void 0, void 0, void 0, function* () {
const e = new mini_signals_1.MiniSignal();
const w = e.add(() => {
it('should not leak memory after detach all', () => __awaiter(void 0, void 0, void 0, function* () {
let e = new mini_signals_1.MiniSignal();
const eR = new WeakRef(e);
let fn = () => {
noop(e, fn);
};
const fR = new WeakRef(fn);
const w = e.add(fn);
fn = null;
(0, chai_1.expect)(fR.deref()).to.exist;
e.dispatch();
(0, chai_1.expect)(fR.deref()).to.exist;
e.detach(w);
yield new Promise(resolve => setTimeout(resolve, 0));
global.gc();
(0, chai_1.expect)(fR.deref()).to.be.undefined;
// should not throw an error when detaching gc ref
e.detachAll();
(0, chai_1.expect)(eR.deref()).to.exist;
// Also cleans up the signal
e = null;
yield new Promise(resolve => setTimeout(resolve, 0));
global.gc();
(0, chai_1.expect)(eR.deref()).to.be.undefined;
// Only the node reference should be left
(0, chai_1.expect)(w).to.exist;
}));
it('should clean up after itself when using add', () => __awaiter(void 0, void 0, void 0, function* () {
let e = new mini_signals_1.MiniSignal();
const eR = new WeakRef(e);
let w;
let fn = () => {
noop(e, w);
e.detach(w);
});
(0, chai_1.expect)(w.deref()).to.exist;
};
const fR = new WeakRef(fn);
w = e.add(fn);
fn = null;
(0, chai_1.expect)(fR.deref()).to.exist;
e.dispatch();
(0, chai_1.expect)(w.deref()).to.exist;
yield new Promise(resolve => setTimeout(resolve, 0));
global.gc();
(0, chai_1.expect)(w.deref()).to.be.undefined;
(0, chai_1.expect)(fR.deref()).to.be.undefined;
// Also cleans up the signal
e = null;
yield new Promise(resolve => setTimeout(resolve, 0));
global.gc();
(0, chai_1.expect)(eR.deref()).to.be.undefined;
// Only the node reference should be left
(0, chai_1.expect)(w).to.exist;
}));
});
});
function noop(...args) {
// empty
}

@@ -93,3 +93,3 @@ [mini-signals](../README.md) / [Exports](../modules.md) / MiniSignal

▸ `Private` **_addNode**(`node`): `MiniSignalRef`<`T`, `S`\>
▸ `Private` **_addNode**(`node`): `MiniSignalNodeRef`<`T`, `S`\>

@@ -104,3 +104,3 @@ #### Parameters

`MiniSignalRef`<`T`, `S`\>
`MiniSignalNodeRef`<`T`, `S`\>

@@ -155,3 +155,3 @@ #### Defined in

▸ **add**(`fn`): `MiniSignalRef`<`T`, `S`\>
▸ **add**(`fn`): `MiniSignalNodeRef`<`T`, `S`\>

@@ -168,3 +168,3 @@ Register a new listener.

`MiniSignalRef`<`T`, `S`\>
`MiniSignalNodeRef`<`T`, `S`\>

@@ -187,3 +187,3 @@ #### Defined in

| :------ | :------ |
| `ref` | `MiniSignalRef`<`T`, `S`\> |
| `ref` | `MiniSignalNodeRef`<`T`, `S`\> |

@@ -190,0 +190,0 @@ #### Returns

{
"name": "mini-signals",
"version": "2.0.0-1",
"version": "2.0.0-2",
"description": "signals, in TypeScript, fast",

@@ -49,15 +49,15 @@ "main": "dist/index.js",

"@types/mocha": "^10.0.1",
"@typescript-eslint/eslint-plugin": "^5.56.0",
"@typescript-eslint/eslint-plugin": "^5.57.0",
"benchmark": "^1.0.0",
"chai": "^4.3.7",
"chg": "^0.4.0",
"eslint": "^8.36.0",
"eslint": "^8.37.0",
"eslint-config-prettier": "^8.8.0",
"eslint-config-standard-with-typescript": "^34.0.1",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-n": "^15.6.1",
"eslint-plugin-n": "^15.7.0",
"eslint-plugin-promise": "^6.1.1",
"eventemitter3": "^5.0.0",
"mocha": "^10.2.0",
"np": "^7.6.4",
"np": "^7.7.0",
"npm-check": "^6.0.1",

@@ -69,3 +69,3 @@ "npm-run-all": "^4.1.5",

"ts-node": "^10.9.1",
"tsd": "^0.28.0",
"tsd": "^0.28.1",
"typedoc": "^0.23.28",

@@ -72,0 +72,0 @@ "typedoc-plugin-markdown": "^3.14.0",

@@ -13,3 +13,3 @@ # mini-signals

> Note: Signals here are the type defined by [js-signals](https://github.com/millermedeiros/js-signals) inspired by AS3-Signals. They should not to be confused with [SolidJS](https://www.solidjs.com/tutorial/introduction_signals) or Angular signals.
> Note: Signals here are the type defined by Miller Medeiros in [js-signals](https://github.com/millermedeiros/js-signals) inspired by AS3-Signals. They should not to be confused with [SolidJS](https://www.solidjs.com/tutorial/introduction_signals) or [Angular signals](https://github.com/angular/angular/discussions/49090).

@@ -23,9 +23,9 @@ ## mini-signals 2.0.0

- `.add` now returns a weak node reference which can be used to remove the listener directly from the signal. Reduces memory leaks.
- `.add` is now type safe. The type of the listener is checked against the type variable in the constructor.
- `.add` is now type safe. The type of the listener is checked against the type variable in the constructor as well as an optional "flavor".
Breaking changes:
- `.add` now returns a node reference instead of a object, which had a `detach` method. The node reference can be used to remove the listener directly from the signal.
- `.once` has been removed. Use `.add` instead with a call to `.detach` in the listener.
- The `thisArg` parameter has been removed from `.add`. Use `.add` with a call to `.bind` or use an arrow function with a closure.
- `.add` now returns a node reference instead of a object. The returned node cannot be removed directly; it must be from the signal using `MiniSignal#detach`.
- `.once` has been removed. Use `.add` instead with a call to `.detach` in the callback.
- The `thisArg` parameter has been removed from `.add`. Use `.add` with a call to `.bind` or (preferred) use an arrow function with a closure.
- `.dispatch` now throws an error if the signal is already dispatching.

@@ -63,3 +63,3 @@

foo: "bar",
updated: new MiniSignal<never, typeof myObject>() // in this case the type variable is never, since we are not passing any parameters
updated: new MiniSignal<never>() // in this case the type variable is never, since we are not passing any parameters
};

@@ -69,5 +69,4 @@

console.log('signal dispatched');
assert(this === myObject);
assert(this.foo === 'baz');
}, myObject); // add listener with context
assert(myObject.foo === 'baz');
});

@@ -74,0 +73,0 @@ myObject.foo = 'baz';

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc