Socket
Socket
Sign inDemoInstall

@furystack/utils

Package Overview
Dependencies
Maintainers
1
Versions
120
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@furystack/utils - npm Package Compare versions

Comparing version 5.0.0 to 6.0.0

18

esm/observable-value.d.ts
import type { Disposable } from './disposable.js';
import type { ValueObserverOptions } from './value-observer.js';
import { ValueObserver } from './value-observer.js';

@@ -13,2 +14,11 @@ /**

export type ValueChangeCallback<T> = (next: T) => void;
export type ObservableValueOptions<T> = {
/**
* Defines a custom compare function to determine if the value should be updated and the observers should be notified
* @param lastValue the last value
* @param nextValue the next value
* @returns if the value should be updated and the observers should be notified
*/
compare: (lastValue: T, nextValue: T) => boolean;
};
/**

@@ -46,6 +56,6 @@ * Defines an ObservableValue value object.

* @param callback The callback method that will be called on each change
* @param getLast Will call the callback with the last known value right after subscription
* @param options Additional ObservableValue options
* @returns The ValueObserver instance
*/
subscribe(callback: ValueChangeCallback<T>, getLast?: boolean): ValueObserver<T>;
subscribe(callback: ValueChangeCallback<T>, options?: ValueObserverOptions<T>): ValueObserver<T>;
/**

@@ -72,7 +82,9 @@ * The observer will unsubscribe from the Observable

getObservers(): readonly ValueObserver<T>[];
private readonly options;
/**
* @param initialValue Optional initial value
* @param options Additional options
*/
constructor(initialValue: T);
constructor(initialValue: T, options?: Partial<ObservableValueOptions<T>>);
}
//# sourceMappingURL=observable-value.d.ts.map

30

esm/observable-value.js

@@ -10,2 +10,3 @@ import { ValueObserver } from './value-observer.js';

}
const defaultComparer = (a, b) => a !== b;
/**

@@ -42,2 +43,4 @@ * Defines an ObservableValue value object.

this._isDisposed = true;
// @ts-expect-error getting currentValue after disposing is not allowed
this.currentValue = null;
}

@@ -49,14 +52,11 @@ observers = new Set();

* @param callback The callback method that will be called on each change
* @param getLast Will call the callback with the last known value right after subscription
* @param options Additional ObservableValue options
* @returns The ValueObserver instance
*/
subscribe(callback, getLast = false) {
subscribe(callback, options) {
if (this._isDisposed) {
throw new ObservableAlreadyDisposedError();
}
const observer = new ValueObserver(this, callback);
const observer = new ValueObserver(this, callback, options);
this.observers.add(observer);
if (getLast) {
callback(this.currentValue);
}
return observer;

@@ -90,7 +90,9 @@ }

}
if (this.currentValue !== newValue) {
if (this.options.compare(this.currentValue, newValue)) {
this.currentValue = newValue;
for (const subscription of this.observers) {
subscription.callback(newValue);
}
this.observers.forEach((observer) => {
if (observer.options?.filter?.(this.currentValue, newValue) !== false) {
observer.callback(newValue);
}
});
}

@@ -105,6 +107,12 @@ }

}
options;
/**
* @param initialValue Optional initial value
* @param options Additional options
*/
constructor(initialValue) {
constructor(initialValue, options) {
this.options = {
compare: defaultComparer,
...options,
};
this.currentValue = initialValue;

@@ -111,0 +119,0 @@ }

@@ -9,18 +9,8 @@ import { describe, it, expect, vi } from 'vitest';

const v = new ObservableValue(undefined);
const doneCallback = vi.fn();
v.subscribe(() => {
expect(v.getValue()).toBe(undefined);
doneCallback();
}, true);
expect(v).toBeInstanceOf(ObservableValue);
expect(doneCallback).toBeCalled();
expect(v.getValue()).toBe(undefined);
});
it('should be constructed with initial value', () => {
const v = new ObservableValue(1);
const doneCallback = vi.fn();
v.subscribe(() => {
expect(v.getValue()).toBe(1);
doneCallback();
}, true);
expect(doneCallback).toBeCalled();
expect(v.getValue()).toBe(1);
});

@@ -34,3 +24,3 @@ describe('Subscription callback', () => {

doneCallback();
}, false);
});
v.setValue(1);

@@ -41,3 +31,3 @@ v.setValue(1);

});
it('should be triggered only on change when getLast is false', () => {
it('should be triggered only on change', () => {
const v = new ObservableValue(1);

@@ -48,3 +38,3 @@ const doneCallback = vi.fn();

doneCallback();
}, false);
});
v.setValue(2);

@@ -126,3 +116,39 @@ expect(doneCallback).toBeCalledTimes(1);

});
describe('Custom Compare function', () => {
it('Should compare the values with the custom compare function', () => {
const v = new ObservableValue({ value: 2 }, {
compare: (a, b) => a.value !== b.value,
});
const onChange = vi.fn();
v.subscribe(onChange);
v.setValue({ value: 2 });
expect(v.getValue()).toEqual({ value: 2 });
expect(onChange).not.toBeCalled();
v.setValue({ value: 3 });
expect(v.getValue()).toEqual({ value: 3 });
expect(onChange).toBeCalledTimes(1);
expect(onChange).toBeCalledWith({ value: 3 });
v.setValue({ value: 3 });
expect(v.getValue()).toEqual({ value: 3 });
expect(onChange).toBeCalledTimes(1);
});
});
describe('Filtered subscriptions', () => {
it('should not trigger the callback if the filter returns false', () => {
const v = new ObservableValue({ shouldNotify: true, value: 1 });
const onChange = vi.fn();
v.subscribe(onChange, {
filter: (nextValue) => nextValue.shouldNotify,
});
v.setValue({ shouldNotify: false, value: 1 });
expect(onChange).not.toBeCalled();
v.setValue({ shouldNotify: false, value: 2 });
expect(onChange).not.toBeCalled();
expect(v.getValue()).toEqual({ shouldNotify: false, value: 2 });
v.setValue({ shouldNotify: true, value: 3 });
expect(onChange).toBeCalledTimes(1);
expect(onChange).toBeCalledWith({ shouldNotify: true, value: 3 });
});
});
});
//# sourceMappingURL=observable-value.spec.js.map
import type { Disposable } from './disposable.js';
import type { ObservableValue, ValueChangeCallback } from './observable-value.js';
export type ValueObserverOptions<T> = {
filter?: (nextValue: T, lastValue: T) => boolean;
};
/**

@@ -28,2 +31,3 @@ * Defines a generic ValueObserver instance

callback: ValueChangeCallback<T>;
readonly options?: ValueObserverOptions<T> | undefined;
/**

@@ -37,5 +41,6 @@ * Disposes the ValueObserver instance. Unsubscribes from the observable

* @param callback The callback that will be fired on change
* @param options Additional options
*/
constructor(observable: ObservableValue<T>, callback: ValueChangeCallback<T>);
constructor(observable: ObservableValue<T>, callback: ValueChangeCallback<T>, options?: ValueObserverOptions<T> | undefined);
}
//# sourceMappingURL=value-observer.d.ts.map

@@ -26,2 +26,3 @@ /**

callback;
options;
/**

@@ -37,8 +38,10 @@ * Disposes the ValueObserver instance. Unsubscribes from the observable

* @param callback The callback that will be fired on change
* @param options Additional options
*/
constructor(observable, callback) {
constructor(observable, callback, options) {
this.observable = observable;
this.callback = callback;
this.options = options;
}
}
//# sourceMappingURL=value-observer.js.map
{
"name": "@furystack/utils",
"version": "5.0.0",
"version": "6.0.0",
"description": "General utilities",

@@ -5,0 +5,0 @@ "type": "module",

@@ -10,9 +10,4 @@ import { describe, it, expect, vi } from 'vitest'

const v = new ObservableValue(undefined)
const doneCallback = vi.fn()
v.subscribe(() => {
expect(v.getValue()).toBe(undefined)
doneCallback()
}, true)
expect(v).toBeInstanceOf(ObservableValue)
expect(doneCallback).toBeCalled()
expect(v.getValue()).toBe(undefined)
})

@@ -22,9 +17,3 @@

const v = new ObservableValue(1)
const doneCallback = vi.fn()
v.subscribe(() => {
expect(v.getValue()).toBe(1)
doneCallback()
}, true)
expect(doneCallback).toBeCalled()
expect(v.getValue()).toBe(1)
})

@@ -40,3 +29,3 @@

doneCallback()
}, false)
})
v.setValue(1)

@@ -48,3 +37,3 @@ v.setValue(1)

it('should be triggered only on change when getLast is false', () => {
it('should be triggered only on change', () => {
const v = new ObservableValue(1)

@@ -56,3 +45,3 @@ const doneCallback = vi.fn()

doneCallback()
}, false)
})
v.setValue(2)

@@ -149,2 +138,49 @@ expect(doneCallback).toBeCalledTimes(1)

})
describe('Custom Compare function', () => {
it('Should compare the values with the custom compare function', () => {
const v = new ObservableValue(
{ value: 2 },
{
compare: (a, b) => a.value !== b.value,
},
)
const onChange = vi.fn()
v.subscribe(onChange)
v.setValue({ value: 2 })
expect(v.getValue()).toEqual({ value: 2 })
expect(onChange).not.toBeCalled()
v.setValue({ value: 3 })
expect(v.getValue()).toEqual({ value: 3 })
expect(onChange).toBeCalledTimes(1)
expect(onChange).toBeCalledWith({ value: 3 })
v.setValue({ value: 3 })
expect(v.getValue()).toEqual({ value: 3 })
expect(onChange).toBeCalledTimes(1)
})
})
describe('Filtered subscriptions', () => {
it('should not trigger the callback if the filter returns false', () => {
const v = new ObservableValue({ shouldNotify: true, value: 1 })
const onChange = vi.fn()
v.subscribe(onChange, {
filter: (nextValue) => nextValue.shouldNotify,
})
v.setValue({ shouldNotify: false, value: 1 })
expect(onChange).not.toBeCalled()
v.setValue({ shouldNotify: false, value: 2 })
expect(onChange).not.toBeCalled()
expect(v.getValue()).toEqual({ shouldNotify: false, value: 2 })
v.setValue({ shouldNotify: true, value: 3 })
expect(onChange).toBeCalledTimes(1)
expect(onChange).toBeCalledWith({ shouldNotify: true, value: 3 })
})
})
})
import type { Disposable } from './disposable.js'
import type { ValueObserverOptions } from './value-observer.js'
import { ValueObserver } from './value-observer.js'

@@ -18,2 +19,14 @@

export type ObservableValueOptions<T> = {
/**
* Defines a custom compare function to determine if the value should be updated and the observers should be notified
* @param lastValue the last value
* @param nextValue the next value
* @returns if the value should be updated and the observers should be notified
*/
compare: (lastValue: T, nextValue: T) => boolean
}
const defaultComparer = <T>(a: T, b: T) => a !== b
/**

@@ -52,2 +65,4 @@ * Defines an ObservableValue value object.

this._isDisposed = true
// @ts-expect-error getting currentValue after disposing is not allowed
this.currentValue = null
}

@@ -60,14 +75,11 @@ private observers: Set<ValueObserver<T>> = new Set()

* @param callback The callback method that will be called on each change
* @param getLast Will call the callback with the last known value right after subscription
* @param options Additional ObservableValue options
* @returns The ValueObserver instance
*/
public subscribe(callback: ValueChangeCallback<T>, getLast = false) {
public subscribe(callback: ValueChangeCallback<T>, options?: ValueObserverOptions<T>) {
if (this._isDisposed) {
throw new ObservableAlreadyDisposedError()
}
const observer = new ValueObserver<T>(this, callback)
const observer = new ValueObserver<T>(this, callback, options)
this.observers.add(observer)
if (getLast) {
callback(this.currentValue)
}
return observer

@@ -104,7 +116,9 @@ }

}
if (this.currentValue !== newValue) {
if (this.options.compare(this.currentValue, newValue)) {
this.currentValue = newValue
for (const subscription of this.observers) {
subscription.callback(newValue)
}
this.observers.forEach((observer) => {
if (observer.options?.filter?.(this.currentValue, newValue) !== false) {
observer.callback(newValue)
}
})
}

@@ -121,8 +135,15 @@ }

private readonly options: ObservableValueOptions<T>
/**
* @param initialValue Optional initial value
* @param options Additional options
*/
constructor(initialValue: T) {
constructor(initialValue: T, options?: Partial<ObservableValueOptions<T>>) {
this.options = {
compare: defaultComparer,
...options,
}
this.currentValue = initialValue
}
}
import type { Disposable } from './disposable.js'
import type { ObservableValue, ValueChangeCallback } from './observable-value.js'
export type ValueObserverOptions<T> = {
filter?: (nextValue: T, lastValue: T) => boolean
}
/**

@@ -38,2 +42,3 @@ * Defines a generic ValueObserver instance

* @param callback The callback that will be fired on change
* @param options Additional options
*/

@@ -43,3 +48,4 @@ constructor(

public callback: ValueChangeCallback<T>,
public readonly options?: ValueObserverOptions<T>,
) {}
}

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

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

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