UNPKG

@clynn-fe/akfe-editor-jsonf

Version:

JSON methods support function parse and stringify

111 lines (104 loc) 3.62 kB
import { EInfinityString, ETypeStrings, LeFE_Prefix, Segment } from './defines' import { isArray, isBigInt, isDate, isFunction, isMap, isNaN, isNegativeInfinity, isObject, isPositiveInfinity, isSet, isSymbol, isUndefined, TAnyFunction } from './type_detectors' import { blockSelfToJSON, shouldBlockSelfToJSON } from './utils' const assemble = (type: string, data?: string) => `${LeFE_Prefix}${Segment}${type}${data ? Segment + data : ''}` const isTypesNeededTraverse = ( val: unknown ): val is unknown[] | Record<string, unknown> => isArray(val) || (isObject(val) && !isDate(val) && !isSet(val) && !isMap(val)) const isArrowFunction = (str: string) => { // TODO: 这块判断有点不太好,后期考虑一下,搞个完善的正则什么的 const arr = str.split('=>') if (arr.length === 1) { // 只有一项说明字符串里没有 =>, 肯定不是箭头函数 return false } const part1 = arr[0].trim() // 取 => 前面的部分 if (part1.startsWith('(') && part1.endsWith(')')) { // 如果这一部分是 (...) 的话,认为是箭头函数,排除这种: function () { return () => {} } return true } // 如果不是 (....), 那只能是单独是形参变量名,不可能包含 {, 排除这种: function () { return a => {} }, 保住这种 a => {} return part1.indexOf('{') === -1 } const functionStringify = (func: TAnyFunction) => { const str = func.toString() if ( str.startsWith('function') || str.startsWith('async function') || isArrowFunction(str) ) { return str } // 这个是为了处理方法,如 { test () {} } return str.startsWith('async') ? `async function ${str.slice(6)}` : `function ${str}` } const needNotTraverseHandler = (val: unknown) => { switch (true) { case isUndefined(val): return assemble(ETypeStrings.undefined) case isNegativeInfinity(val): return assemble(ETypeStrings.Infinity, EInfinityString.negative) case isPositiveInfinity(val): return assemble(ETypeStrings.Infinity, EInfinityString.positive) case isNaN(val): return assemble(ETypeStrings.NaN) case isBigInt(val): return assemble(ETypeStrings.BigInt, (val as bigint).toString()) case isSymbol(val): // TODO: 辣鸡 TS 有 Bug, 目前不支持 symbol.prototype.description 属性。 // 请关注官方 Release, 支持了以后升级改掉这个 any 类型声明。 return assemble(ETypeStrings.Symbol, (val as any).description) case isFunction(val): return assemble( ETypeStrings.Function, functionStringify(val as TAnyFunction) ) case isDate(val): return assemble(ETypeStrings.Date, `${(val as Date).getTime()}`) case isMap(val): return assemble( ETypeStrings.Map, stringify(Array.from((val as Map<unknown, unknown>).entries())) ) case isSet(val): return assemble(ETypeStrings.Set, stringify([...(val as Set<unknown>)])) default: return val } } export const stringify = (data: Record<string, unknown> | unknown[]): string => JSON.stringify(data, (key: string, val: unknown) => { if (!isTypesNeededTraverse(val)) { return needNotTraverseHandler(val) } else { return isObject(val) ? Object.entries(val).reduce( (prev, [k, v]) => Object.assign(prev, { [k]: shouldBlockSelfToJSON(v) ? blockSelfToJSON(v) : v }), {} ) : val.map(item => shouldBlockSelfToJSON(item) ? blockSelfToJSON(item) : item ) } })