Last active
June 5, 2017 17:30
-
-
Save quidmonkey/395da0b98b2136bdb38d3f769ca44bf8 to your computer and use it in GitHub Desktop.
Simple FSM Based on Redux.js Style of State Management - Features Timewarping
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { merge, mergeWith } from 'lodash-es'; | |
const history = []; // history of all states | |
let timePeriod = 0; // index for history, used to timewarp throughout the history | |
let state = Object.freeze({}); // current state | |
/** | |
* Recursively merges all objects, and overwrites | |
* all other values. | |
* @param {*} destObj Current state | |
* @param {*} srcVal Any value to be merged | |
* @return {*} Resolved value | |
*/ | |
export function customizer(destObj, srcVal) { | |
if (isObj(srcVal)) { | |
return merge(destObj, srcVal); | |
} else { | |
return srcVal; | |
} | |
} | |
/** | |
* Fast forward history by one iteration. | |
* @return {Object} History state | |
*/ | |
export function fastForwardTime() { | |
timePeriod = Math.min(history.length - 1, ++timePeriod); | |
return getHistory(timePeriod); | |
} | |
/** | |
* Freeze the new state to prevent mutations | |
* @param {Object} candidate New State candidate | |
* @return {Object} New Immutable State | |
*/ | |
export function freezeState(candidate) { | |
return Object.freeze(candidate); | |
} | |
/** | |
* Get the history for a specific time period | |
* @param {Number} period History index | |
* @return {*} History state | |
*/ | |
export function getHistory(period) { | |
return history[period]; | |
} | |
/** | |
* Get current state | |
* @return {Object} Current state | |
*/ | |
export function getState() { | |
return state; | |
} | |
/** | |
* Is a value an object? | |
* @param {*} val Any JavaScript value | |
* @return {Boolean} True, if value is an object; false, otherwise. | |
*/ | |
export function isObj(val) { | |
return typeof val === 'object' && !(val instanceof Array); | |
} | |
/** | |
* Timewarp function that sets the current time period | |
* to the present or most recent state | |
* @return {Object} Latest history state | |
*/ | |
export function presentTime() { | |
timePeriod = history.length - 1; | |
return getHistory(timePeriod); | |
} | |
/** | |
* Rewind history by one iteration | |
* @return {Object} History state | |
*/ | |
export function rewindTime() { | |
timePeriod = Math.max(0, --timePeriod); | |
return getHistory(timePeriod); | |
} | |
/** | |
* Set a new state | |
* @param {Object} newState New state to be merged | |
* @return {Object} New state candidate that has been merged with previous state | |
*/ | |
export function setState(newState) { | |
const candidate = mergeWith(state, newState, customizer); | |
state = freezeState(candidate); | |
history.push(state); | |
timePeriod = history.length - 1; | |
return state; | |
} | |
export default { | |
getState, | |
fastForwardTime, | |
presentTime, | |
rewindTime, | |
setState | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment