josonify
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
import { every, isString } from "lodash-es";
|
||||
import { symbol } from "zod";
|
||||
|
||||
type JsonifiableLite =
|
||||
string | number | boolean | bigint | null | undefined |
|
||||
Date | ArrayBuffer | SharedArrayBuffer | ArrayBufferView |
|
||||
JsonifiableLite[] | { [key: string]: JsonifiableLite };
|
||||
|
||||
export type Jsonifiable =
|
||||
JsonifiableLite |
|
||||
Jsonifiable[] |
|
||||
Map<JsonifiableLite, Jsonifiable> |
|
||||
Set<Jsonifiable> |
|
||||
{ jsonify(): Jsonifiable } |
|
||||
{ [key: string]: Jsonifiable };
|
||||
|
||||
export type Jsonified<T extends Jsonifiable> =
|
||||
T extends string ? string :
|
||||
T extends number ? number :
|
||||
T extends boolean ? boolean :
|
||||
T extends bigint ? string :
|
||||
T extends null ? null :
|
||||
T extends undefined ? undefined :
|
||||
T extends Date ? string :
|
||||
T extends ArrayBuffer ? string :
|
||||
T extends SharedArrayBuffer ? string :
|
||||
T extends ArrayBufferView ? string :
|
||||
T extends (infer K extends Jsonifiable)[] ? Jsonified<K>[] :
|
||||
T extends Map<infer K extends Jsonifiable, infer V extends Jsonifiable> ? (
|
||||
K extends string ? { [key in string]: Jsonified<V> } : [Jsonified<K>, Jsonified<V>][]) :
|
||||
T extends Set<infer V extends Jsonifiable> ? Jsonified<V>[] :
|
||||
T extends object ? (
|
||||
T extends { jsonify(): infer V extends Jsonifiable } ? Jsonified<V> : //HACK: jsonify()는 Jsonified여야 함
|
||||
{[key in keyof T]: Jsonified<T[key]>}): //FIXME: keyof T에 symbol을 받을 수 없어야 함
|
||||
T extends unknown ? unknown :
|
||||
never;
|
||||
|
||||
|
||||
/**
|
||||
* Convert any object to JSON-safe object
|
||||
*/
|
||||
export function jsonify<T extends Jsonifiable>(item: T): Jsonified<T> {
|
||||
if (typeof item === 'string' || typeof item === 'number' || typeof item === 'boolean') {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return item as any;
|
||||
}
|
||||
|
||||
if (typeof item === 'bigint') {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return item.toString() as any;
|
||||
}
|
||||
|
||||
if (item === undefined || item === null) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return item as any;
|
||||
}
|
||||
|
||||
if (item instanceof Date) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return item.toISOString() as any;
|
||||
}
|
||||
|
||||
if (item instanceof ArrayBuffer || item instanceof SharedArrayBuffer) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return Buffer.from(item).toString('base64') as any;
|
||||
}
|
||||
|
||||
if (ArrayBuffer.isView(item)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return Buffer.from(item.buffer, item.byteOffset, item.byteLength).toString('base64') as any;
|
||||
}
|
||||
|
||||
if (Array.isArray(item)) {
|
||||
//HACK: depth hack
|
||||
const result: Jsonified<string>[] = [];
|
||||
for (const v of item) {
|
||||
result.push(jsonify(v as string) as Jsonified<string>);
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return result as any;
|
||||
}
|
||||
|
||||
if (item instanceof Map) {
|
||||
//HACK: depth hack
|
||||
|
||||
const onlyStringKey = every(item.keys, isString);
|
||||
if (onlyStringKey) {
|
||||
const result: { [key: string]: Jsonified<string> } = {};
|
||||
for (const [k, v] of item.entries()) {
|
||||
result[k as string] = jsonify(v as string) as Jsonified<string>;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return result as any;
|
||||
}
|
||||
|
||||
const result: [Jsonified<string>, Jsonified<string>][] = [];
|
||||
for (const [k, v] of item.entries()) {
|
||||
result.push([jsonify(k as string), jsonify(v as string)] as [Jsonified<string>, Jsonified<string>]);
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return result as any;
|
||||
}
|
||||
|
||||
if (item instanceof Set) {
|
||||
const result: Jsonified<string>[] = [];
|
||||
for (const v of item.values()) {
|
||||
result.push(jsonify(v as string) as Jsonified<string>);
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return result as any;
|
||||
}
|
||||
|
||||
if (typeof item === 'object') {
|
||||
if (typeof (item as { jsonify(): unknown }).jsonify === 'function') {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return (item as { jsonify(): unknown }).jsonify() as any;
|
||||
}
|
||||
|
||||
const result: { [key: string]: Jsonified<string> } = {};
|
||||
for (const [k, v] of Object.entries(item)) {
|
||||
if (typeof k !== 'string') {
|
||||
continue;
|
||||
}
|
||||
if (typeof v === 'function') {
|
||||
continue;
|
||||
}
|
||||
result[k] = jsonify(v as string) as Jsonified<string>;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return result as any;
|
||||
}
|
||||
|
||||
throw new Error(`jsonify: invalid type ${typeof item}`);
|
||||
}
|
||||
Reference in New Issue
Block a user