@atproto/lexicon
Version:
atproto Lexicon schema language library
94 lines (84 loc) • 2.32 kB
text/typescript
import { CID } from 'multiformats/cid'
import {
IpldValue,
JsonValue,
check,
ipldToJson,
jsonToIpld,
} from '@atproto/common-web'
import { BlobRef, jsonBlobRef } from './blob-refs'
export type LexValue =
| IpldValue
| BlobRef
| Array<LexValue>
| { [key: string]: LexValue }
export type RepoRecord = Record<string, LexValue>
// @NOTE avoiding use of check.is() here only because it makes
// these implementations slow, and they often live in hot paths.
export const lexToIpld = (val: LexValue): IpldValue => {
// walk arrays
if (Array.isArray(val)) {
return val.map((item) => lexToIpld(item))
}
// objects
if (val && typeof val === 'object') {
// convert blobs, leaving the original encoding so that we don't change CIDs on re-encode
if (val instanceof BlobRef) {
return val.original
}
// retain cids & bytes
if (CID.asCID(val) || val instanceof Uint8Array) {
return val
}
// walk plain objects
const toReturn = {}
for (const key of Object.keys(val)) {
toReturn[key] = lexToIpld(val[key])
}
return toReturn
}
// pass through
return val
}
export const ipldToLex = (val: IpldValue): LexValue => {
// map arrays
if (Array.isArray(val)) {
return val.map((item) => ipldToLex(item))
}
// objects
if (val && typeof val === 'object') {
// convert blobs, using hints to avoid expensive is() check
if (
(val['$type'] === 'blob' ||
(typeof val['cid'] === 'string' &&
typeof val['mimeType'] === 'string')) &&
check.is(val, jsonBlobRef)
) {
return BlobRef.fromJsonRef(val)
}
// retain cids, bytes
if (CID.asCID(val) || val instanceof Uint8Array) {
return val
}
// map plain objects
const toReturn = {}
for (const key of Object.keys(val)) {
toReturn[key] = ipldToLex(val[key])
}
return toReturn
}
// pass through
return val
}
export const lexToJson = (val: LexValue): JsonValue => {
return ipldToJson(lexToIpld(val))
}
export const stringifyLex = (val: LexValue): string => {
return JSON.stringify(lexToJson(val))
}
export const jsonToLex = (val: JsonValue): LexValue => {
return ipldToLex(jsonToIpld(val))
}
export const jsonStringToLex = (val: string): LexValue => {
return jsonToLex(JSON.parse(val))
}