Skip to content

Commit

Permalink
feat: add name property to errors
Browse files Browse the repository at this point in the history
Adds a `.name` property to all errors that can be used in a more
ideomatic way than `.code`.
  • Loading branch information
achingbrain committed Sep 13, 2024
1 parent 3490930 commit 3d70363
Show file tree
Hide file tree
Showing 21 changed files with 210 additions and 57 deletions.
1 change: 0 additions & 1 deletion packages/ipfs-unixfs-exporter/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@
"@ipld/dag-json": "^10.2.0",
"@ipld/dag-pb": "^4.1.0",
"@multiformats/murmur3": "^2.1.8",
"err-code": "^3.0.1",
"hamt-sharding": "^3.0.6",
"interface-blockstore": "^5.2.10",
"ipfs-unixfs": "^11.0.0",
Expand Down
87 changes: 87 additions & 0 deletions packages/ipfs-unixfs-exporter/src/errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
export class BadPathError extends Error {
static name = 'BadPathError'
static code = 'ERR_BAD_PATH'
name = BadPathError.name
code = BadPathError.code

constructor (message = 'Bad path') {
super(message)
}
}

export class NotFoundError extends Error {
static name = 'NotFoundError'
static code = 'ERR_NOT_FOUND'
name = NotFoundError.name
code = NotFoundError.code

constructor (message = 'Not found') {
super(message)
}
}

export class NoResolverError extends Error {
static name = 'NoResolverError'
static code = 'ERR_NO_RESOLVER'
name = NoResolverError.name
code = NoResolverError.code

constructor (message = 'No resolver') {
super(message)
}
}

export class NotUnixFSError extends Error {
static name = 'NotUnixFSError'
static code = 'ERR_NOT_UNIXFS'
name = NotUnixFSError.name
code = NotUnixFSError.code

constructor (message = 'Not UnixFS') {
super(message)
}
}

export class OverReadError extends Error {
static name = 'OverReadError'
static code = 'ERR_OVER_READ'
name = OverReadError.name
code = OverReadError.code

constructor (message = 'Over read') {
super(message)
}
}

export class UnderReadError extends Error {
static name = 'UnderReadError'
static code = 'ERR_UNDER_READ'
name = UnderReadError.name
code = UnderReadError.code

constructor (message = 'Under read') {
super(message)
}
}

export class NoPropError extends Error {
static name = 'NoPropError'
static code = 'ERR_NO_PROP'
name = NoPropError.name
code = NoPropError.code

constructor (message = 'No Property found') {
super(message)
}
}

export class InvalidParametersError extends Error {
static name = 'InvalidParametersError'
static code = 'ERR_INVALID_PARAMS'
name = InvalidParametersError.name
code = InvalidParametersError.code

constructor (message = 'Invalid parameters') {
super(message)
}
}
10 changes: 6 additions & 4 deletions packages/ipfs-unixfs-exporter/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,18 @@
* ```
*/

import errCode from 'err-code'
import last from 'it-last'
import { CID } from 'multiformats/cid'
import { BadPathError, NotFoundError } from './errors.js'
import resolve from './resolvers/index.js'
import type { PBNode } from '@ipld/dag-pb'
import type { Bucket } from 'hamt-sharding'
import type { Blockstore } from 'interface-blockstore'
import type { UnixFS } from 'ipfs-unixfs'
import type { ProgressOptions, ProgressEvent } from 'progress-events'

export * from './errors.js'

export interface ExportProgress {
/**
* How many bytes of the file have been read
Expand Down Expand Up @@ -361,7 +363,7 @@ const cidAndRest = (path: string | Uint8Array | CID): { cid: CID, toResolve: str
}
}

throw errCode(new Error(`Unknown path type ${path}`), 'ERR_BAD_PATH')
throw new BadPathError(`Unknown path type ${path}`)

Check warning on line 366 in packages/ipfs-unixfs-exporter/src/index.ts

View check run for this annotation

Codecov / codecov/patch

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

Added line #L366 was not covered by tests
}

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

if (result.entry == null && result.next == null) {
throw errCode(new Error(`Could not resolve ${path}`), 'ERR_NOT_FOUND')
throw new NotFoundError(`Could not resolve ${path}`)

Check warning on line 399 in packages/ipfs-unixfs-exporter/src/index.ts

View check run for this annotation

Codecov / codecov/patch

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

Added line #L399 was not covered by tests
}

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

if (result == null) {
throw errCode(new Error(`Could not resolve ${path}`), 'ERR_NOT_FOUND')
throw new NotFoundError(`Could not resolve ${path}`)

Check warning on line 446 in packages/ipfs-unixfs-exporter/src/index.ts

View check run for this annotation

Codecov / codecov/patch

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

Added line #L446 was not covered by tests
}

return result
Expand Down
4 changes: 2 additions & 2 deletions packages/ipfs-unixfs-exporter/src/resolvers/identity.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import errCode from 'err-code'
import * as mh from 'multiformats/hashes/digest'
import { CustomProgressEvent } from 'progress-events'
import { NotFoundError } from '../errors.js'
import extractDataFromBlock from '../utils/extract-data-from-block.js'
import validateOffsetAndLength from '../utils/validate-offset-and-length.js'
import type { ExporterOptions, Resolver, ExportProgress } from '../index.js'
Expand Down Expand Up @@ -28,7 +28,7 @@ const rawContent = (node: Uint8Array): ((options?: ExporterOptions) => AsyncGene

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

Check warning on line 31 in packages/ipfs-unixfs-exporter/src/resolvers/identity.ts

View check run for this annotation

Codecov / codecov/patch

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

Added line #L31 was not covered by tests
}
const buf = mh.decode(cid.multihash.bytes)

Expand Down
4 changes: 2 additions & 2 deletions packages/ipfs-unixfs-exporter/src/resolvers/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import * as dagCbor from '@ipld/dag-cbor'
import * as dagJson from '@ipld/dag-json'
import * as dagPb from '@ipld/dag-pb'
import errCode from 'err-code'
import * as json from 'multiformats/codecs/json'
import * as raw from 'multiformats/codecs/raw'
import { identity } from 'multiformats/hashes/identity'
import { NoResolverError } from '../errors.js'
import dagCborResolver from './dag-cbor.js'
import dagJsonResolver from './dag-json.js'
import identifyResolver from './identity.js'
Expand All @@ -26,7 +26,7 @@ const resolve: Resolve = async (cid, name, path, toResolve, depth, blockstore, o
const resolver = resolvers[cid.code]

if (resolver == null) {
throw errCode(new Error(`No resolver for code ${cid.code}`), 'ERR_NO_RESOLVER')
throw new NoResolverError(`No resolver for code ${cid.code}`)
}

return resolver(cid, name, path, toResolve, resolve, depth, blockstore, options)
Expand Down
4 changes: 2 additions & 2 deletions packages/ipfs-unixfs-exporter/src/resolvers/raw.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import errCode from 'err-code'
import { CustomProgressEvent } from 'progress-events'
import { NotFoundError } from '../errors.js'
import extractDataFromBlock from '../utils/extract-data-from-block.js'
import validateOffsetAndLength from '../utils/validate-offset-and-length.js'
import type { ExporterOptions, Resolver, ExportProgress } from '../index.js'
Expand Down Expand Up @@ -27,7 +27,7 @@ const rawContent = (node: Uint8Array): ((options?: ExporterOptions) => AsyncGene

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

const block = await blockstore.get(cid, options)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as dagPb from '@ipld/dag-pb'
import errCode from 'err-code'
import { UnixFS } from 'ipfs-unixfs'
import map from 'it-map'
import parallel from 'it-parallel'
Expand All @@ -8,6 +7,7 @@ import { type Pushable, pushable } from 'it-pushable'
import * as raw from 'multiformats/codecs/raw'
import PQueue from 'p-queue'
import { CustomProgressEvent } from 'progress-events'
import { NotUnixFSError, OverReadError, UnderReadError } from '../../../errors.js'
import extractDataFromBlock from '../../../utils/extract-data-from-block.js'
import validateOffsetAndLength from '../../../utils/validate-offset-and-length.js'
import type { ExporterOptions, UnixfsV1FileContent, UnixfsV1Resolver, ReadableStorage, ExportProgress, ExportWalk } from '../../../index.js'
Expand All @@ -23,15 +23,15 @@ async function walkDAG (blockstore: ReadableStorage, node: dagPb.PBNode | Uint8A
}

if (node.Data == null) {
throw errCode(new Error('no data in PBNode'), 'ERR_NOT_UNIXFS')
throw new NotUnixFSError('no data in PBNode')

Check warning on line 26 in packages/ipfs-unixfs-exporter/src/resolvers/unixfs-v1/content/file.ts

View check run for this annotation

Codecov / codecov/patch

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

Added line #L26 was not covered by tests
}

let file: UnixFS

try {
file = UnixFS.unmarshal(node.Data)
} catch (err: any) {
throw errCode(err, 'ERR_NOT_UNIXFS')
throw new NotUnixFSError(err.message)

Check warning on line 34 in packages/ipfs-unixfs-exporter/src/resolvers/unixfs-v1/content/file.ts

View check run for this annotation

Codecov / codecov/patch

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

Added line #L34 was not covered by tests
}

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

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

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

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

if (read > wanted) {
queue.end()
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')
throw new OverReadError('Read too many bytes - the file size reported by the UnixFS data in the root node may be incorrect')
}

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

if (read < wanted) {
throw errCode(new Error('Traversed entire DAG but did not read enough bytes'), 'ERR_UNDER_READ')
throw new UnderReadError('Traversed entire DAG but did not read enough bytes')
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { decode, type PBNode } from '@ipld/dag-pb'
import errCode from 'err-code'
import { UnixFS } from 'ipfs-unixfs'
import map from 'it-map'
import parallel from 'it-parallel'
import { pipe } from 'it-pipe'
import { CustomProgressEvent } from 'progress-events'
import { NotUnixFSError } from '../../../errors.js'
import type { ExporterOptions, Resolve, UnixfsV1DirectoryContent, UnixfsV1Resolver, ReadableStorage, ExportWalk } from '../../../index.js'

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

if (node.Data == null) {
throw errCode(new Error('no data in PBNode'), 'ERR_NOT_UNIXFS')
throw new NotUnixFSError('no data in PBNode')

Check warning on line 26 in packages/ipfs-unixfs-exporter/src/resolvers/unixfs-v1/content/hamt-sharded-directory.ts

View check run for this annotation

Codecov / codecov/patch

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

Added line #L26 was not covered by tests
}

let dir: UnixFS
try {
dir = UnixFS.unmarshal(node.Data)
} catch (err: any) {
throw errCode(err, 'ERR_NOT_UNIXFS')
throw new NotUnixFSError(err.message)

Check warning on line 33 in packages/ipfs-unixfs-exporter/src/resolvers/unixfs-v1/content/hamt-sharded-directory.ts

View check run for this annotation

Codecov / codecov/patch

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

Added line #L33 was not covered by tests
}

if (dir.fanout == null) {
throw errCode(new Error('missing fanout'), 'ERR_NOT_UNIXFS')
throw new NotUnixFSError('missing fanout')

Check warning on line 37 in packages/ipfs-unixfs-exporter/src/resolvers/unixfs-v1/content/hamt-sharded-directory.ts

View check run for this annotation

Codecov / codecov/patch

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

Added line #L37 was not covered by tests
}

const padLength = (dir.fanout - 1n).toString(16).length
Expand Down
10 changes: 5 additions & 5 deletions packages/ipfs-unixfs-exporter/src/resolvers/unixfs-v1/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { decode, type PBNode } from '@ipld/dag-pb'
import errCode from 'err-code'
import { UnixFS } from 'ipfs-unixfs'
import { NotFoundError, NotUnixFSError } from '../../errors.js'
import findShardCid from '../../utils/find-cid-in-shard.js'
import contentDirectory from './content/directory.js'
import contentFile from './content/file.js'
Expand Down Expand Up @@ -39,14 +39,14 @@ const unixFsResolver: Resolver = async (cid, name, path, toResolve, resolve, dep
}

if (node.Data == null) {
throw errCode(new Error('no data in PBNode'), 'ERR_NOT_UNIXFS')
throw new NotUnixFSError('no data in PBNode')

Check warning on line 42 in packages/ipfs-unixfs-exporter/src/resolvers/unixfs-v1/index.ts

View check run for this annotation

Codecov / codecov/patch

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

Added line #L42 was not covered by tests
}

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

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

if (linkCid == null) {
throw errCode(new Error('file does not exist'), 'ERR_NOT_FOUND')
throw new NotFoundError('file does not exist')
}

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

if (content == null) {
throw errCode(new Error('could not find content exporter'), 'ERR_NOT_FOUND')
throw new NotFoundError('could not find content exporter')

Check warning on line 85 in packages/ipfs-unixfs-exporter/src/resolvers/unixfs-v1/index.ts

View check run for this annotation

Codecov / codecov/patch

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

Added line #L85 was not covered by tests
}

if (unixfs.isDirectory()) {
Expand Down
10 changes: 5 additions & 5 deletions packages/ipfs-unixfs-exporter/src/utils/find-cid-in-shard.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { decode, type PBLink, type PBNode } from '@ipld/dag-pb'
import { murmur3128 } from '@multiformats/murmur3'
import errCode from 'err-code'
import { Bucket, type BucketPosition, createHAMT } from 'hamt-sharding'
import { UnixFS } from 'ipfs-unixfs'
import { NotUnixFSError } from '../errors.js'
import type { ExporterOptions, ShardTraversalContext, ReadableStorage } from '../index.js'
import type { CID } from 'multiformats/cid'

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

Check warning on line 69 in packages/ipfs-unixfs-exporter/src/utils/find-cid-in-shard.ts

View check run for this annotation

Codecov / codecov/patch

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

Added line #L69 was not covered by tests
}

let dir: UnixFS
try {
dir = UnixFS.unmarshal(node.Data)
} catch (err: any) {
throw errCode(err, 'ERR_NOT_UNIXFS')
throw new NotUnixFSError(err.message)

Check warning on line 76 in packages/ipfs-unixfs-exporter/src/utils/find-cid-in-shard.ts

View check run for this annotation

Codecov / codecov/patch

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

Added line #L76 was not covered by tests
}

if (dir.type !== 'hamt-sharded-directory') {
throw errCode(new Error('not a HAMT'), 'ERR_NOT_UNIXFS')
throw new NotUnixFSError('not a HAMT')

Check warning on line 80 in packages/ipfs-unixfs-exporter/src/utils/find-cid-in-shard.ts

View check run for this annotation

Codecov / codecov/patch

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

Added line #L80 was not covered by tests
}
if (dir.fanout == null) {
throw errCode(new Error('missing fanout'), 'ERR_NOT_UNIXFS')
throw new NotUnixFSError('missing fanout')

Check warning on line 83 in packages/ipfs-unixfs-exporter/src/utils/find-cid-in-shard.ts

View check run for this annotation

Codecov / codecov/patch

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

Added line #L83 was not covered by tests
}

const rootBucket = createHAMT<boolean>({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import errCode from 'err-code'
import { CID } from 'multiformats/cid'
import { NoPropError } from '../errors.js'
import type { ResolveResult } from '../index.js'

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

Expand Down
Loading

0 comments on commit 3d70363

Please sign in to comment.