76 lines
1.5 KiB
JavaScript
76 lines
1.5 KiB
JavaScript
import * as I from 'immutable';
|
|
import immutablediff from 'immutablediff';
|
|
|
|
export class StateSynchronizer {
|
|
|
|
constructor(statefuls) {
|
|
this._state = I.Map();
|
|
this._statefuls = statefuls;
|
|
this.tick();
|
|
}
|
|
|
|
diff(previousState) {
|
|
// Take a pure JS diff.
|
|
const steps = immutablediff(
|
|
previousState,
|
|
this._state
|
|
).toJS();
|
|
if (0 === steps.length) {
|
|
return undefined;
|
|
}
|
|
return steps;
|
|
}
|
|
|
|
static forwardStep(step) {
|
|
const {path, op, value} = step;
|
|
const parts = path.split('/');
|
|
const [key] = parts.splice(1, 1);
|
|
const subpath = parts.join('/');
|
|
return [key, {
|
|
op,
|
|
path: subpath ? subpath : '/',
|
|
value,
|
|
}];
|
|
}
|
|
|
|
static isStepUpdate(step) {
|
|
return -1 !== ['add', 'replace'].indexOf(step.op);
|
|
}
|
|
|
|
patchState(patch) {
|
|
const stepMap = {};
|
|
for (const {op, path, value} of patch) {
|
|
const parts = path.split('/');
|
|
const [key] = parts.splice(1, 1);
|
|
if (!stepMap[key]) {
|
|
stepMap[key] = [];
|
|
}
|
|
const subpath = parts.join('/');
|
|
stepMap[key].push({
|
|
op,
|
|
path: subpath ? subpath : '/',
|
|
value,
|
|
});
|
|
}
|
|
for (const key in stepMap) {
|
|
const stateful = this._statefuls[key];
|
|
if (!stateful) {
|
|
continue;
|
|
}
|
|
stateful.patchState(stepMap[key]);
|
|
}
|
|
}
|
|
|
|
get state() {
|
|
return this._state;
|
|
}
|
|
|
|
tick() {
|
|
for (const key in this._statefuls) {
|
|
const stateful = this._statefuls[key];
|
|
this._state = this._state.set(key, stateful.state);
|
|
}
|
|
}
|
|
|
|
}
|