Skip to content

Commit 66682df

Browse files
committed
chore: add links, tree and get APIs to Block
1 parent 70cd8ce commit 66682df

File tree

1 file changed

+97
-1
lines changed

1 file changed

+97
-1
lines changed

src/block.js

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// @ts-check
22

3-
import { createV1 } from './cid.js'
3+
import { createV1, asCID } from './cid.js'
44

55
/**
66
* @class
@@ -92,6 +92,102 @@ export class Block {
9292
return cid
9393
}
9494
}
95+
96+
links () {
97+
return links(this.data, [], this)
98+
}
99+
100+
tree () {
101+
return tree(this.data, [], this)
102+
}
103+
104+
/**
105+
* @param {string} path
106+
*/
107+
get (path) {
108+
return get(this.data, path.split('/').filter(Boolean), this)
109+
}
110+
}
111+
112+
/**
113+
* @template T
114+
* @param {T} source
115+
* @param {Array<string|number>} base
116+
* @param {BlockConfig} config
117+
* @returns {Iterable<[string, CID]>}
118+
*/
119+
const links = function * (source, base, config) {
120+
for (const [key, value] of Object.entries(source)) {
121+
const path = [...base, key]
122+
if (value != null && typeof value === 'object') {
123+
if (Array.isArray(value)) {
124+
for (const [index, element] of value.entries()) {
125+
const elementPath = [...path, index]
126+
const cid = asCID(element, config)
127+
if (cid) {
128+
yield [elementPath.join('/'), cid]
129+
} else if (typeof element === 'object') {
130+
yield * links(element, elementPath, config)
131+
}
132+
}
133+
} else {
134+
const cid = asCID(value, config)
135+
if (cid) {
136+
yield [path.join('/'), cid]
137+
} else {
138+
yield * links(value, path, config)
139+
}
140+
}
141+
}
142+
}
143+
}
144+
145+
/**
146+
* @template T
147+
* @param {T} source
148+
* @param {Array<string|number>} base
149+
* @param {BlockConfig} config
150+
* @returns {Iterable<string>}
151+
*/
152+
const tree = function * (source, base, config) {
153+
for (const [key, value] of Object.entries(source)) {
154+
const path = [...base, key]
155+
yield path.join('/')
156+
if (value != null && typeof value === 'object' && !asCID(value, config)) {
157+
if (Array.isArray(value)) {
158+
for (const [index, element] of value.entries()) {
159+
const elementPath = [...path, index]
160+
yield elementPath.join('/')
161+
if (typeof element === 'object' && !asCID(elementPath, config)) {
162+
yield * tree(element, elementPath, config)
163+
}
164+
}
165+
} else {
166+
yield * tree(value, path, config)
167+
}
168+
}
169+
}
170+
}
171+
172+
/**
173+
* @template T
174+
* @param {T} source
175+
* @param {string[]} path
176+
* @param {BlockConfig} config
177+
*/
178+
const get = (source, path, config) => {
179+
let node = source
180+
for (const [index, key] of path.entries()) {
181+
node = node[key]
182+
if (node == null) {
183+
throw new Error(`Object has no property at ${path.slice(0, index - 1).map(part => `[${JSON.stringify(part)}]`).join('')}`)
184+
}
185+
const cid = asCID(node, config)
186+
if (cid) {
187+
return { value: cid, remaining: path.slice(index).join('/') }
188+
}
189+
}
190+
return { value: node }
95191
}
96192

97193
/**

0 commit comments

Comments
 (0)