@dependable/session
Version:
Save and restore @dependable/state to the session storage
62 lines (50 loc) • 1.57 kB
JavaScript
const objectToJSON = (value, cache) =>
Object.fromEntries(
Object.entries(value).map(([k, v]) => [k, toJSON(v, cache)])
);
const arrayToJSON = (value, cache) => value.map((item) => toJSON(item, cache));
const toJSON = (value, cache) => {
if (typeof value === "function") {
if (value.kind === "observable") {
const id = storeObservableInCache(value, cache);
return { $reference: id };
} else {
throw new Error(
"Observables can only contain JSON serializable data and other observables"
);
}
}
if (value && typeof value === "object") {
if (Array.isArray(value)) {
return arrayToJSON(value, cache);
} else {
return objectToJSON(value, cache);
}
}
return value;
};
const storeObservableInCache = (observable, cache) => {
let id = observable.id || observable.sessionId || cache.ids.get(observable);
if (!id) {
id = "$" + cache.nextId++;
cache.ids.set(observable, id);
}
if (!cache[id]) {
cache.observables[id] = toJSON(observable(), cache);
}
return id;
};
export const snapshotFromObservables = (observables, nextId = 0) => {
const cache = { nextId, ids: new Map(), observables: {} };
Array.from(observables)
.filter((subscribable) => subscribable.kind === "observable")
.sort((a, b) => {
if (a.id < b.id) return -1;
if (a.id > b.id) return 1;
return 0;
})
.forEach((subscribable) => {
storeObservableInCache(subscribable, cache);
});
return { nextId: cache.nextId, observables: cache.observables };
};