Last active
June 21, 2021 19:20
-
-
Save gioragutt/d10b7118e75281774da6dad259ef4138 to your computer and use it in GitHub Desktop.
Example for my custom json parse/stringify reviver/replacer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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