Skip to content

Instantly share code, notes, and snippets.

@gioragutt
Last active June 21, 2021 19:20
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/d10b7118e75281774da6dad259ef4138 to your computer and use it in GitHub Desktop.
Save gioragutt/d10b7118e75281774da6dad259ef4138 to your computer and use it in GitHub Desktop.
Example for my custom json parse/stringify reviver/replacer
import {isObservableMap, isObservableSet, observable} from 'mobx';
const DATA_TYPE_FIELD = '___jsonDataType';
function getCollectionTypeName(value: any): 'Set' | 'Map' | 'ObservableSet' | 'ObservableMap' | undefined {
if (isObservableMap(value)) {
return 'ObservableMap';
}
if (isObservableSet(value)) {
return 'ObservableSet';
}
if (value instanceof Map) {
return 'Map';
}
if (value instanceof Set) {
return 'Set';
}
return undefined;
}
function replacer(_key: string, value: any): any {
const collectionTypeName = getCollectionTypeName(value);
if (!collectionTypeName) {
return value;
}
return {
[DATA_TYPE_FIELD]: collectionTypeName,
value: [...value],
};
}
function reviver(_key: string, value: any): any {
if (typeof value !== 'object' || value === null) {
return value;
}
switch (value[DATA_TYPE_FIELD] as ReturnType<typeof getCollectionTypeName>) {
case 'ObservableMap':
return observable.map(value.value);
case 'ObservableSet':
return observable.set(value.value);
case 'Map':
return new Map(value.value);
case 'Set':
return new Set(value.value);
default:
return value;
}
}
export function parseJsonWithCollections<T>(value: string): T {
return JSON.parse(value, reviver);
}
export function stringifyJsonWithCollections<T>(value: T): string {
return JSON.stringify(value, replacer);
}
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, adapter] of adapterEntries) {
if (adapter.is(value)) {
return {name, adapter};
}
}
return undefined;
}
const DATA_TYPE_FIELD = '___jsonDataType';
function replaceField(value: any): any {
const adapterDesc = getAdapter(value);
if (!adapterDesc) {
return value;
}
return {
[DATA_TYPE_FIELD]: adapterDesc.name,
value: adapterDesc.adapter.serialize(value),
};
}
function replacer(_key: string, value: any): any {
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
return value;
}
return Object.fromEntries(
Object.entries(value).map(([fieldKey, fieldValue]) => [fieldKey, replaceField(fieldValue)]),
);
}
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