UNPKG

@clynn-fe/akfe-editor-jsonf

Version:

JSON methods support function parse and stringify

147 lines (140 loc) 4.17 kB
import { EInfinityString, ETypeStrings, LeFE_Prefix, Segment, UndefinedReplacer } from './defines' import { isArray, isDate, isMap, isObject, isSet, isString } from './type_detectors' const parseReplaceString = (str: string) => { // 由于 dataString 里可能还有 Segment,这里的意思是只取前两个,剩下的,还给拼起来,留着下面用 const [, type, ...dataStringArr] = str.split(Segment) const dataString = dataStringArr.join(Segment) return { type, dataString } } const stringParse = (str: string, parse: (json: string) => any) => { if (str.startsWith(LeFE_Prefix)) { const { type, dataString } = parseReplaceString(str) switch (type) { // undefined 比较坑,这里不处理,最后遍历统一处理 // case ETypeStrings.undefined: // return undefined case ETypeStrings.Infinity: return dataString === EInfinityString.positive ? Infinity : -Infinity case ETypeStrings.NaN: return NaN case ETypeStrings.BigInt: try { return BigInt(dataString) } catch (error) { console.error(error) return BigInt(0) } case ETypeStrings.Symbol: return Symbol(dataString) case ETypeStrings.Function: try { return Function(`return ${dataString}`)() } catch (error) { console.error(error) return function placeholder() { console.warn('注意!该函数在 JSON 解析时出现错误。') } } case ETypeStrings.Date: return new Date(Number(dataString)) case ETypeStrings.Set: try { return new Set(parse(dataString)) } catch (error) { console.error(error) return new Set() } case ETypeStrings.Map: try { return new Map(parse(dataString)) } catch (error) { console.error(error) return new Map() } default: return str } } else { /* Start: 老 Function 逻辑兼容 */ if (str.startsWith('function')) { try { return Function(`return ${str}`)() } catch (error) { console.error(error) return function placeholder() { console.warn('注意!该函数在 JSON 解析时出现错误。') } } } /* End: 老 Function 逻辑兼容 */ return str } } const isTypesNeededTraverse = ( val: unknown ): val is unknown[] | Record<string, unknown> => (isObject(val) && !isDate(val) && !isSet(val) && !isMap(val)) || isArray(val) const needNotTraverseHandler = (val: unknown) => isString(val) ? stringParse(val, parse) : // 在无需遍历的类型中,除了 string 就是 boolean, number, null, 直接返回 val const undefinedHandler = ( val: unknown[] | Record<string, unknown> ): unknown[] | Record<string, unknown> => isObject(val) ? Object.entries(val).reduce((prev, [k, v]) => { if (isTypesNeededTraverse(v)) { return Object.assign(prev, { [k]: undefinedHandler(v) }) } else { const { type } = isString(v) && v.startsWith(LeFE_Prefix) ? parseReplaceString(v) : { type: '' } return Object.assign(prev, { [k]: type === ETypeStrings.undefined || v === UndefinedReplacer ? undefined : v }) } }, {}) : val.map(item => { if (isTypesNeededTraverse(item)) { return undefinedHandler(item) } else { const { type } = isString(item) && item.startsWith(LeFE_Prefix) ? parseReplaceString(item) : { type: '' } return type === ETypeStrings.undefined ? undefined : item } }) export const parse = (json: string): any => { const result = JSON.parse(json, (key: string, val: string) => { return !isTypesNeededTraverse(val) ? needNotTraverseHandler(val) : val }) return undefinedHandler(result) }