Skip to content

Instantly share code, notes, and snippets.

@gioragutt
Created June 22, 2021 19:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gioragutt/c0a3ae2391fb49e6487a183bf585520b to your computer and use it in GitHub Desktop.
Save gioragutt/c0a3ae2391fb49e6487a183bf585520b to your computer and use it in GitHub Desktop.
Boilerplate for extendable ES6/MobX compatible JSON replacer/reviver
import {isObservableMap, isObservableSet} from 'mobx';
interface Adapter {
is: (value: unknown) => boolean;
serialize: (value: any) => any;
deserialize: (value: any) => any;
}
const spread = (value: any) => [...value];
const adapters: Record<string, Adapter> = {
Set: {
is: value => value instanceof Set,
serialize: spread,
deserialize: value => new Set(value),
},
Map: {
is: value => value instanceof Map,
serialize: spread,
deserialize: value => new Map(value),
},
ObservableSet: {
is: isObservableSet,
serialize: spread,
deserialize: value => new Set(value),
},
ObservableMap: {
is: isObservableMap,
serialize: spread,
deserialize: value => new Map(value),
},
};
const adapterEntries = Object.entries(adapters);
function getAdapter(value: any) {
for (const [name, {is, serialize}] of adapterEntries) {
if (is(value)) {
return {name, serialize};
}
}
return undefined;
}
const DATA_TYPE_FIELD = '___jsonDataType';
function replacer(this: any, key: string, value: any): any {
if (typeof value !== 'object' || value === null) {
return value;
}
const adapterDesc = getAdapter(this[key]);
if (!adapterDesc) {
return value;
}
return {
[DATA_TYPE_FIELD]: adapterDesc.name,
value: adapterDesc.serialize(value),
};
}
function reviver(_key: string, value: any): any {
if (typeof value !== 'object' || value === null) {
return value;
}
const adapter = adapters[value[DATA_TYPE_FIELD]];
if (!adapter) {
return value;
}
return adapter.deserialize(value.value);
}
export function parseJsonWithCollections<T>(value: string): T {
return JSON.parse(value, reviver);
}
export function stringifyJsonWithCollections<T>(value: T, space?: string | number): string {
return JSON.stringify(value, replacer, space);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment