Skip to content

Commit 1b40e3e

Browse files
author
Alan Shaw
authored
feat: add dag-json resolver (#397)
Basically the same as `dag-cbor`...allows the exporter to `walkPath` and export `dag-json` encoded data.
1 parent 54de7bc commit 1b40e3e

File tree

4 files changed

+105
-0
lines changed

4 files changed

+105
-0
lines changed

packages/ipfs-unixfs-exporter/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@
136136
},
137137
"dependencies": {
138138
"@ipld/dag-cbor": "^9.0.0",
139+
"@ipld/dag-json": "^10.1.7",
139140
"@ipld/dag-pb": "^4.0.0",
140141
"@multiformats/murmur3": "^2.0.0",
141142
"err-code": "^3.0.1",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import * as dagJson from '@ipld/dag-json'
2+
import errCode from 'err-code'
3+
import { CID } from 'multiformats/cid'
4+
import type { Resolver } from '../index.js'
5+
6+
const resolve: Resolver = async (cid, name, path, toResolve, resolve, depth, blockstore, options) => {
7+
const block = await blockstore.get(cid, options)
8+
const object = dagJson.decode<any>(block)
9+
let subObject = object
10+
let subPath = path
11+
12+
while (toResolve.length > 0) {
13+
const prop = toResolve[0]
14+
15+
if (prop in subObject) {
16+
// remove the bit of the path we have resolved
17+
toResolve.shift()
18+
subPath = `${subPath}/${prop}`
19+
20+
const subObjectCid = CID.asCID(subObject[prop])
21+
if (subObjectCid != null) {
22+
return {
23+
entry: {
24+
type: 'object',
25+
name,
26+
path,
27+
cid,
28+
node: block,
29+
depth,
30+
size: BigInt(block.length),
31+
content: async function * () {
32+
yield object
33+
}
34+
},
35+
next: {
36+
cid: subObjectCid,
37+
name: prop,
38+
path: subPath,
39+
toResolve
40+
}
41+
}
42+
}
43+
44+
subObject = subObject[prop]
45+
} else {
46+
// cannot resolve further
47+
throw errCode(new Error(`No property named ${prop} found in dag-json node ${cid}`), 'ERR_NO_PROP')
48+
}
49+
}
50+
51+
return {
52+
entry: {
53+
type: 'object',
54+
name,
55+
path,
56+
cid,
57+
node: block,
58+
depth,
59+
size: BigInt(block.length),
60+
content: async function * () {
61+
yield object
62+
}
63+
}
64+
}
65+
}
66+
67+
export default resolve

packages/ipfs-unixfs-exporter/src/resolvers/index.ts

+3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import * as dagCbor from '@ipld/dag-cbor'
2+
import * as dagJson from '@ipld/dag-json'
23
import * as dagPb from '@ipld/dag-pb'
34
import errCode from 'err-code'
45
import * as raw from 'multiformats/codecs/raw'
56
import { identity } from 'multiformats/hashes/identity'
67
import dagCborResolver from './dag-cbor.js'
8+
import dagJsonResolver from './dag-json.js'
79
import identifyResolver from './identity.js'
810
import rawResolver from './raw.js'
911
import dagPbResolver from './unixfs-v1/index.js'
@@ -13,6 +15,7 @@ const resolvers: Record<number, Resolver> = {
1315
[dagPb.code]: dagPbResolver,
1416
[raw.code]: rawResolver,
1517
[dagCbor.code]: dagCborResolver,
18+
[dagJson.code]: dagJsonResolver,
1619
[identity.code]: identifyResolver
1720
}
1821

packages/ipfs-unixfs-exporter/test/exporter.spec.ts

+34
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* eslint-env mocha */
22

33
import * as dagCbor from '@ipld/dag-cbor'
4+
import * as dagJson from '@ipld/dag-json'
45
import * as dagPb from '@ipld/dag-pb'
56
import { expect } from 'aegir/chai'
67
import { MemoryBlockstore } from 'blockstore-core'
@@ -1008,6 +1009,39 @@ describe('exporter', () => {
10081009
return expect(first(exported.content())).to.eventually.deep.equal(node)
10091010
})
10101011

1012+
it('errors when exporting a non-existent key from a json node', async () => {
1013+
const node = {
1014+
foo: 'bar'
1015+
}
1016+
1017+
const jsonBlock = dagJson.encode(node)
1018+
const cid = CID.createV1(dagJson.code, await sha256.digest(jsonBlock))
1019+
await block.put(cid, jsonBlock)
1020+
1021+
try {
1022+
await exporter(`${cid}/baz`, block)
1023+
} catch (err: any) {
1024+
expect(err.code).to.equal('ERR_NO_PROP')
1025+
}
1026+
})
1027+
1028+
it('exports a json node', async () => {
1029+
const node = {
1030+
foo: 'bar'
1031+
}
1032+
1033+
const jsonBlock = dagJson.encode(node)
1034+
const cid = CID.createV1(dagJson.code, await sha256.digest(jsonBlock))
1035+
await block.put(cid, jsonBlock)
1036+
const exported = await exporter(`${cid}`, block)
1037+
1038+
if (exported.type !== 'object') {
1039+
throw new Error('Unexpected type')
1040+
}
1041+
1042+
return expect(first(exported.content())).to.eventually.deep.equal(node)
1043+
})
1044+
10111045
it('errors when exporting a node with no resolver', async () => {
10121046
const cid = CID.create(1, 0x78, CID.parse('zdj7WkRPAX9o9nb9zPbXzwG7JEs78uyhwbUs8JSUayB98DWWY').multihash)
10131047

0 commit comments

Comments
 (0)