UNPKG

merkle-reference

Version:

This is a TS library implementing [merkle reference] specification.

102 lines (97 loc) 3.04 kB
import * as Null from '../null.js' import * as StringType from '../string.js' import * as Boolean from '../boolean.js' import * as Integer from '../integer.js' import * as Float from '../float.js' import * as Bytes from '../bytes.js' import * as Map from './map.js' import * as List from './list.js' import * as Reference from '../reference.js' /** * JSON normalization function that does equivalent of `JSON.parse(JSON.stringify(value))` * * @param {unknown} value */ export const toJSON = (value) => { switch (value) { case Infinity: case -Infinity: return undefined default: { switch (typeof value) { case 'function': case 'undefined': case 'symbol': return undefined case 'number': return isNaN(/** @type {number} */ (value)) ? undefined : value case 'object': { if (value === null) { return null } else if (value instanceof Date) { return value.toISOString() } else if (value instanceof RegExp) { return {} } else if ( typeof (/** @type {{toJSON?:unknown}} */ (value)?.toJSON) === 'function' ) { return /** @type {{toJSON?:unknown}} */ (value).toJSON() } else if (value instanceof globalThis.String) { return `${value}` } else if (value instanceof globalThis.Boolean) { return value.valueOf() } else if (value instanceof globalThis.Number) { const num = value.valueOf() return isNaN(num) ? undefined : num } else { return value } } default: { return value } } } } } /** * @param {unknown} data * @param {import('../tree.js').Builder} builder * @returns {import('../tree.js').Node|import('../lib.js').Reference} */ export const toTree = (data, builder) => { // Apply toJSON normalization first (like JSONTraversal.entries does) const json = toJSON(data) // If top-level normalization results in undefined, the value is unrepresentable in JSON if (json === undefined) { throw new TypeError(`Unknown type ${globalThis.String(data)}`) } // Now determine type based on normalized value and handle traversal switch (typeof json) { case 'number': return Number.isInteger(json) ? Integer.toTree(json) : Float.toTree(json) case 'bigint': return Integer.toTree(json) case 'boolean': return Boolean.toTree(json) case 'string': return StringType.toTree(json) case 'object': { if (json === null) { return Null.toTree(json) } else if (Bytes.is(json)) { return Bytes.toTree(json) } else if (Array.isArray(json)) { return List.toTree(json, builder) } else if (Reference.is(json)) { return json } else { return Map.toTree(json, builder) } } default: { throw new TypeError(`Unknown type ${globalThis.String(json)}`) } } }