/**
* @summary sdo
* @version 3.0.0
* @since 3.0.0
* @author Arian Khosravi <arian.khosravi@aofl.com>
*/
import {get} from '@aofl/object-utils';
import {Store} from './store'; // eslint-disable-line
import {storeInstance as defaultStoreInstance} from './instance';
const defineDecorators = Symbol('defineDecorators');
/**
* Sate Definition Object {Sdo} is a base class to define sub states of the store.
*
* @memberof module:@aofl/store
*/
class Sdo {
/**
* Creates an instance of Sdo.
* @param {Object} initialState
* @param {Store} [storeInstance=defaultStoreInstance]
*/
constructor(initialState, storeInstance = defaultStoreInstance) {
/* istanbul ignore next */
if (typeof this.constructor.namespace === 'undefined') {
throw new Error(`${this.constructor.name}: Missing static property namespace.`);
}
const proto = Object.getPrototypeOf(this);
const properties = Object.getOwnPropertyDescriptors(proto);
/** @type {String} */
this.namespace = this.constructor.namespace;
this.initialState = initialState;
this.storeInstance = storeInstance;
this[defineDecorators](properties);
}
/**
* @type {Object}
* @readonly
* @private
*/
get state() {
return this.storeInstance.getState()[this.namespace];
}
/**
* Commits state to store.
*
* @param {Object} state
*/
commit(state) {
this.storeInstance.commit(this.namespace, state);
}
/**
* Reset state to intital state
*/
reset() {
this.storeInstance.commit(this.namespace, this.constructor.initialState);
}
/**
* subscribe() register the callback function with registerCallback and returns
* the unsubscribe function.
*
* @param {Furtion} callback
* @return {Function}
*/
subscribe(callback) {
return this.storeInstance.subscribe(callback);
}
/**
* @private
* @param {Object} properties
*/
[defineDecorators](properties) {
for (const property in properties) {
/* istanbul ignore next */
if (!Object.hasOwnProperty.call(properties, property)) continue;
/* istanbul ignore next */
if (property === 'namespace') continue;
if (typeof properties[property].value === 'undefined' && typeof properties[property].set === 'undefined') {
const getFn = Reflect.get(properties[property], 'get');
Object.defineProperty(this, property, {
get: () => { // eslint-disable-line
const observedProperty = this.observedProperties[property];
let changed = false;
const state = this.storeInstance.getState();
const newValues = [];
for (let i = 0; i < observedProperty.keys.length; i++) {
const key = observedProperty.keys[i];
const value = observedProperty.values[i];
const newValue = get(state, key);
newValues.push(newValue);
if (value !== newValue) {
changed = true;
}
}
observedProperty.values = newValues;
if (changed) {
this.observedProperties[property].value = Reflect.apply(getFn, this, []);
}
return this.observedProperties[property].value;
}
});
}
}
}
}
export {
Sdo
};