Skip to content

Commit f4905d2

Browse files
authored
feat: remove buffer dependency (#460)
* test: add more coverage for normalise-dag-node.ts * feat: remove dependency on Buffer * fix: setExplorePath handles url check properly * fix: more type safety
1 parent 7fc8cf8 commit f4905d2

File tree

13 files changed

+334
-91
lines changed

13 files changed

+334
-91
lines changed

.aegir.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ export default {
105105

106106
// vite stuff
107107
'rollup-plugin-node-polyfills',
108+
'@vitest/coverage-v8',
108109

109110
// typescript plugins
110111
'typescript-plugin-css-modules'

.storybook/preview.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
import { type Preview } from '@storybook/react';
2-
import { Buffer } from 'buffer'
3-
4-
globalThis.Buffer = Buffer
52

63
// import CSS files
74
import 'ipfs-css'

dev/devPage.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
1-
/* globals globalThis */
21
import 'ipfs-css'
3-
import { Buffer } from 'buffer'
42
import React, { type MouseEvent, useEffect, useState } from 'react'
53
import { createRoot } from 'react-dom/client'
64
import { I18nextProvider, useTranslation } from 'react-i18next'
75
import 'tachyons'
86
import i18n from '../src/i18n.js'
97
import { ExplorePage, StartExploringPage, IpldExploreForm, IpldCarExploreForm, ExploreProvider, HeliaProvider, useExplore, useHelia } from '../src/index.js'
108

11-
globalThis.Buffer = globalThis.Buffer ?? Buffer
12-
139
const HeaderComponent: React.FC = () => {
1410
const activeColor = 'navy 0-100'
1511
const inActiveColor = 'navy o-50'

package-lock.json

Lines changed: 97 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@
179179
"test": "run-s test:unit test:storybook:ci test:consumer",
180180
"test:node": "run-s test:unit",
181181
"test:unit": "vitest run --environment=node",
182+
"test:unit:cov": "vitest run --environment=node --coverage",
182183
"storybook": "storybook dev",
183184
"storybook:build": "storybook build",
184185
"test:consumer": "run-s test:consumer:webui test:consumer:ipld.io",
@@ -232,6 +233,7 @@
232233
"@types/react-helmet": "^6.1.11",
233234
"@types/react-virtualized": "^9.21.30",
234235
"@vitejs/plugin-react": "^4.3.2",
236+
"@vitest/coverage-v8": "^2.1.3",
235237
"aegir": "^44.1.4",
236238
"concurrently": "^9.0.1",
237239
"eslint-config-ipfs": "^7.0.6",

src/lib/browser-shims.js

Lines changed: 0 additions & 7 deletions
This file was deleted.

src/lib/cid.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { CID, type MultibaseDecoder } from 'multiformats/cid'
66
/**
77
* Converts a value to a CID or returns null if it cannot be converted.
88
*/
9-
export function toCidOrNull <T extends string> (value: CID | string | null, base?: MultibaseDecoder<T> | undefined): CID | null {
9+
export function toCidOrNull <T extends string> (value: CID | string | null | unknown, base?: MultibaseDecoder<T> | undefined): CID | null {
1010
if (value == null) return null
1111
try {
1212
return CID.asCID(value) ?? CID.parse(value as string, base)

src/lib/extract-info.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ import { type CID } from 'multiformats'
22
import { decodeCid } from '../components/cid-info/decode-cid.js'
33
import getCodecNameFromCode from './get-codec-name-from-code'
44

5-
const toHex = (bytes: Uint8Array): string => Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString('hex').toUpperCase()
5+
const toHex = (bytes: Uint8Array): string => Array.from(new Uint8Array(bytes.buffer, bytes.byteOffset, bytes.byteLength))
6+
.map(byte => byte.toString(16).padStart(2, '0'))
7+
.join('')
8+
.toUpperCase()
69

710
export interface ExtractedInfo {
811
base: string

src/lib/normalise-dag-node.ts

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import * as dagCbor from '@ipld/dag-cbor'
33
import * as dagPb from '@ipld/dag-pb'
44
import { UnixFS } from 'ipfs-unixfs'
5+
import { type CID } from 'multiformats/cid'
56
import { toCidOrNull, getCodeOrNull, toCidStrOrNull } from './cid.js'
67
import { isTruthy } from './helpers.js'
78
import type { NormalizedDagPbNodeFormat, CodecType, NormalizedDagNode, NormalizedDagLink, dagNode } from '../types.js'
@@ -25,7 +26,7 @@ function isDagPbNode (node: dagNode | PBNode, cid: string): node is PBNode {
2526
* @param {string} cidStr - the cid string passed to `ipfs.dag.get`
2627
* @returns {import('../types').NormalizedDagNode}
2728
*/
28-
export default function normaliseDagNode (node: dagNode | PBNode, cidStr: string): NormalizedDagNode {
29+
export function normaliseDagNode (node: dagNode | PBNode, cidStr: string): NormalizedDagNode {
2930
const code = getCodeOrNull(cidStr)
3031
if (isDagPbNode(node, cidStr)) {
3132
return normaliseDagPb(node, cidStr, dagPb.code)
@@ -34,6 +35,7 @@ export default function normaliseDagNode (node: dagNode | PBNode, cidStr: string
3435
// @ts-expect-error - todo: resolve node type error
3536
return normaliseDagCbor(node, cidStr, code ?? dagCbor.code)
3637
}
38+
export default normaliseDagNode
3739

3840
/**
3941
* Normalize links and add type info. Add unixfs info where available
@@ -120,18 +122,41 @@ export function normaliseDagCbor (data: NormalizedDagNode['data'], cid: string,
120122
}
121123
}
122124

125+
type PlainObjectOrArray = Record<string, unknown> | unknown[] | string
126+
127+
function isPlainObjectOrArray (obj: unknown): obj is PlainObjectOrArray {
128+
return (
129+
obj !== null &&
130+
typeof obj === 'object' &&
131+
!(obj instanceof ArrayBuffer) &&
132+
!ArrayBuffer.isView(obj) &&
133+
!(typeof obj === 'string')
134+
)
135+
}
136+
137+
type DagCborNodeObject = Record<string, unknown> & { '/': string | CID | null }
138+
139+
/**
140+
* This should be called after `isPlainObjectOrArray` to avoid type errors.
141+
*/
142+
function isDagCborNodeObject (obj: PlainObjectOrArray): obj is DagCborNodeObject {
143+
return Object.keys(obj).length === 1 && (obj as Record<string, unknown>)['/'] != null
144+
}
145+
123146
/**
124147
* A valid IPLD link in a dag-cbor node is an object with single "/" property.
125148
*/
126149
export function findAndReplaceDagCborLinks (obj: unknown, sourceCid: string, path: string = ''): NormalizedDagLink[] {
127-
if (obj == null || typeof obj !== 'object' || Buffer.isBuffer(obj) || typeof obj === 'string') {
150+
if (!isPlainObjectOrArray(obj)) {
128151
return []
129152
}
130153

131-
// FIXME: remove as any cast
132-
const cid = toCidOrNull(obj as any)
133-
if (cid != null) {
134-
return [{ path, source: sourceCid, target: cid.toString(), size: BigInt(0), index: 0 }]
154+
const cid = toCidOrNull(obj)
155+
if (typeof obj === 'string' || cid != null) {
156+
if (cid != null) {
157+
return [{ path, source: sourceCid, target: cid.toString(), size: BigInt(0), index: 0 }]
158+
}
159+
return []
135160
}
136161

137162
if (Array.isArray(obj)) {
@@ -146,22 +171,19 @@ export function findAndReplaceDagCborLinks (obj: unknown, sourceCid: string, pat
146171
const keys = Object.keys(obj)
147172

148173
// Support older `{ "/": Buffer } style links until all the IPLD formats are updated.
149-
if (keys.length === 1 && keys[0] === '/') {
150-
// @ts-expect-error - todo: resolve this type error
174+
if (isDagCborNodeObject(obj)) {
151175
const targetCid = toCidOrNull(obj['/'])
152176

153177
if (targetCid == null) return []
154178

155179
const target = targetCid.toString()
156-
// @ts-expect-error - todo: resolve this type error
157180
obj['/'] = target
158181

159182
return [{ path, source: sourceCid, target, size: BigInt(0), index: 0 }]
160183
}
161184

162185
if (keys.length > 0) {
163186
return keys
164-
// @ts-expect-error - todo: resolve this type error
165187
.map(key => findAndReplaceDagCborLinks(obj[key], sourceCid, isTruthy(path) ? `${path}/${key}` : `${key}`))
166188
.reduce((a, b) => a.concat(b))
167189
.filter(a => Boolean(a))

0 commit comments

Comments
 (0)