hyperflow
Version:
A javascript state flow and mutation management toolkit & library for developing universal app.
218 lines (206 loc) • 7.56 kB
JavaScript
/**
* Copyright 2015-present Tuan Le.
*
* Licensed under the MIT License.
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://opensource.org/licenses/mit-license.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*------------------------------------------------------------------------
*
* @module StateMutationComposite
* @description - A persistent state mutation with reducer/reconfigurator composite module.
*
* @author Tuan Le (tuan.t.lei@gmail.com)
*
* @flow
*/
'use strict'; // eslint-disable-line
import CommonElement from '../../elements/common-element';
import CompositeElement from '../../elements/composite-element';
/* factory Ids */
import {
SERVICE_FACTORY_CODE,
STORE_FACTORY_CODE
} from '../factory-code';
const Hf = CommonElement();
export default CompositeElement({
template: {
/**
* @description - Initialized and check that factory is valid for this composite.
*
* @method $initStateMutationComposite
* @return void
*/
$initStateMutationComposite () {
const factory = this;
if (Hf.DEVELOPMENT) {
if (!Hf.isSchema({
fId: `string`,
name: `string`,
outgoing: `function`,
reduceState: `function`,
reconfigState: `function`,
getStateAsObject: `function`
}).of(factory) || !(factory.fId.substr(0, SERVICE_FACTORY_CODE.length) === SERVICE_FACTORY_CODE ||
factory.fId.substr(0, STORE_FACTORY_CODE.length) === STORE_FACTORY_CODE)) {
Hf.log(`error`, `StateMutationComposite.$init - Factory is invalid. Cannot apply composite.`);
}
}
},
/**
* @description - Reset state to initial default.
*
* @method reset
* @param {object} option
* @return void
*/
// reset (option = {
// forceMutationEvent: false,
// suppressMutationEvent: false,
// delayMutationEvent: 0
// }) {
// const factory = this;
// const {
// forceMutationEvent,
// suppressMutationEvent,
// delayMutationEvent
// } = Hf.fallback({
// forceMutationEvent: false,
// suppressMutationEvent: false,
// delayMutationEvent: 0
// });
//
// // TODO: needs re-implementation
// },
/**
* @description - Reduce and update state on state change/mutation.
*
* @method reduce
* @param {object|function} reducer
* @param {object} option
* @return {boolean}
*/
reduce (reducer, option = {
forceMutationEvent: false,
suppressMutationEvent: false,
delayMutationEvent: 0
}) {
const factory = this;
const {
forceMutationEvent,
suppressMutationEvent,
delayMutationEvent
} = Hf.fallback({
forceMutationEvent: false,
suppressMutationEvent: false,
delayMutationEvent: 0
}).of(option);
const currentState = Hf.mix(factory.getStateAsObject(), {
exclusion: {
keys: [
`name`,
`fId`
]
}
}).with({});
let mutated = false;
if (Hf.isFunction(reducer)) {
mutated = factory.reduceState(reducer(currentState));
} else if (Hf.isObject(reducer)) {
mutated = factory.reduceState(reducer);
}
if (forceMutationEvent || (mutated && !suppressMutationEvent)) {
const newState = Hf.mix(factory.getStateAsObject(), {
exclusion: {
keys: [
`name`,
`fId`
]
}
}).with({});
const stateMutationEventId = !forceMutationEvent ? `as-state-mutated` : `as-state-forced-to-mutate`;
/* emitting a mutation event to interface */
if (delayMutationEvent > 0) {
factory.outgoing(
// `do-sync-reflected-state,
stateMutationEventId
).delay(delayMutationEvent).emit(() => newState);
} else {
factory.outgoing(
// `do-sync-reflected-state,
stateMutationEventId
).emit(() => newState);
}
}
return mutated;
},
/**
* @description - Reconfig and update state.
*
* @method reconfig
* @param {object|function} reconfigurator
* @param {object} option
* @return void
*/
reconfig (reconfigurator, option = {
forceMutationEvent: false,
suppressMutationEvent: false,
delayMutationEvent: 0
}) {
const factory = this;
const {
forceMutationEvent,
suppressMutationEvent,
delayMutationEvent
} = Hf.fallback({
forceMutationEvent: false,
suppressMutationEvent: false,
delayMutationEvent: 0
}).of(option);
const currentState = Hf.mix(factory.getStateAsObject(), {
exclusion: {
keys: [
`name`,
`fId`
]
}
}).with({});
if (Hf.isFunction(reconfigurator)) {
factory.reconfigState(reconfigurator(currentState));
} else if (Hf.isObject(reconfigurator)) {
factory.reconfigState(reconfigurator);
}
if (forceMutationEvent || !suppressMutationEvent) {
const newState = Hf.mix(factory.getStateAsObject(), {
exclusion: {
keys: [
`name`,
`fId`
]
}
}).with({});
const stateMutationEventId = !forceMutationEvent ? `as-state-mutated` : `as-state-forced-to-mutate`;
/* emitting a mutation event to interface */
if (delayMutationEvent > 0) {
factory.outgoing(
// `do-sync-reflected-state,
stateMutationEventId
).delay(delayMutationEvent).emit(() => newState);
} else {
factory.outgoing(
// `do-sync-reflected-state,
stateMutationEventId
).emit(() => newState);
}
}
}
}
});