Skip to content

Commit

Permalink
feat!: latest multiformats, full types check & gen & publish (#6)
Browse files Browse the repository at this point in the history
BREAKING CHANGE:

* check, generate and publish full TypeScript types
* use multiformats@7 and its non-default exports and updated types
* export types based on latest multiformats structure
* publish with "main"
  • Loading branch information
rvagg committed Apr 26, 2021
1 parent b067f75 commit 297d8d7
Show file tree
Hide file tree
Showing 8 changed files with 233 additions and 61 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/mikeals-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x, 14.x]
node-version: [12.x, 14.x, 16.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
Expand Down
115 changes: 80 additions & 35 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,57 +1,102 @@
import json from 'fast-json-stable-stringify'
// @ts-ignore
import isCircular from '@ipld/is-circular'
import transform from 'lodash.transform'
import { bytes, CID } from 'multiformats'
import { base64 } from 'multiformats/bases/base64'

const _encode = (obj) => transform(obj, (result, value, key) => {
const cid = CID.asCID(value)
if (cid) {
result[key] = { '/': cid.toString() }
} else if (bytes.isBinary(value)) {
value = bytes.coerce(value)
result[key] = { '/': { bytes: base64.encode(value) } }
} else if (typeof value === 'object' && value !== null) {
result[key] = _encode(value)
} else {
result[key] = value
}
})
/**
* @template {number} Code
* @template T
* @typedef {import('multiformats/codecs/interface').BlockCodec<Code, T>} BlockCodec
*/

/**
* @template T
* @param {T} obj
* @returns {T}
*/
const transformEncode = (obj) => transform(obj,
/**
* @param {any} result
* @param {any} value
* @param {string} key
*/
(result, value, key) => {
const cid = CID.asCID(value)
if (cid) {
result[key] = { '/': cid.toString() }
} else if (bytes.isBinary(value)) {
value = bytes.coerce(value)
result[key] = { '/': { bytes: base64.encode(value) } }
} else if (typeof value === 'object' && value !== null) {
result[key] = transformEncode(value)
} else {
result[key] = value
}
})

const encode = (obj) => {
/**
* @template T
* @param {T} obj
* @returns {Uint8Array}
*/
const _encode = (obj) => {
if (typeof obj === 'object' && !bytes.isBinary(obj) && !CID.asCID(obj) && obj) {
if (isCircular(obj, { asCID: true })) {
throw new Error('Object contains circular references')
}
obj = _encode(obj)
obj = transformEncode(obj)
}
return bytes.fromString(json(obj))
}

const _decode = (obj) => transform(obj, (result, value, key) => {
if (typeof value === 'object' && value !== null) {
if (value['/']) {
if (typeof value['/'] === 'string') {
result[key] = CID.parse(value['/'])
} else if (typeof value['/'] === 'object' && value['/'].bytes) {
result[key] = base64.decode(value['/'].bytes)
/**
* @param {object} obj
* @returns {any}
*/
const transformDecode = (obj) => transform(obj,
/**
* @param {any} result
* @param {any} value
* @param {string} key
* @returns {any}
*/
(result, value, key) => {
if (typeof value === 'object' && value !== null) {
if (value['/']) {
if (typeof value['/'] === 'string') {
result[key] = CID.parse(value['/'])
} else if (typeof value['/'] === 'object' && value['/'].bytes) {
result[key] = base64.decode(value['/'].bytes)
} else {
result[key] = transformDecode(value)
}
} else {
result[key] = _decode(value)
result[key] = transformDecode(value)
}
} else {
result[key] = _decode(value)
result[key] = value
}
} else {
result[key] = value
}
})
})

const decode = (buffer) => {
const obj = JSON.parse(bytes.toString(buffer))
return _decode({ value: obj }).value
/**
* @template T
* @param {Uint8Array} data
* @returns {T}
*/
const _decode = (data) => {
const obj = JSON.parse(bytes.toString(data))
return transformDecode({ value: obj }).value
}

const name = 'dag-json'
const code = 0x0129

export { encode, decode, name, code }
/**
* @template T
* @type {BlockCodec<0x0129, T>}
*/
export const { name, code, decode, encode } = {
name: 'dag-json',
code: 0x0129,
encode: _encode,
decode: _decode
}
72 changes: 47 additions & 25 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,45 +1,67 @@
{
"name": "@ipld/dag-json",
"version": "0.0.0-dev",
"description": "JSON Directed Acrylic Graph for IPLD",
"description": "JSON Directed Acrylic Graph (DAG-JSON) for IPLD",
"main": "index.js",
"types": "./types/index.d.ts",
"type": "module",
"directories": {
"test": "test"
},
"scripts": {
"lint": "standard",
"build": "npm_config_yes=true npx ipjs@latest build --tests",
"publish": "npm_config_yes=true npx ipjs@latest publish",
"test:cjs": "npm run build && mocha dist/cjs/node-test/test-*.js",
"lint": "standard *.js test/*.js",
"build": "npm run build:js && npm run build:types",
"build:js": "ipjs build --tests --main && npm run build:copy",
"build:copy": "cp -a tsconfig.json index.js dist/ && mkdir -p dist/test && cp test/*.js dist/test/",
"build:types": "npm run build:copy && cd dist && tsc --build",
"publish": "ipjs publish",
"test:cjs": "npm run build:js && mocha dist/cjs/node-test/test-*.js && npm run test:cjs:browser",
"test:node": "hundreds mocha test/test-*.js",
"test:browser": "polendina --cleanup dist/cjs/node-test/test-*.js",
"test": "npm run lint && npm run test:node && npm run test:cjs && npm run test:browser",
"coverage": "c8 --reporter=html mocha test/test-*.js && npx st -d coverage -p 8080"
"test:cjs:browser": "polendina --page --worker --serviceworker --cleanup dist/cjs/node-test/test-*.js",
"test:ts": "npm run build:types && npm run test --prefix test/ts-use",
"test": "npm run lint && npm run test:node && npm run test:cjs && npm run test:ts",
"coverage": "c8 --reporter=html mocha test/test-*.js && npm_config_yes=true npx st -d coverage -p 8080"
},
"exports": {
"import": "./index.js"
},
"license": "(Apache-2.0 AND MIT)",
"repository": {
"type": "git",
"url": "git+https://github.com/mikeal/dag-json.git"
"url": "git+https://github.com/ipld/js-dag-json.git"
},
"keywords": [],
"author": "Mikeal Rogers <mikeal.rogers@gmail.com> (https://www.mikealrogers.com/)",
"license": "(Apache-2.0 AND MIT)",
"keywords": [
"IPFS",
"IPLD"
],
"bugs": {
"url": "https://github.com/mikeal/dag-json/issues"
},
"homepage": "https://github.com/mikeal/dag-json#readme",
"devDependencies": {
"hundreds": "0.0.8",
"mocha": "^8.1.1",
"polendina": "^1.1.0",
"standard": "^14.3.4"
"url": "https://github.com/ipld/js-dag-json/issues"
},
"homepage": "https://github.com/ipld/js-dag-json",
"dependencies": {
"@ipld/is-circular": "^2.0.0",
"@types/lodash.transform": "^4.6.6",
"fast-json-stable-stringify": "^2.1.0",
"lodash.transform": "^4.6.0",
"multiformats": "^4.0.0"
}
"multiformats": "^7.0.0"
},
"devDependencies": {
"hundreds": "^0.0.9",
"ipjs": "^5.0.0",
"mocha": "^8.3.2",
"polendina": "^1.1.0",
"standard": "^16.0.3",
"typescript": "^4.2.4"
},
"directories": {
"test": "test"
},
"typesVersions": {
"*": {
"*": [
"types/*"
],
"types/*": [
"types/*"
]
}
},
"author": "Mikeal Rogers <mikeal.rogers@gmail.com> (https://www.mikealrogers.com/)"
}
3 changes: 3 additions & 0 deletions test/ts-use/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
src/main.js
tsconfig.tsbuildinfo
11 changes: 11 additions & 0 deletions test/ts-use/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "ts-use",
"private": true,
"dependencies": {
"@ipld/dag-json": "file:../../dist/",
"multiformats": "file:../../node_modules/multiformats"
},
"scripts": {
"test": "npm install && npx -p typescript tsc && node src/main.js"
}
}
45 changes: 45 additions & 0 deletions test/ts-use/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { deepStrictEqual } from 'assert'

import { BlockEncoder, BlockDecoder, BlockCodec } from 'multiformats/codecs/interface'
import * as dagJson from '@ipld/dag-json'

const main = () => {
// make sure we have a full CodecFeature
useCodecFeature(dagJson)
}

function useCodecFeature (codec: BlockCodec<297, any>) {
// use only as a BlockEncoder
useEncoder(codec)

// use only as a BlockDecoder
useDecoder(codec)

// use as a full BlockCodec which does both BlockEncoder & BlockDecoder
useBlockCodec(codec)
}

function useEncoder<Codec extends number> (encoder: BlockEncoder<Codec, string>) {
deepStrictEqual(encoder.code, 297)
deepStrictEqual(encoder.name, 'dag-json')
deepStrictEqual(Array.from(encoder.encode('blip')), [34, 98, 108, 105, 112, 34])
console.log('[TS] ✓ { encoder: BlockEncoder }')
}

function useDecoder<Codec extends number> (decoder: BlockDecoder<Codec, Uint8Array>) {
deepStrictEqual(decoder.code, 297)
deepStrictEqual(decoder.decode(Uint8Array.from([34, 98, 108, 105, 112, 34 ])), 'blip')
console.log('[TS] ✓ { decoder: BlockDecoder }')
}

function useBlockCodec<Codec extends number> (blockCodec: BlockCodec<Codec, string>) {
deepStrictEqual(blockCodec.code, 297)
deepStrictEqual(blockCodec.name, 'dag-json')
deepStrictEqual(Array.from(blockCodec.encode('blip')), [34, 98, 108, 105, 112, 34])
deepStrictEqual(blockCodec.decode(Uint8Array.from([34, 98, 108, 105, 112, 34])), 'blip')
console.log('[TS] ✓ {}:BlockCodec')
}

main()

export default main
9 changes: 9 additions & 0 deletions test/ts-use/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"compilerOptions": {
"strict": true,
"moduleResolution": "node",
"noImplicitAny": true,
"skipLibCheck": true,
"incremental": true
}
}
37 changes: 37 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": false,
"noImplicitAny": true,
"noImplicitThis": true,
"noFallthroughCasesInSwitch": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"strictFunctionTypes": false,
"strictNullChecks": true,
"strictPropertyInitialization": true,
"strictBindCallApply": true,
"strict": true,
"alwaysStrict": true,
"esModuleInterop": true,
"target": "ES2018",
"moduleResolution": "node",
"declaration": true,
"declarationMap": true,
"outDir": "types",
"skipLibCheck": true,
"stripInternal": true,
"resolveJsonModule": true,
"baseUrl": ".",
"emitDeclarationOnly": true
},
"include": [
"index.js"
],
"exclude": [
"node_modules"
],
"compileOnSave": false
}

0 comments on commit 297d8d7

Please sign in to comment.