Skip to content

Commit 70145c7

Browse files
authored
feat: add name property to errors (#414)
Adds a `.name` property to all errors that can be used in a more ideomatic way than `.code`.
1 parent c345042 commit 70145c7

21 files changed

+210
-57
lines changed

packages/ipfs-unixfs-exporter/package.json

-1
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,6 @@
140140
"@ipld/dag-json": "^10.2.2",
141141
"@ipld/dag-pb": "^4.1.2",
142142
"@multiformats/murmur3": "^2.1.8",
143-
"err-code": "^3.0.1",
144143
"hamt-sharding": "^3.0.6",
145144
"interface-blockstore": "^5.3.0",
146145
"ipfs-unixfs": "^11.0.0",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
export class BadPathError extends Error {
2+
static name = 'BadPathError'
3+
static code = 'ERR_BAD_PATH'
4+
name = BadPathError.name
5+
code = BadPathError.code
6+
7+
constructor (message = 'Bad path') {
8+
super(message)
9+
}
10+
}
11+
12+
export class NotFoundError extends Error {
13+
static name = 'NotFoundError'
14+
static code = 'ERR_NOT_FOUND'
15+
name = NotFoundError.name
16+
code = NotFoundError.code
17+
18+
constructor (message = 'Not found') {
19+
super(message)
20+
}
21+
}
22+
23+
export class NoResolverError extends Error {
24+
static name = 'NoResolverError'
25+
static code = 'ERR_NO_RESOLVER'
26+
name = NoResolverError.name
27+
code = NoResolverError.code
28+
29+
constructor (message = 'No resolver') {
30+
super(message)
31+
}
32+
}
33+
34+
export class NotUnixFSError extends Error {
35+
static name = 'NotUnixFSError'
36+
static code = 'ERR_NOT_UNIXFS'
37+
name = NotUnixFSError.name
38+
code = NotUnixFSError.code
39+
40+
constructor (message = 'Not UnixFS') {
41+
super(message)
42+
}
43+
}
44+
45+
export class OverReadError extends Error {
46+
static name = 'OverReadError'
47+
static code = 'ERR_OVER_READ'
48+
name = OverReadError.name
49+
code = OverReadError.code
50+
51+
constructor (message = 'Over read') {
52+
super(message)
53+
}
54+
}
55+
56+
export class UnderReadError extends Error {
57+
static name = 'UnderReadError'
58+
static code = 'ERR_UNDER_READ'
59+
name = UnderReadError.name
60+
code = UnderReadError.code
61+
62+
constructor (message = 'Under read') {
63+
super(message)
64+
}
65+
}
66+
67+
export class NoPropError extends Error {
68+
static name = 'NoPropError'
69+
static code = 'ERR_NO_PROP'
70+
name = NoPropError.name
71+
code = NoPropError.code
72+
73+
constructor (message = 'No Property found') {
74+
super(message)
75+
}
76+
}
77+
78+
export class InvalidParametersError extends Error {
79+
static name = 'InvalidParametersError'
80+
static code = 'ERR_INVALID_PARAMS'
81+
name = InvalidParametersError.name
82+
code = InvalidParametersError.code
83+
84+
constructor (message = 'Invalid parameters') {
85+
super(message)
86+
}
87+
}

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

+6-4
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,18 @@
4545
* ```
4646
*/
4747

48-
import errCode from 'err-code'
4948
import last from 'it-last'
5049
import { CID } from 'multiformats/cid'
50+
import { BadPathError, NotFoundError } from './errors.js'
5151
import resolve from './resolvers/index.js'
5252
import type { PBNode } from '@ipld/dag-pb'
5353
import type { Bucket } from 'hamt-sharding'
5454
import type { Blockstore } from 'interface-blockstore'
5555
import type { UnixFS } from 'ipfs-unixfs'
5656
import type { ProgressOptions, ProgressEvent } from 'progress-events'
5757

58+
export * from './errors.js'
59+
5860
export interface ExportProgress {
5961
/**
6062
* How many bytes of the file have been read
@@ -361,7 +363,7 @@ const cidAndRest = (path: string | Uint8Array | CID): { cid: CID, toResolve: str
361363
}
362364
}
363365

364-
throw errCode(new Error(`Unknown path type ${path}`), 'ERR_BAD_PATH')
366+
throw new BadPathError(`Unknown path type ${path}`)
365367
}
366368

367369
/**
@@ -394,7 +396,7 @@ export async function * walkPath (path: string | CID, blockstore: ReadableStorag
394396
const result = await resolve(cid, name, entryPath, toResolve, startingDepth, blockstore, options)
395397

396398
if (result.entry == null && result.next == null) {
397-
throw errCode(new Error(`Could not resolve ${path}`), 'ERR_NOT_FOUND')
399+
throw new NotFoundError(`Could not resolve ${path}`)
398400
}
399401

400402
if (result.entry != null) {
@@ -441,7 +443,7 @@ export async function exporter (path: string | CID, blockstore: ReadableStorage,
441443
const result = await last(walkPath(path, blockstore, options))
442444

443445
if (result == null) {
444-
throw errCode(new Error(`Could not resolve ${path}`), 'ERR_NOT_FOUND')
446+
throw new NotFoundError(`Could not resolve ${path}`)
445447
}
446448

447449
return result

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import errCode from 'err-code'
21
import * as mh from 'multiformats/hashes/digest'
32
import { CustomProgressEvent } from 'progress-events'
3+
import { NotFoundError } from '../errors.js'
44
import extractDataFromBlock from '../utils/extract-data-from-block.js'
55
import validateOffsetAndLength from '../utils/validate-offset-and-length.js'
66
import type { ExporterOptions, Resolver, ExportProgress } from '../index.js'
@@ -28,7 +28,7 @@ const rawContent = (node: Uint8Array): ((options?: ExporterOptions) => AsyncGene
2828

2929
const resolve: Resolver = async (cid, name, path, toResolve, resolve, depth, blockstore, options) => {
3030
if (toResolve.length > 0) {
31-
throw errCode(new Error(`No link named ${path} found in raw node ${cid}`), 'ERR_NOT_FOUND')
31+
throw new NotFoundError(`No link named ${path} found in raw node ${cid}`)
3232
}
3333
const buf = mh.decode(cid.multihash.bytes)
3434

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import * as dagCbor from '@ipld/dag-cbor'
22
import * as dagJson from '@ipld/dag-json'
33
import * as dagPb from '@ipld/dag-pb'
4-
import errCode from 'err-code'
54
import * as json from 'multiformats/codecs/json'
65
import * as raw from 'multiformats/codecs/raw'
76
import { identity } from 'multiformats/hashes/identity'
7+
import { NoResolverError } from '../errors.js'
88
import dagCborResolver from './dag-cbor.js'
99
import dagJsonResolver from './dag-json.js'
1010
import identifyResolver from './identity.js'
@@ -26,7 +26,7 @@ const resolve: Resolve = async (cid, name, path, toResolve, depth, blockstore, o
2626
const resolver = resolvers[cid.code]
2727

2828
if (resolver == null) {
29-
throw errCode(new Error(`No resolver for code ${cid.code}`), 'ERR_NO_RESOLVER')
29+
throw new NoResolverError(`No resolver for code ${cid.code}`)
3030
}
3131

3232
return resolver(cid, name, path, toResolve, resolve, depth, blockstore, options)

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import errCode from 'err-code'
21
import { CustomProgressEvent } from 'progress-events'
2+
import { NotFoundError } from '../errors.js'
33
import extractDataFromBlock from '../utils/extract-data-from-block.js'
44
import validateOffsetAndLength from '../utils/validate-offset-and-length.js'
55
import type { ExporterOptions, Resolver, ExportProgress } from '../index.js'
@@ -27,7 +27,7 @@ const rawContent = (node: Uint8Array): ((options?: ExporterOptions) => AsyncGene
2727

2828
const resolve: Resolver = async (cid, name, path, toResolve, resolve, depth, blockstore, options) => {
2929
if (toResolve.length > 0) {
30-
throw errCode(new Error(`No link named ${path} found in raw node ${cid}`), 'ERR_NOT_FOUND')
30+
throw new NotFoundError(`No link named ${path} found in raw node ${cid}`)
3131
}
3232

3333
const block = await blockstore.get(cid, options)

packages/ipfs-unixfs-exporter/src/resolvers/unixfs-v1/content/file.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import * as dagPb from '@ipld/dag-pb'
2-
import errCode from 'err-code'
32
import { UnixFS } from 'ipfs-unixfs'
43
import map from 'it-map'
54
import parallel from 'it-parallel'
@@ -8,6 +7,7 @@ import { type Pushable, pushable } from 'it-pushable'
87
import * as raw from 'multiformats/codecs/raw'
98
import PQueue from 'p-queue'
109
import { CustomProgressEvent } from 'progress-events'
10+
import { NotUnixFSError, OverReadError, UnderReadError } from '../../../errors.js'
1111
import extractDataFromBlock from '../../../utils/extract-data-from-block.js'
1212
import validateOffsetAndLength from '../../../utils/validate-offset-and-length.js'
1313
import type { ExporterOptions, UnixfsV1FileContent, UnixfsV1Resolver, ReadableStorage, ExportProgress, ExportWalk } from '../../../index.js'
@@ -23,15 +23,15 @@ async function walkDAG (blockstore: ReadableStorage, node: dagPb.PBNode | Uint8A
2323
}
2424

2525
if (node.Data == null) {
26-
throw errCode(new Error('no data in PBNode'), 'ERR_NOT_UNIXFS')
26+
throw new NotUnixFSError('no data in PBNode')
2727
}
2828

2929
let file: UnixFS
3030

3131
try {
3232
file = UnixFS.unmarshal(node.Data)
3333
} catch (err: any) {
34-
throw errCode(err, 'ERR_NOT_UNIXFS')
34+
throw new NotUnixFSError(err.message)
3535
}
3636

3737
// might be a unixfs `raw` node or have data on intermediate nodes
@@ -47,7 +47,7 @@ async function walkDAG (blockstore: ReadableStorage, node: dagPb.PBNode | Uint8A
4747
const childOps: Array<{ link: dagPb.PBLink, blockStart: bigint }> = []
4848

4949
if (node.Links.length !== file.blockSizes.length) {
50-
throw errCode(new Error('Inconsistent block sizes and dag links'), 'ERR_NOT_UNIXFS')
50+
throw new NotUnixFSError('Inconsistent block sizes and dag links')
5151
}
5252

5353
for (let i = 0; i < node.Links.length; i++) {
@@ -98,7 +98,7 @@ async function walkDAG (blockstore: ReadableStorage, node: dagPb.PBNode | Uint8A
9898
child = block
9999
break
100100
default:
101-
queue.end(errCode(new Error(`Unsupported codec: ${link.Hash.code}`), 'ERR_NOT_UNIXFS'))
101+
queue.end(new NotUnixFSError(`Unsupported codec: ${link.Hash.code}`))
102102
return
103103
}
104104

@@ -171,7 +171,7 @@ const fileContent: UnixfsV1Resolver = (cid, node, unixfs, path, resolve, depth,
171171

172172
if (read > wanted) {
173173
queue.end()
174-
throw errCode(new Error('Read too many bytes - the file size reported by the UnixFS data in the root node may be incorrect'), 'ERR_OVER_READ')
174+
throw new OverReadError('Read too many bytes - the file size reported by the UnixFS data in the root node may be incorrect')
175175
}
176176

177177
if (read === wanted) {
@@ -188,7 +188,7 @@ const fileContent: UnixfsV1Resolver = (cid, node, unixfs, path, resolve, depth,
188188
}
189189

190190
if (read < wanted) {
191-
throw errCode(new Error('Traversed entire DAG but did not read enough bytes'), 'ERR_UNDER_READ')
191+
throw new UnderReadError('Traversed entire DAG but did not read enough bytes')
192192
}
193193
}
194194

packages/ipfs-unixfs-exporter/src/resolvers/unixfs-v1/content/hamt-sharded-directory.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { decode, type PBNode } from '@ipld/dag-pb'
2-
import errCode from 'err-code'
32
import { UnixFS } from 'ipfs-unixfs'
43
import map from 'it-map'
54
import parallel from 'it-parallel'
65
import { pipe } from 'it-pipe'
76
import { CustomProgressEvent } from 'progress-events'
7+
import { NotUnixFSError } from '../../../errors.js'
88
import type { ExporterOptions, Resolve, UnixfsV1DirectoryContent, UnixfsV1Resolver, ReadableStorage, ExportWalk } from '../../../index.js'
99

1010
const hamtShardedDirectoryContent: UnixfsV1Resolver = (cid, node, unixfs, path, resolve, depth, blockstore) => {
@@ -23,18 +23,18 @@ async function * listDirectory (node: PBNode, path: string, resolve: Resolve, de
2323
const links = node.Links
2424

2525
if (node.Data == null) {
26-
throw errCode(new Error('no data in PBNode'), 'ERR_NOT_UNIXFS')
26+
throw new NotUnixFSError('no data in PBNode')
2727
}
2828

2929
let dir: UnixFS
3030
try {
3131
dir = UnixFS.unmarshal(node.Data)
3232
} catch (err: any) {
33-
throw errCode(err, 'ERR_NOT_UNIXFS')
33+
throw new NotUnixFSError(err.message)
3434
}
3535

3636
if (dir.fanout == null) {
37-
throw errCode(new Error('missing fanout'), 'ERR_NOT_UNIXFS')
37+
throw new NotUnixFSError('missing fanout')
3838
}
3939

4040
const padLength = (dir.fanout - 1n).toString(16).length

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

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { decode, type PBNode } from '@ipld/dag-pb'
2-
import errCode from 'err-code'
32
import { UnixFS } from 'ipfs-unixfs'
3+
import { NotFoundError, NotUnixFSError } from '../../errors.js'
44
import findShardCid from '../../utils/find-cid-in-shard.js'
55
import contentDirectory from './content/directory.js'
66
import contentFile from './content/file.js'
@@ -39,14 +39,14 @@ const unixFsResolver: Resolver = async (cid, name, path, toResolve, resolve, dep
3939
}
4040

4141
if (node.Data == null) {
42-
throw errCode(new Error('no data in PBNode'), 'ERR_NOT_UNIXFS')
42+
throw new NotUnixFSError('no data in PBNode')
4343
}
4444

4545
try {
4646
unixfs = UnixFS.unmarshal(node.Data)
4747
} catch (err: any) {
4848
// non-UnixFS dag-pb node? It could happen.
49-
throw errCode(err, 'ERR_NOT_UNIXFS')
49+
throw new NotUnixFSError(err.message)
5050
}
5151

5252
if (path == null) {
@@ -64,7 +64,7 @@ const unixFsResolver: Resolver = async (cid, name, path, toResolve, resolve, dep
6464
}
6565

6666
if (linkCid == null) {
67-
throw errCode(new Error('file does not exist'), 'ERR_NOT_FOUND')
67+
throw new NotFoundError('file does not exist')
6868
}
6969

7070
// remove the path component we have resolved
@@ -82,7 +82,7 @@ const unixFsResolver: Resolver = async (cid, name, path, toResolve, resolve, dep
8282
const content = contentExporters[unixfs.type](cid, node, unixfs, path, resolve, depth, blockstore)
8383

8484
if (content == null) {
85-
throw errCode(new Error('could not find content exporter'), 'ERR_NOT_FOUND')
85+
throw new NotFoundError('could not find content exporter')
8686
}
8787

8888
if (unixfs.isDirectory()) {

packages/ipfs-unixfs-exporter/src/utils/find-cid-in-shard.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { decode, type PBLink, type PBNode } from '@ipld/dag-pb'
22
import { murmur3128 } from '@multiformats/murmur3'
3-
import errCode from 'err-code'
43
import { Bucket, type BucketPosition, createHAMT } from 'hamt-sharding'
54
import { UnixFS } from 'ipfs-unixfs'
5+
import { NotUnixFSError } from '../errors.js'
66
import type { ExporterOptions, ShardTraversalContext, ReadableStorage } from '../index.js'
77
import type { CID } from 'multiformats/cid'
88

@@ -66,21 +66,21 @@ const toBucketPath = (position: BucketPosition<boolean>): Array<Bucket<boolean>>
6666
const findShardCid = async (node: PBNode, name: string, blockstore: ReadableStorage, context?: ShardTraversalContext, options?: ExporterOptions): Promise<CID | undefined> => {
6767
if (context == null) {
6868
if (node.Data == null) {
69-
throw errCode(new Error('no data in PBNode'), 'ERR_NOT_UNIXFS')
69+
throw new NotUnixFSError('no data in PBNode')
7070
}
7171

7272
let dir: UnixFS
7373
try {
7474
dir = UnixFS.unmarshal(node.Data)
7575
} catch (err: any) {
76-
throw errCode(err, 'ERR_NOT_UNIXFS')
76+
throw new NotUnixFSError(err.message)
7777
}
7878

7979
if (dir.type !== 'hamt-sharded-directory') {
80-
throw errCode(new Error('not a HAMT'), 'ERR_NOT_UNIXFS')
80+
throw new NotUnixFSError('not a HAMT')
8181
}
8282
if (dir.fanout == null) {
83-
throw errCode(new Error('missing fanout'), 'ERR_NOT_UNIXFS')
83+
throw new NotUnixFSError('missing fanout')
8484
}
8585

8686
const rootBucket = createHAMT<boolean>({

packages/ipfs-unixfs-exporter/src/utils/resolve-object-path.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import errCode from 'err-code'
21
import { CID } from 'multiformats/cid'
2+
import { NoPropError } from '../errors.js'
33
import type { ResolveResult } from '../index.js'
44

55
export function resolveObjectPath (object: any, block: Uint8Array, cid: CID, name: string, path: string, toResolve: string[], depth: number): ResolveResult {
@@ -41,7 +41,7 @@ export function resolveObjectPath (object: any, block: Uint8Array, cid: CID, nam
4141
subObject = subObject[prop]
4242
} else {
4343
// cannot resolve further
44-
throw errCode(new Error(`No property named ${prop} found in node ${cid}`), 'ERR_NO_PROP')
44+
throw new NoPropError(`No property named ${prop} found in node ${cid}`)
4545
}
4646
}
4747

0 commit comments

Comments
 (0)