Skip to content

Commit 2043975

Browse files
committed
feat!: CID as an interface
This is an attempt at implementing #203, converting the CID class into a minimal interface and having factory functions to return objects that conform to the CID interface. I've preserved all the generics the `Link` interface introduced and there are functions in `link.js` that add the extra methods to turn something that conforms to `CID` into something that can be used as a `Link` so existing code using the `Link` API should not have to change. Notably there was no need to update any of the `Link` tests. The static methods on CID have been exported as individual functions - the names remain the same (`decode`, `parse`, etc) in an attempt to be less disruptive. Code using these methods should mostly just need to change: ```js import { CID } from 'multiformats/cid' ``` to: ```js import * as CID from 'multiformats/cid ``` Types can be imported as: ```ts import type { CID } from 'multiformats/interface' ``` or as before: ```ts import type { CID } from 'multiformats/cid' ``` BREAKING CHANGE: the CID class is now an interface
1 parent 0ec751a commit 2043975

14 files changed

+573
-470
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ This library defines common interfaces and low level building blocks for various
3636
This library provides implementations for most basics and many others can be found in linked repositories.
3737

3838
```js
39-
import { CID } from 'multiformats/cid'
39+
import * as CID from 'multiformats/cid'
4040
import * as json from 'multiformats/codecs/json'
4141
import { sha256 } from 'multiformats/hashes/sha2'
4242

src/block.js

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@ import { bytes as binary, CID } from './index.js'
22
// Linter can see that API is used in types.
33
// eslint-disable-next-line
44
import * as API from './interface.js'
5+
// Linter can see that API is used in types.
6+
// eslint-disable-next-line
7+
import * as CIDAPI from './cid/interface.js'
8+
// Linter can see that API is used in types.
9+
// eslint-disable-next-line
10+
import * as LinkAPI from './link/interface.js'
11+
import { asLink } from './link.js'
512

613
function readonly ({ enumerable = true, configurable = false } = {}) {
714
return { enumerable, configurable, writable: false }
@@ -10,7 +17,7 @@ function readonly ({ enumerable = true, configurable = false } = {}) {
1017
/**
1118
* @param {[string|number, string]} path
1219
* @param {any} value
13-
* @returns {Iterable<[string, CID]>}
20+
* @returns {Iterable<[string, CIDAPI.CID]>}
1421
*/
1522
function * linksWithin (path, value) {
1623
if (value != null && typeof value === 'object') {
@@ -39,7 +46,7 @@ function * linksWithin (path, value) {
3946
* @template T
4047
* @param {T} source
4148
* @param {Array<string|number>} base
42-
* @returns {Iterable<[string, CID]>}
49+
* @returns {Iterable<[string, CIDAPI.CID]>}
4350
*/
4451
function * links (source, base) {
4552
if (source == null || source instanceof Uint8Array) {
@@ -121,7 +128,7 @@ function get (source, path) {
121128
class Block {
122129
/**
123130
* @param {object} options
124-
* @param {CID<T, C, A, V>} options.cid
131+
* @param {LinkAPI.Link<T, C, A, V>} options.cid
125132
* @param {API.ByteView<T>} options.bytes
126133
* @param {T} options.value
127134
*/
@@ -176,14 +183,14 @@ async function encode ({ value, codec, hasher }) {
176183

177184
const bytes = codec.encode(value)
178185
const hash = await hasher.digest(bytes)
179-
/** @type {CID<T, Code, Alg, 1>} */
186+
/** @type {CIDAPI.CID<T, Code, Alg, 1>} */
180187
const cid = CID.create(
181188
1,
182189
codec.code,
183190
hash
184191
)
185192

186-
return new Block({ value, bytes, cid })
193+
return new Block({ value, bytes, cid: asLink(cid) })
187194
}
188195

189196
/**
@@ -194,18 +201,18 @@ async function encode ({ value, codec, hasher }) {
194201
* @param {API.ByteView<T>} options.bytes
195202
* @param {API.BlockDecoder<Code, T>} options.codec
196203
* @param {API.MultihashHasher<Alg>} options.hasher
197-
* @returns {Promise<API.BlockView<T, Code, Alg>>}
204+
* @returns {Promise<API.BlockView<T, Code, Alg, 1>>}
198205
*/
199206
async function decode ({ bytes, codec, hasher }) {
200207
if (!bytes) throw new Error('Missing required argument "bytes"')
201208
if (!codec || !hasher) throw new Error('Missing required argument: codec or hasher')
202209

203210
const value = codec.decode(bytes)
204211
const hash = await hasher.digest(bytes)
205-
/** @type {CID<T, Code, Alg, 1>} */
212+
/** @type {CIDAPI.CID<T, Code, Alg, 1>} */
206213
const cid = CID.create(1, codec.code, hash)
207214

208-
return new Block({ value, bytes, cid })
215+
return new Block({ value, bytes, cid: asLink(cid) })
209216
}
210217

211218
/**
@@ -229,8 +236,7 @@ function createUnsafe ({ bytes, cid, value: maybeValue, codec }) {
229236
if (value === undefined) throw new Error('Missing required argument, must either provide "value" or "codec"')
230237

231238
return new Block({
232-
// eslint-disable-next-line object-shorthand
233-
cid: /** @type {CID<T, Code, Alg, V>} */ (cid),
239+
cid,
234240
bytes,
235241
value
236242
})

src/block/interface.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* eslint-disable @typescript-eslint/no-unnecessary-type-constraint */
22
/* eslint-disable no-use-before-define */
33
import { Link, Version } from '../link/interface.js'
4-
import { CID } from '../cid.js'
4+
import { CID } from '../cid/interface.js'
55

66
/**
77
* A byte-encoded representation of some type of `Data`.
@@ -64,7 +64,7 @@ export interface BlockView<
6464
A extends number = number,
6565
V extends Version = 1
6666
> extends Block<T, C, A, V> {
67-
cid: CID<T, C, A, V>
67+
cid: Link<T, C, A, V>
6868
value: T
6969

7070
links: () => Iterable<[string, CID]>

0 commit comments

Comments
 (0)