UNPKG

@atproto/common-web

Version:

Shared web-platform-friendly code for atproto libraries

107 lines (100 loc) 2.66 kB
import { CID } from 'multiformats/cid' import * as ui8 from 'uint8arrays' export type JsonValue = | boolean | number | string | null | undefined | unknown | Array<JsonValue> | { [key: string]: JsonValue } export type IpldValue = | JsonValue | CID | Uint8Array | Array<IpldValue> | { [key: string]: IpldValue } // @NOTE avoiding use of check.is() here only because it makes // these implementations slow, and they often live in hot paths. export const jsonToIpld = (val: JsonValue): IpldValue => { // walk arrays if (Array.isArray(val)) { return val.map((item) => jsonToIpld(item)) } // objects if (val && typeof val === 'object') { // check for dag json values if (typeof val['$link'] === 'string' && Object.keys(val).length === 1) { return CID.parse(val['$link']) } if (typeof val['$bytes'] === 'string' && Object.keys(val).length === 1) { return ui8.fromString(val['$bytes'], 'base64') } // walk plain objects const toReturn = {} for (const key of Object.keys(val)) { toReturn[key] = jsonToIpld(val[key]) } return toReturn } // pass through return val } export const ipldToJson = (val: IpldValue): JsonValue => { // walk arrays if (Array.isArray(val)) { return val.map((item) => ipldToJson(item)) } // objects if (val && typeof val === 'object') { // convert bytes if (val instanceof Uint8Array) { return { $bytes: ui8.toString(val, 'base64'), } } // convert cids if (CID.asCID(val)) { return { $link: (val as CID).toString(), } } // walk plain objects const toReturn = {} for (const key of Object.keys(val)) { toReturn[key] = ipldToJson(val[key]) } return toReturn } // pass through return val as JsonValue } export const ipldEquals = (a: IpldValue, b: IpldValue): boolean => { // walk arrays if (Array.isArray(a) && Array.isArray(b)) { if (a.length !== b.length) return false for (let i = 0; i < a.length; i++) { if (!ipldEquals(a[i], b[i])) return false } return true } // objects if (a && b && typeof a === 'object' && typeof b === 'object') { // check bytes if (a instanceof Uint8Array && b instanceof Uint8Array) { return ui8.equals(a, b) } // check cids if (CID.asCID(a) && CID.asCID(b)) { return CID.asCID(a)?.equals(CID.asCID(b)) } // walk plain objects if (Object.keys(a).length !== Object.keys(b).length) return false for (const key of Object.keys(a)) { if (!ipldEquals(a[key], b[key])) return false } return true } return a === b }