state-switch
Version:
State Switch is a Change Monitor/Guarder for Async Actions.
134 lines • 4.64 kB
JavaScript
import { getLoggable } from 'brolog';
import { nop, isNop, } from '@pipeletteio/nop';
import { VERSION, } from './version.js';
import { StateSwitchEventEmitter, } from './events.js';
let COUNTER = 0;
export class StateSwitch extends StateSwitchEventEmitter {
_name;
_options;
_log;
_activePromise;
_inactivePromise;
_activeResolver;
_inactiveResolver;
_isActive;
_isPending;
constructor(_name = `StateSwitch#${COUNTER++}`, _options = {}) {
super();
this._name = _name;
this._options = _options;
this._log = getLoggable(_options.log);
this._log.verbose('StateSwitch', 'constructor(%s, "%s")', _name, JSON.stringify(_options));
this._isActive = false;
this._isPending = false;
/**
* for ready()
*/
this._activeResolver = nop;
this._inactiveResolver = nop;
this._activePromise = new Promise(resolve => {
this._activeResolver = resolve;
});
this._inactivePromise = Promise.resolve();
}
name() {
return this._name;
}
version() {
return VERSION;
}
active(state) {
/**
* Set
*/
if (state) {
this._log.verbose('StateSwitch', '<%s> active(%s) <- (%s)', this._name, state, this.active());
this._isActive = true;
this._isPending = (state === 'pending');
this.emit('active', state);
/**
* for stable()
*/
if (isNop(this._inactiveResolver)) {
this._inactivePromise = new Promise(resolve => (this._inactiveResolver = resolve));
}
if (state === true && !isNop(this._activeResolver)) {
this._activeResolver();
this._activeResolver = nop;
}
return;
}
/**
* Get
*/
const activeState = this._isActive
? this._isPending ? 'pending' : true
: false;
this._log.silly('StateSwitch', '<%s> active() is %s', this._name, activeState);
return activeState;
}
inactive(state) {
/**
* Set
*/
if (state) {
this._log.verbose('StateSwitch', '<%s> inactive(%s) <- (%s)', this._name, state, this.inactive());
this._isActive = false;
this._isPending = (state === 'pending');
this.emit('inactive', state);
/**
* for stable()
*/
if (isNop(this._activeResolver)) {
this._activePromise = new Promise(resolve => (this._activeResolver = resolve));
}
if (state === true && !isNop(this._inactiveResolver)) {
this._inactiveResolver();
this._inactiveResolver = nop;
}
return;
}
/**
* Get
*/
const inactiveState = !this._isActive
? this._isPending ? 'pending' : true
: false;
this._log.silly('StateSwitch', '<%s> inactive() is %s', this._name, inactiveState);
return inactiveState;
}
/**
* does the state is not stable(in process)?
*/
pending() {
this._log.silly('StateSwitch', '<%s> pending() is %s', this._name, this._isPending);
return this._isPending;
}
/**
* Wait the pending state to be stable.
*/
async stable(state, noCross = false) {
this._log.verbose('StateSwitch', '<%s> stable(%s, noCross=%s)', this._name, state, noCross);
if (typeof state === 'undefined') {
state = this._isActive ? 'active' : 'inactive';
}
if (state === 'active') {
if (this._isActive === false && noCross === true) {
throw new Error('stable(active) but the state is inactive. call stable(active, false) to disable noCross');
}
await this._activePromise;
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
}
else if (state === 'inactive') {
if (this._isActive === true && noCross === true) {
throw new Error('stable(inactive) but the state is active. call stable(inactive, false) to disable noCross');
}
await this._inactivePromise;
}
else {
throw new Error(`should not go here. ${state} should be of type 'never'`);
}
this._log.silly('StateSwitch', '<%s> stable(%s, %s) resolved.', this._name, state, noCross);
}
}
//# sourceMappingURL=state-switch.js.map