diff --git a/.aegir.js b/.aegir.cjs similarity index 51% rename from .aegir.js rename to .aegir.cjs index 378889f..53e8c55 100644 --- a/.aegir.js +++ b/.aegir.cjs @@ -4,7 +4,17 @@ const path = require('path') /** @type {import('aegir').Options["build"]["config"]} */ const esbuild = { - inject: [path.join(__dirname, './scripts/node-globals.js')] + inject: [path.join(__dirname, './scripts/node-globals.js')], + plugins: [ + { + name: 'node built ins', + setup (build) { + build.onResolve({ filter: /^immediate$/ }, () => { + return { path: path.join(__dirname, './scripts/immediate.js') } + }) + } + } + ] } /** @type {import('aegir').PartialOptions} */ @@ -19,4 +29,4 @@ module.exports = { } } } -} \ No newline at end of file +} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e67b088..3b0afed 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -57,11 +57,13 @@ jobs: steps: - uses: actions/checkout@v2 - run: npm install - - run: npx xvfb-maybe aegir test -t electron-main --bail + - run: npm run pretest + - run: npx xvfb-maybe aegir test -t electron-main --bail -f dist/cjs/node-test/*js test-electron-renderer: needs: check runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - run: npm install - - run: npx xvfb-maybe aegir test -t electron-renderer --bail \ No newline at end of file + - run: npm run pretest + - run: npx xvfb-maybe aegir test -t electron-renderer --bail -f dist/cjs/browser-test/*js diff --git a/.gitignore b/.gitignore index eb82212..83ea039 100644 --- a/.gitignore +++ b/.gitignore @@ -40,4 +40,5 @@ dist test/test-repo/datastore init-default datastore-test -.vscode \ No newline at end of file +.vscode +types diff --git a/README.md b/README.md index ba35779..523cfbc 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# js-datastore-level +# js-datastore-level [![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) [![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/) @@ -14,21 +14,18 @@ > Datastore implementation with [levelup](https://github.com/level/levelup) backend. -## Lead Maintainer +## Lead Maintainer [Alex Potsides](https://github.com/achingbrain) -## Table of Contents +## Table of Contents -- [js-datastore-level](#js-datastore-level) - - [Lead Maintainer](#Lead-Maintainer) - - [Table of Contents](#Table-of-Contents) - - [Install](#Install) - - [Usage](#Usage) - - [Browser Shimming Leveldown](#Browser-Shimming-Leveldown) - - [Database names](#Database-names) - - [Contribute](#Contribute) - - [License](#License) +- [Install](#install) +- [Usage](#usage) + - [Browser Shimming Leveldown](#browser-shimming-leveldown) + - [Database names](#database-names) +- [Contribute](#contribute) +- [License](#license) ## Install @@ -39,13 +36,13 @@ $ npm install datastore-level ## Usage ```js -const LevelStore = require('datastore-level') +import { LevelDatastore } from 'datastore-level' // Default using level as backend for node or the browser -const store = new LevelStore('path/to/store') +const store = new LevelDatastore('path/to/store') // another leveldown compliant backend like memdown -const memStore = new LevelStore('my/mem/store', { +const memStore = new LevelDatastore('my/mem/store', { db: require('level-mem') }) ``` @@ -61,8 +58,8 @@ If you are using a bundler that does not support `pkg.browser`, you will need to `level-js@3` changed the database prefix from `IDBWrapper-` to `level-js-`, so please specify the old prefix if you wish to continue using databases created using `datastore-level` prior to `v0.12.0`. E.g. ```javascript -const leveljs = require('level-js') -const browserStore = new LevelStore('my/db/name', { +import leveljs from 'level-js' +import browserStore = new LevelDatastore('my/db/name', { db: (path) => leveljs(path, { prefix: 'IDBWrapper-' }) diff --git a/package.json b/package.json index 7949403..646248b 100644 --- a/package.json +++ b/package.json @@ -4,23 +4,28 @@ "description": "Datastore implementation with level(up|down) backend", "leadMaintainer": "Pedro Teixeira ", "main": "src/index.js", - "types": "dist/src/index.d.ts", + "type": "module", + "types": "types/index.d.ts", "files": [ - "src", - "dist" + "*", + "!**/*.tsbuildinfo" ], + "exports": { + ".": { + "import": "./src/index.js" + } + }, "scripts": { - "test": "aegir test", - "test:node": "aegir test -t node", - "test:browser": "aegir test -t browser", - "test:webworker": "aegir test -t webworker", - "prepare": "aegir build --no-bundle", + "clean": "rimraf dist types", + "prepare": "aegir build --no-bundle && cp -R types dist", "lint": "aegir ts -p check && aegir lint", - "release": "aegir release", - "release-minor": "aegir release --type minor", - "release-major": "aegir release --type major", - "coverage": "nyc -s npm run test:node && nyc report --reporter=html", - "dep-check": "aegir dep-check" + "build": "aegir build", + "release": "aegir release --target node", + "release-minor": "aegir release --type minor --target node", + "release-major": "aegir release --type major --target node", + "pretest": "aegir build --esm-tests", + "test": "aegir test", + "dep-check": "aegir dep-check -i rimraf" }, "repository": { "type": "git", @@ -42,26 +47,32 @@ }, "homepage": "https://github.com/ipfs/js-datastore-level#readme", "dependencies": { - "datastore-core": "^5.0.0", - "interface-datastore": "^5.1.1", + "datastore-core": "^6.0.5", + "interface-datastore": "^6.0.2", "it-filter": "^1.0.2", "it-map": "^1.0.5", + "it-sort": "^1.0.0", "it-take": "^1.0.1", "level": "^7.0.0" }, "devDependencies": { "@ipld/dag-cbor": "^6.0.5", - "aegir": "^33.2.4", + "@types/rimraf": "^3.0.2", + "aegir": "^35.0.3", "assert": "^2.0.0", "buffer": "^6.0.3", - "interface-datastore-tests": "^1.0.0", + "interface-datastore-tests": "^2.0.3", + "ipfs-utils": "^8.1.6", "level-mem": "^5.0.1", "multiformats": "^9.2.0", "rimraf": "^3.0.0", "util": "^0.12.3" }, "eslintConfig": { - "extends": "ipfs" + "extends": "ipfs", + "parserOptions": { + "sourceType": "module" + } }, "contributors": [ "achingbrain ", diff --git a/scripts/immediate.js b/scripts/immediate.js new file mode 100644 index 0000000..2b6f76f --- /dev/null +++ b/scripts/immediate.js @@ -0,0 +1 @@ +module.exports = setTimeout diff --git a/scripts/node-globals.js b/scripts/node-globals.js index ee3c67f..2936df1 100644 --- a/scripts/node-globals.js +++ b/scripts/node-globals.js @@ -1,2 +1,3 @@ // @ts-nocheck -export const { Buffer } = require('buffer') \ No newline at end of file +export const { Buffer } = require('buffer') +export const setImmediate = global.setImmediate diff --git a/src/index.js b/src/index.js index 0596c18..d217df5 100644 --- a/src/index.js +++ b/src/index.js @@ -1,14 +1,11 @@ -'use strict' - -const { - Key, Errors, Adapter, - utils: { - sortAll - } -} = require('interface-datastore') -const filter = require('it-filter') -const map = require('it-map') -const take = require('it-take') +import { Key } from 'interface-datastore' +import { BaseDatastore, Errors } from 'datastore-core' +import filter from 'it-filter' +import map from 'it-map' +import take from 'it-take' +import sort from 'it-sort' +// @ts-ignore no types +import Level from 'level' /** * @typedef {import('interface-datastore').Datastore} Datastore @@ -24,7 +21,7 @@ const take = require('it-take') * * @implements {Datastore} */ -class LevelDatastore extends Adapter { +export class LevelDatastore extends BaseDatastore { /** * @param {any} path * @param {Object} [opts] @@ -50,7 +47,7 @@ class LevelDatastore extends Adapter { delete opts.db } else { // @ts-ignore - this.database = require('level') + this.database = Level } } @@ -183,7 +180,7 @@ class LevelDatastore extends Adapter { } if (Array.isArray(q.orders)) { - it = q.orders.reduce((it, f) => sortAll(it, f), it) + it = q.orders.reduce((it, f) => sort(it, f), it) } const { offset, limit } = q @@ -213,7 +210,7 @@ class LevelDatastore extends Adapter { } if (Array.isArray(q.orders)) { - it = q.orders.reduce((it, f) => sortAll(it, f), it) + it = q.orders.reduce((it, f) => sort(it, f), it) } const { offset, limit } = q @@ -293,5 +290,3 @@ function levelIteratorToIterator (li) { } } } - -module.exports = LevelDatastore diff --git a/test/browser.js b/test/browser.js index 55385dc..73bf40a 100644 --- a/test/browser.js +++ b/test/browser.js @@ -1,17 +1,16 @@ /* eslint-env mocha */ -'use strict' -const { MountDatastore } = require('datastore-core') -const { Key } = require('interface-datastore') +import { MountDatastore } from 'datastore-core' +import { Key } from 'interface-datastore/key' // @ts-ignore -const leveljs = require('level') -const LevelStore = require('../src') +import leveljs from 'level' +import { LevelDatastore } from '../src/index.js' +import { interfaceDatastoreTests } from 'interface-datastore-tests' describe('LevelDatastore', () => { describe('interface-datastore (leveljs)', () => { - // @ts-ignore - require('interface-datastore-tests')({ - setup: () => new LevelStore('hello', { db: leveljs }), + interfaceDatastoreTests({ + setup: () => new LevelDatastore('hello', { db: leveljs }), teardown: () => new Promise((resolve, reject) => { // @ts-ignore leveljs.destroy('hello', err => { @@ -23,18 +22,17 @@ describe('LevelDatastore', () => { }) describe('interface-datastore (mount(leveljs, leveljs, leveljs))', () => { - // @ts-ignore - require('interface-datastore-tests')({ + interfaceDatastoreTests({ setup () { return new MountDatastore([{ prefix: new Key('/a'), - datastore: new LevelStore('one', { db: leveljs }) + datastore: new LevelDatastore('one', { db: leveljs }) }, { prefix: new Key('/q'), - datastore: new LevelStore('two', { db: leveljs }) + datastore: new LevelDatastore('two', { db: leveljs }) }, { prefix: new Key('/z'), - datastore: new LevelStore('three', { db: leveljs }) + datastore: new LevelDatastore('three', { db: leveljs }) }]) }, teardown () { diff --git a/test/fixtures/test-level-iterator-destroy.js b/test/fixtures/test-level-iterator-destroy.js index b558fd6..ef3892e 100644 --- a/test/fixtures/test-level-iterator-destroy.js +++ b/test/fixtures/test-level-iterator-destroy.js @@ -1,13 +1,14 @@ -'use strict' - -const { utils, Key } = require('interface-datastore') -const LevelStore = require('../../src') +import { Key } from 'interface-datastore/key' +import { LevelDatastore } from '../../src/index.js' +import tempdir from 'ipfs-utils/src/temp-dir.js' +// @ts-ignore no types +import Level from 'level' async function testLevelIteratorDestroy () { // @ts-ignore - const store = new LevelStore(utils.tmpdir(), { db: require('level') }) + const store = new LevelDatastore(tempdir(), { db: Level }) await store.open() - await store.put(new Key(`/test/key${Date.now()}`), Buffer.from(`TESTDATA${Date.now()}`)) + await store.put(new Key(`/test/key${Date.now()}`), new TextEncoder().encode(`TESTDATA${Date.now()}`)) for await (const d of store.query({})) { console.log(d) // eslint-disable-line no-console } diff --git a/test/index.spec.js b/test/index.spec.js index b0a4f06..f9a627b 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -1,18 +1,18 @@ /* eslint-env mocha */ -'use strict' -const { expect } = require('aegir/utils/chai') +import { expect } from 'aegir/utils/chai.js' // @ts-ignore -const levelmem = require('level-mem') +import levelmem from 'level-mem' // @ts-ignore -const level = require('level') -const LevelStore = require('../src') -const { utils } = require('interface-datastore') +import level from 'level' +import { LevelDatastore } from '../src/index.js' +import tempdir from 'ipfs-utils/src/temp-dir.js' +import { interfaceDatastoreTests } from 'interface-datastore-tests' describe('LevelDatastore', () => { describe('initialization', () => { it('should default to a leveldown database', async () => { - const levelStore = new LevelStore('init-default') + const levelStore = new LevelDatastore('init-default') await levelStore.open() expect(levelStore.db.options).to.include({ @@ -25,7 +25,7 @@ describe('LevelDatastore', () => { }) it('should be able to override the database', async () => { - const levelStore = new LevelStore('init-default', { + const levelStore = new LevelDatastore('init-default', { db: levelmem, createIfMissing: true, errorIfExists: true @@ -42,9 +42,8 @@ describe('LevelDatastore', () => { ;[levelmem, level].forEach(database => { describe(`interface-datastore ${database.name}`, () => { - // @ts-ignore - require('interface-datastore-tests')({ - setup: () => new LevelStore(utils.tmpdir(), { db: database }), + interfaceDatastoreTests({ + setup: () => new LevelDatastore(tempdir(), { db: database }), teardown () {} }) }) diff --git a/test/node.js b/test/node.js index 66d8717..a531c3e 100644 --- a/test/node.js +++ b/test/node.js @@ -1,55 +1,53 @@ /* eslint-env mocha */ -'use strict' -const { expect } = require('aegir/utils/chai') -const path = require('path') -const { Key, utils } = require('interface-datastore') +import { expect } from 'aegir/utils/chai.js' +import path from 'path' +import { Key } from 'interface-datastore/key' +import rimraf from 'rimraf' +import { MountDatastore } from 'datastore-core' +import { CID } from 'multiformats/cid' +import * as Digest from 'multiformats/hashes/digest' +import * as dagCbor from '@ipld/dag-cbor' +import { promisify } from 'util' +import childProcess from 'child_process' // @ts-ignore -const rimraf = require('rimraf') -const { MountDatastore } = require('datastore-core') -const { CID } = require('multiformats/cid') -const Digest = require('multiformats/hashes/digest') -const dagCbor = require('@ipld/dag-cbor') -const { promisify } = require('util') -const childProcess = require('child_process') +import level from 'level' // @ts-ignore -const level = require('level') -// @ts-ignore -const tests = require('interface-datastore-tests') - -const LevelStore = require('../src') +import { interfaceDatastoreTests } from 'interface-datastore-tests' +import { LevelDatastore } from '../src/index.js' +import tempdir from 'ipfs-utils/src/temp-dir.js' describe('LevelDatastore', () => { describe('interface-datastore (leveldown)', () => { - const dir = utils.tmpdir() - tests({ - setup: () => new LevelStore(dir, { db: level }), + const dir = tempdir() + interfaceDatastoreTests({ + setup: () => new LevelDatastore(dir, { db: level }), teardown: () => promisify(rimraf)(dir) }) }) describe('interface-datastore (mount(leveldown, leveldown, leveldown))', () => { const dirs = [ - utils.tmpdir(), - utils.tmpdir(), - utils.tmpdir() + tempdir(), + tempdir(), + tempdir() ] - tests({ + interfaceDatastoreTests({ setup () { return new MountDatastore([{ prefix: new Key('/a'), - datastore: new LevelStore(dirs[0], { + datastore: new LevelDatastore(dirs[0], { db: level }) }, { prefix: new Key('/q'), - datastore: new LevelStore(dirs[1], { + datastore: new LevelDatastore(dirs[1], { db: level }) }, { prefix: new Key('/z'), - datastore: new LevelStore(dirs[2], { + datastore: new LevelDatastore(dirs[2], { db: level }) }]) @@ -61,7 +59,7 @@ describe('LevelDatastore', () => { }) it.skip('interop with go', async () => { - const store = new LevelStore(path.join(__dirname, 'test-repo', 'datastore'), { + const store = new LevelDatastore(path.join(__dirname, 'test-repo', 'datastore'), { db: level }) @@ -91,7 +89,7 @@ describe('LevelDatastore', () => { // // https://github.com/Level/leveldown/blob/d3453fbde4d2a8aa04d9091101c25c999649069b/binding.cc#L545 it('should not leave iterators open and leak memory', (done) => { - const cp = childProcess.fork(path.join(__dirname, '/fixtures/test-level-iterator-destroy'), { stdio: 'pipe' }) + const cp = childProcess.fork(path.join(process.cwd(), '/test/fixtures/test-level-iterator-destroy'), { stdio: 'pipe' }) let out = '' const { stdout, stderr } = cp diff --git a/tsconfig.json b/tsconfig.json index fe3cbd6..c743414 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,7 @@ { "extends": "aegir/src/config/tsconfig.aegir.json", "compilerOptions": { - "outDir": "dist" + "outDir": "types" }, "include": [ "test",