avocado-old/packages/state/synchronizer.js

70 lines
1.6 KiB
JavaScript
Raw Normal View History

2019-03-20 18:33:13 -05:00
import * as I from 'immutable';
import immutablediff from 'immutablediff';
export class StateSynchronizer {
constructor(statefuls) {
this._state = I.Map();
this._statefuls = statefuls;
this.tick();
2019-03-20 18:33:13 -05:00
}
acceptStateChange(change) {
for (const key in change) {
const stateful = this._statefuls[key];
if (!stateful) {
continue;
}
stateful.acceptStateChange(change[key]);
}
}
diff(previousState) {
2019-04-05 15:08:59 -05:00
// Take a pure JS diff.
const steps = immutablediff(previousState, this._state).toJS();
const updateSteps = steps.filter(StateSynchronizer.isStepUpdate);
return StateSynchronizer.hydratePathValues(updateSteps);
2019-03-20 18:33:13 -05:00
}
2019-04-05 15:08:59 -05:00
static hydratePathValues(pathValues) {
let accumulated = {};
for (const {path, value} of pathValues) {
if ('/' === path) {
accumulated = value;
}
else {
const parts = path.split('/');
parts.shift();
let walk = accumulated;
for (let i = 0; i < parts.length; ++i) {
const part = parts[i];
walk[part] = walk[part] || {};
if (i === parts.length - 1) {
walk[part] = value;
}
else {
walk = walk[part];
2019-03-20 18:33:13 -05:00
}
}
}
}
2019-04-05 15:08:59 -05:00
return accumulated;
}
static isStepUpdate(step) {
return -1 !== ['add', 'replace'].indexOf(step.op);
2019-03-20 18:33:13 -05:00
}
get state() {
2019-03-20 18:33:13 -05:00
return this._state;
}
tick() {
2019-03-20 18:33:13 -05:00
for (const key in this._statefuls) {
const stateful = this._statefuls[key];
2019-03-26 15:41:49 -05:00
this._state = this._state.set(key, stateful.state);
2019-03-20 18:33:13 -05:00
}
}
}