From 498d8629a34699bb7f34b264a0a7127f25343480 Mon Sep 17 00:00:00 2001 From: Nodari Chkuaselidze Date: Sun, 18 Jun 2023 13:32:42 +0400 Subject: [PATCH 1/3] pkg: add type lints. --- .github/workflows/node.js.yml | 5 +- lib/bdb.js | 5 +- lib/db.js | 60 ++++++++++---- lib/level-browser.js | 9 +- lib/level.js | 7 ++ lib/memdb.js | 120 +++++++++++++-------------- lib/rbt.js | 150 +++++++++++++++++++++------------- package-lock.json | 17 +++- package.json | 6 +- tsconfig.json | 31 +++++++ 10 files changed, 265 insertions(+), 145 deletions(-) create mode 100644 tsconfig.json diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index f4666b6..6e245ff 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -12,11 +12,14 @@ jobs: node-version: 18.x - name: Install bslint - run: npm i -g bslint + run: npm i -g bslint typescript - name: Lint run: npm run lint + - name: Lint types + run: npm run lint-types + build: name: Build & Test runs-on: ${{matrix.os}} diff --git a/lib/bdb.js b/lib/bdb.js index e5c06d8..ac32fa5 100644 --- a/lib/bdb.js +++ b/lib/bdb.js @@ -26,9 +26,12 @@ exports.create = (options) => { const {memory, location} = options; - if (memory) + if (memory) { + // @ts-ignore return new DB(MemDB, 'memory', options); + } + // @ts-ignore return new DB(Level, location, options); }; diff --git a/lib/db.js b/lib/db.js index d2434d4..e7a7076 100644 --- a/lib/db.js +++ b/lib/db.js @@ -35,15 +35,55 @@ const iteratorTypes = { ITER_TYPE_KEY_VAL }; +/** @typedef {import('./memdb')} MemDB */ +/** @typedef {import('./level')} LevelDB */ + +/** + * @typedef {Object} MemDBClass + * @property {(location: string, callback: function) => void} destroy + * @property {(location: string, callback: function) => void} repair + * @property {(location: string) => void} backup + */ +/** + * @typedef {Object} LevelDBClass + * @property {(location: string, callback: function) => void} destroy + * @property {(location: string, callback: function) => void} repair + * @property {(location: string) => void} backup + */ + /** * DB */ class DB { + /** @type {DBOptions} */ + options; + + /** @type {LevelDBClass|MemDBClass} */ + backend; + + /** @type {String} */ + location; + + /** @type {boolean} */ + loading; + + /** @type {boolean} */ + closing; + + /** @type {boolean} */ + loaded; + + /** @type {boolean} */ + leveldown; + + /** @type {LevelDB|MemDB} */ + binding; + /** * Create a DB instance. * @constructor - * @param {Function} backend - Database backend. + * @param {MemDBClass|LevelDBClass} backend - Database backend. * @param {String} location - File location. * @param {Object?} options - Leveldown options. */ @@ -75,10 +115,13 @@ class DB { const Backend = this.backend; // A lower-level binding. + // @ts-ignore if (Backend.leveldown) { + // @ts-ignore this.binding = new Backend(this.location); this.leveldown = true; } else { + // @ts-ignore this.binding = new Backend(this.location); } } @@ -202,17 +245,7 @@ class DB { */ backup(path) { - if (!this.binding.backup) - return this.clone(path); - - return new Promise((resolve, reject) => { - if (!this.loaded) { - reject(new Error('Database is closed.')); - return; - } - - this.binding.backup(path, wrap(resolve, reject)); - }); + return this.clone(path); } /** @@ -227,7 +260,7 @@ class DB { /** * Get root bucket. - * @returns {Bucket} + * @returns {DB} */ root() { @@ -839,7 +872,6 @@ class Bucket { * @constructor * @ignore * @param {DB} db - * @param {Batch} batch * @param {Buffer} prefix */ diff --git a/lib/level-browser.js b/lib/level-browser.js index 53b0f43..6792818 100644 --- a/lib/level-browser.js +++ b/lib/level-browser.js @@ -171,7 +171,9 @@ class Level { if (result === undefined) { const err = new Error('IDB_NOTFOUND: Key not found.'); + // @ts-ignore err.notFound = true; + // @ts-ignore err.type = 'NotFoundError'; callback(err); return; @@ -284,7 +286,7 @@ class Batch { /** * Insert a record. - * @param {Buffer|String} key + * @param {Buffer} key * @param {Buffer} value */ @@ -296,7 +298,7 @@ class Batch { /** * Remove a record. - * @param {Buffer|String} key + * @param {Buffer} key */ del(key) { @@ -397,7 +399,7 @@ class BatchOp { * @ignore * @param {String} type * @param {Buffer} key - * @param {Buffer|null} value + * @param {Buffer} [value=null] */ constructor(type, key, value) { @@ -534,6 +536,7 @@ class Iterator { total += 1; } + /** @type {Buffer|String} */ let key = Buffer.from(cursor.key, 'hex'); let value = cursor.value; diff --git a/lib/level.js b/lib/level.js index e47c299..d6d8e74 100644 --- a/lib/level.js +++ b/lib/level.js @@ -88,6 +88,13 @@ class LevelDOWN { binding.db_approximate_size(this.context, start, end, callback); } + /** + * @param {Buffer} start + * @param {Buffer} end + * @param {(key: Buffer, value: Buffer) => void} callback + * @returns {void} + */ + compactRange(start, end, callback) { assert(isValue(start)); assert(isValue(end)); diff --git a/lib/memdb.js b/lib/memdb.js index 87cc845..368af0c 100644 --- a/lib/memdb.js +++ b/lib/memdb.js @@ -10,6 +10,13 @@ const assert = require('bsert'); const RBT = require('./rbt'); const DUMMY = Buffer.alloc(0); +/** @typedef {import('./rbt').RBTData} RBTData */ + +/** + * @callback ImmediateCB + * @returns {void} + */ + /** * MemDB */ @@ -18,9 +25,7 @@ class MemDB { /** * Create a memdb. * @constructor - * @param {String?} location - Phony location. - * @param {Object?} options - * @param {Function} options.compare - Comparator. + * @param {String} [location='memory'] - Phony location. */ constructor(location) { @@ -52,7 +57,6 @@ class MemDB { /** * Insert a record. - * @private * @param {Buffer|String} key * @param {Buffer} value */ @@ -75,7 +79,6 @@ class MemDB { /** * Remove a record. - * @private * @param {Buffer|String} key * @returns {Boolean} */ @@ -92,8 +95,8 @@ class MemDB { /** * Traverse between a range of keys and collect records. * @private - * @param {Buffer} min - * @param {Buffer} max + * @param {Buffer|String} min + * @param {Buffer|String} max * @returns {RBTData[]} Records. */ @@ -113,7 +116,7 @@ class MemDB { /** * Open the database (leveldown method). * @param {Object?} options - * @param {Function} callback + * @param {ImmediateCB} callback */ open(options, callback) { @@ -132,7 +135,7 @@ class MemDB { /** * Close the database (leveldown method). - * @param {Function} callback + * @param {ImmediateCB} callback */ close(callback) { @@ -142,30 +145,20 @@ class MemDB { /** * Retrieve a record (leveldown method). * @param {Buffer|String} key - * @param {Object?} options * @param {Function} callback - Returns Buffer. */ - get(key, options, callback) { - if (!callback) { - callback = options; - options = null; - } - - if (!options) - options = {}; - + get(key, callback) { + /** @type {Buffer|String} */ let value = this.search(key); if (!value) { - const err = new Error('MEMDB_NOTFOUND: Key not found.'); - err.notFound = true; - err.type = 'NotFoundError'; + const err = new NotFoundError('MEMDB_NOTFOUND: Key not found.'); setImmediate(() => callback(err)); return; } - if (options.asBuffer === false) + if (this.options.asBuffer === false) value = value.toString('utf8'); setImmediate(() => callback(null, value)); @@ -175,54 +168,34 @@ class MemDB { * Insert a record (leveldown method). * @param {Buffer|String} key * @param {Buffer} value - * @param {Object?} options - * @param {Function} callback + * @param {ImmediateCB} callback */ - put(key, value, options, callback) { - if (!callback) { - callback = options; - options = null; - } - + put(key, value, callback) { this.insert(key, value); - setImmediate(callback); } /** * Remove a record (leveldown method). * @param {Buffer|String} key - * @param {Object?} options - * @param {Function} callback + * @param {ImmediateCB} callback */ - del(key, options, callback) { - if (!callback) { - callback = options; - options = null; - } - + del(key, callback) { this.remove(key); - setImmediate(callback); } /** * Create an atomic batch (leveldown method). * @see Leveldown.Batch - * @param {Object[]?} ops - * @param {Object?} options - * @param {Function} callback + * @param {Object[]} [ops] + * @param {Function} [callback] */ - batch(ops, options, callback) { - if (!callback) { - callback = options; - options = null; - } - - const b = new Batch(this, options); + batch(ops, callback) { + const b = new Batch(this); if (ops) { b.ops = ops; @@ -236,7 +209,7 @@ class MemDB { /** * Create an iterator (leveldown method). * @param {Object} options - See {Leveldown.Iterator}. - * @returns {Leveldown.Iterator}. + * @returns {Iterator}. */ iterator(options) { @@ -276,7 +249,7 @@ class MemDB { /** * Destroy the database (leveldown function) (NOP). * @param {String} location - * @param {Function} callback + * @param {ImmediateCB} callback */ static destroy(location, callback) { @@ -286,12 +259,16 @@ class MemDB { /** * Repair the database (leveldown function) (NOP). * @param {String} location - * @param {Function} callback + * @param {ImmediateCB} callback */ static repair(location, callback) { setImmediate(callback); } + + compactRange() { + throw new Error('Not implemented.'); + } } /** @@ -304,11 +281,9 @@ class Batch { * @constructor * @ignore * @param {MemDB} db - * @param {Object?} options */ - constructor(db, options) { - this.options = options || {}; + constructor(db) { this.ops = []; this.db = db; this.written = false; @@ -316,7 +291,7 @@ class Batch { /** * Insert a record. - * @param {Buffer|String} key + * @param {Buffer} key * @param {Buffer} value */ @@ -328,7 +303,7 @@ class Batch { /** * Remove a record. - * @param {Buffer|String} key + * @param {Buffer} key */ del(key) { @@ -365,7 +340,7 @@ class Batch { this.ops = []; this.written = true; - setImmediate(callback); + setImmediate(() => callback); return this; } @@ -392,7 +367,7 @@ class BatchOp { * @ignore * @param {String} type * @param {Buffer} key - * @param {Buffer|null} value + * @param {Buffer} [value=null] */ constructor(type, key, value) { @@ -411,7 +386,7 @@ class Iterator { * Create an iterator. * @constructor * @ignore - * @param {RBT} db + * @param {MemDB} db * @param {Object?} options */ @@ -502,14 +477,14 @@ class Iterator { if (!result) { this.iter = null; - setImmediate(callback); + setImmediate(() => callback()); return; } if (options.limit !== -1) { if (this.total >= options.limit) { this.iter = null; - setImmediate(callback); + setImmediate(() => callback()); return; } this.total += 1; @@ -566,7 +541,7 @@ class Iterator { this.ended = true; this.iter = null; - setImmediate(callback); + setImmediate(() => callback()); } } @@ -668,6 +643,21 @@ class IteratorOptions { } } +class NotFoundError extends Error { + /** + * @param {String} message + */ + + constructor(message) { + super(message); + this.type = 'NotFoundError'; + this.notFound = true; + + if (Error.captureStackTrace) + Error.captureStackTrace(this, NotFoundError); + } +} + /* * Helpers */ diff --git a/lib/rbt.js b/lib/rbt.js index 4901943..6100f7f 100644 --- a/lib/rbt.js +++ b/lib/rbt.js @@ -48,7 +48,7 @@ class RBT { /** * Do a key lookup. * @param {Buffer|String} key - * @returns {Buffer?} value + * @returns {RBTNode|null} value */ search(key) { @@ -71,7 +71,7 @@ class RBT { /** * Insert a record. - * @param {Buffer|String} key + * @param {Buffer} key * @param {Buffer} value */ @@ -137,17 +137,17 @@ class RBT { x.parent.color = BLACK; y.color = BLACK; x.parent.parent.color = RED; - x = x.parent.parent; + x = /** @type {RBTNode}*/(x.parent.parent); } else { if (x === x.parent.right) { - x = x.parent; + x = /** @type {RBTNode}*/(x.parent); this.rotl(x); } x.parent.color = BLACK; x.parent.parent.color = RED; - this.rotr(x.parent.parent); + this.rotl(/** @type {RBTNode}*/(x.parent.parent)); } } else { const y = x.parent.parent.left; @@ -156,17 +156,17 @@ class RBT { x.parent.color = BLACK; y.color = BLACK; x.parent.parent.color = RED; - x = x.parent.parent; + x = /** @type {RBTNode} */(x.parent.parent); } else { if (x === x.parent.left) { - x = x.parent; + x = /** @type {RBTNode} */(x.parent); this.rotr(x); } x.parent.color = BLACK; x.parent.parent.color = RED; - this.rotl(x.parent.parent); + this.rotl(/** @type {RBTNode}*/(x.parent.parent)); } } } @@ -231,7 +231,7 @@ class RBT { } if (y.color === BLACK) - this.removeFixup(x); + this.removeFixup(/** @type {RBTNode}*/(x)); } /** @@ -248,18 +248,18 @@ class RBT { if (w.color === RED) { w.color = BLACK; x.parent.color = RED; - this.rotl(x.parent); + this.rotl(/** @type {RBTNode}*/(x.parent)); w = x.parent.right; } if (w.left.color === BLACK && w.right.color === BLACK) { w.color = RED; - x = x.parent; + x = /** @type {RBTNode} */(x.parent); } else { if (w.right.color === BLACK) { w.left.color = BLACK; w.color = RED; - this.rotr(w); + this.rotr(/** @type {RBTNode} */(w)); w = x.parent.right; } @@ -267,7 +267,7 @@ class RBT { x.parent.color = BLACK; w.right.color = BLACK; - this.rotl(x.parent); + this.rotl(/** @type {RBTNode} */(x.parent)); x = this.root; } @@ -277,18 +277,18 @@ class RBT { if (w.color === RED) { w.color = BLACK; x.parent.color = RED; - this.rotr(x.parent); + this.rotr(/** @type {RBTNode} */(x.parent)); w = x.parent.left; } if (w.right.color === BLACK && w.left.color === BLACK) { w.color = RED; - x = x.parent; + x = /** @type {RBTNode} */(x.parent); } else { if (w.left.color === BLACK) { w.right.color = BLACK; w.color = RED; - this.rotl(w); + this.rotl(/** @type {RBTNode} */(w)); w = x.parent.left; } @@ -296,7 +296,7 @@ class RBT { x.parent.color = BLACK; w.left.color = BLACK; - this.rotr(x.parent); + this.rotr(/** @type {RBTNode} */(x.parent)); x = this.root; } @@ -366,7 +366,6 @@ class RBT { /** * Minimum subtree. - * @private * @param {RBTNode} z * @returns {RBTNode} */ @@ -376,14 +375,13 @@ class RBT { return z; while (!z.left.isNull()) - z = z.left; + z = /** @type {RBTNode} */(z.left); return z; } /** * Maximum subtree. - * @private * @param {RBTNode} z * @returns {RBTNode} */ @@ -393,24 +391,23 @@ class RBT { return z; while (!z.right.isNull()) - z = z.right; + z = /** @type {RBTNode} */(z.right); return z; } /** * Successor node. - * @private * @param {RBTNode} x * @returns {RBTNode} */ successor(x) { if (!x.right.isNull()) { - x = x.right; + x = /** @type {RBTNode} */(x.right); while (!x.left.isNull()) - x = x.left; + x = /** @type {RBTNode} */(x.left); return x; } @@ -418,26 +415,25 @@ class RBT { let y = x.parent; while (!y.isNull() && x === y.right) { - x = y; + x = /** @type {RBTNode} */(y); y = y.parent; } - return y; + return /** @type {RBTNode} */(y); } /** * Predecessor node. - * @private * @param {RBTNode} x * @returns {RBTNode} */ predecessor(x) { if (!x.left.isNull()) { - x = x.left; + x = /** @type {RBTNode} */(x.left); while (!x.right.isNull()) - x = x.right; + x = /** @type {RBTNode} */(x.right); return x; } @@ -445,11 +441,11 @@ class RBT { let y = x.parent; while (!y.isNull() && x === y.left) { - x = y; + x = /** @type {RBTNode} */(y); y = y.parent; } - return y; + return /** @type {RBTNode} */(y); } /** @@ -528,7 +524,7 @@ class RBT { /** * Create an iterator. - * @param {RBTNode?} snapshot + * @param {RBTNode} [snapshot] * @returns {RBTIterator} */ @@ -540,11 +536,12 @@ class RBT { * Traverse between a range of keys and collect records. * @param {Buffer} min * @param {Buffer} max - * @returns {RBTNode[]} Records. + * @returns {RBTData[]} Records. */ range(min, max) { const iter = this.iterator(); + /** @type {RBTData[]} */ const items = []; if (min) @@ -637,7 +634,7 @@ class RBTIterator { /** * Seek to a key from the current node (gte). - * @param {String} key + * @param {Buffer} key */ seek(key) { @@ -646,7 +643,7 @@ class RBTIterator { /** * Seek to a key from the current node (gte). - * @param {String} key + * @param {Buffer} key */ seekMin(key) { @@ -665,9 +662,9 @@ class RBTIterator { if (cmp > 0) { current = root; - root = root.left; + root = /** @type {RBTNode} */(root.left); } else { - root = root.right; + root = /** @type {RBTNode} */(root.right); } } @@ -678,7 +675,7 @@ class RBTIterator { /** * Seek to a key from the current node (lte). - * @param {String} key + * @param {Buffer} key */ seekMax(key) { @@ -697,9 +694,9 @@ class RBTIterator { if (cmp < 0) { current = root; - root = root.right; + root = /** @type {RBTNode} */(root.right); } else { - root = root.left; + root = /** @type {RBTNode} */(root.left); } } @@ -710,7 +707,7 @@ class RBTIterator { /** * Seek to previous node. - * @param {String} key + * @returns {Boolean} */ prev() { @@ -762,17 +759,29 @@ class RBTIterator { */ class RBTNode { + /** @type {Buffer} */ + key; + + /** @type {Buffer} */ + value; + + /** @type {Number} */ + color; + + /** @type {RBTNode|RBTSentinel} */ + parent; + + /** @type {RBTNode|RBTSentinel} */ + left; + + /** @type {RBTNode|RBTSentinel} */ + right; + /** * Create an RBT node. * @constructor * @param {Buffer} key * @param {Buffer} value - * @property {Buffer} key - * @property {Buffer} value - * @property {Number} color - * @property {RBTNode|RBTSentinel} parent - * @property {RBTNode|RBTSentinel} left - * @property {RBTNode|RBTSentinel} right */ constructor(key, value) { @@ -840,15 +849,27 @@ class RBTNode { */ class RBTSentinel { + /** @type {null} */ + key; + + /** @type {null} */ + value; + + /** @type {Number} */ + color; + + /** @type {null} */ + parent; + + /** @type {null} */ + left; + + /** @type {null} */ + right; + /** * Create an RBT Sentinel Node. * @constructor - * @property {null} key - * @property {null} value - * @property {Number} [color=BLACK] - * @property {null} parent - * @property {null} left - * @property {null} right */ constructor() { @@ -885,13 +906,17 @@ class RBTSentinel { */ class RBTData { + /** @type {Buffer} */ + key; + + /** @type {Buffer} */ + value; + /** * Create an RBT key/value pair. * @constructor * @param {Buffer} key * @param {Buffer} value - * @property {Buffer} key - * @property {Buffer} value */ constructor(key, value) { @@ -906,18 +931,28 @@ class RBTData { SENTINEL = new RBTSentinel(); +/** + * @param {RBTNode|RBTSentinel} parent + * @param {RBTNode|RBTSentinel} node + */ + function copyLeft(parent, node) { if (!node.isNull()) { - parent.left = node.clone(); + parent.left = /** @type {RBTNode} */(node).clone(); parent.left.parent = parent; copyLeft(parent.left, node.left); copyRight(parent.left, node.right); } } +/** + * @param {RBTNode|RBTSentinel} parent + * @param {RBTNode|RBTSentinel} node + */ + function copyRight(parent, node) { if (!node.isNull()) { - parent.right = node.clone(); + parent.right = /** @type {RBTNode} */(node).clone(); parent.right.parent = parent; copyLeft(parent.right, node.left); copyRight(parent.right, node.right); @@ -928,4 +963,5 @@ function copyRight(parent, node) { * Expose */ +RBT.RBTData = RBTData; module.exports = RBT; diff --git a/package-lock.json b/package-lock.json index b34bd19..ef84d16 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,10 +14,11 @@ "loady": "~0.0.5" }, "devDependencies": { - "bmocha": "^2.1.0" + "bmocha": "^2.1.0", + "bts-type-deps": "^0.0.3" }, "engines": { - "node": ">=8.6.0" + "node": ">=12.0.0" } }, "node_modules/bmocha": { @@ -41,6 +42,12 @@ "node": ">=8.0.0" } }, + "node_modules/bts-type-deps": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/bts-type-deps/-/bts-type-deps-0.0.3.tgz", + "integrity": "sha512-OQHGWhX5amae6Vj6ShlGaQu0sNCICgJ5YspNZPRzfR5RobrD+wjm5vkZK/J3EH5b/ymxqSWo9VkiFNpCxjaG2Q==", + "dev": true + }, "node_modules/loady": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/loady/-/loady-0.0.5.tgz", @@ -62,6 +69,12 @@ "resolved": "https://registry.npmjs.org/bsert/-/bsert-0.0.10.tgz", "integrity": "sha512-NHNwlac+WPy4t2LoNh8pXk8uaIGH3NSaIUbTTRXGpE2WEbq0te/tDykYHkFK57YKLPjv/aGHmbqvnGeVWDz57Q==" }, + "bts-type-deps": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/bts-type-deps/-/bts-type-deps-0.0.3.tgz", + "integrity": "sha512-OQHGWhX5amae6Vj6ShlGaQu0sNCICgJ5YspNZPRzfR5RobrD+wjm5vkZK/J3EH5b/ymxqSWo9VkiFNpCxjaG2Q==", + "dev": true + }, "loady": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/loady/-/loady-0.0.5.tgz", diff --git a/package.json b/package.json index 0330fd3..335be03 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "scripts": { "install": "node-gyp rebuild", "lint": "eslint lib/ test/", + "lint-types": "tsc -p .", "test": "bmocha --reporter spec test/*-test.js" }, "dependencies": { @@ -25,10 +26,11 @@ "loady": "~0.0.5" }, "devDependencies": { - "bmocha": "^2.1.8" + "bmocha": "^2.1.8", + "bts-type-deps": "^0.0.3" }, "engines": { - "node": ">=8.6.0" + "node": ">=12.0.0" }, "gypfile": true, "browser": { diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..66e7ad5 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,31 @@ +{ + "include": [ + "lib/**/*.js" + ], + "compilerOptions": { + "rootDir": ".", + "target": "ES2016", + "lib": [ + "ES2016" + ], + + "noEmit": true, + + "allowJs": true, + "checkJs": true, + "maxNodeModuleJsDepth": 0, + + "module": "commonjs", + "moduleResolution": "node", + "resolveJsonModule": true, + + "stripInternal": true, + "noImplicitThis": true, + "noUnusedLocals": true, + "noUnusedParameters": false, + + "typeRoots": [ + "node_modules/bts-type-deps/types" + ] + } +} From f6b81782917bb2354165678b7c77b90d394a450c Mon Sep 17 00:00:00 2001 From: Nodari Chkuaselidze Date: Sun, 18 Jun 2023 14:37:55 +0400 Subject: [PATCH 2/3] type-lint: add details iterator options. --- .github/workflows/node.js.yml | 3 + lib/db.js | 192 +++++++++++++++++++++++++++------- package-lock.json | 14 +-- 3 files changed, 166 insertions(+), 43 deletions(-) diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 6e245ff..e6091ea 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -14,6 +14,9 @@ jobs: - name: Install bslint run: npm i -g bslint typescript + - name: Install dependencies + run: npm install + - name: Lint run: npm run lint diff --git a/lib/db.js b/lib/db.js index e7a7076..2ff2450 100644 --- a/lib/db.js +++ b/lib/db.js @@ -51,6 +51,77 @@ const iteratorTypes = { * @property {(location: string) => void} backup */ +/** + * @typedef {Object} IterOptions + * @property {Buffer} [gte] + * @property {Buffer} [gt] + * @property {Buffer} [lte] + * @property {Buffer} [lt] + * @property {boolean} [keys] + * @property {boolean} [values] + * @property {boolean} [fillCache] + * @property {boolean} [reverse] + * @property {number} [limit] + */ + +/** + * @template T + * @typedef {Object} RangeOptions + * @property {Buffer} [gte] + * @property {Buffer} [gt] + * @property {Buffer} [lte] + * @property {Buffer} [lt] + * @property {boolean} [reverse] + * @property {number} [limit] + * @property {EachCallback} [parse] + */ + +/** + * @template T + * @typedef {Object} KeysOptions + * @property {Buffer} [gte] + * @property {Buffer} [gt] + * @property {Buffer} [lte] + * @property {Buffer} [lt] + * @property {boolean} [reverse] + * @property {number} [limit] + * @property {KeysCallback} [parse] + */ + +/** + * @template T + * @typedef {Object} ValuesOptions + * @property {Buffer} [gte] + * @property {Buffer} [gt] + * @property {Buffer} [lte] + * @property {Buffer} [lt] + * @property {boolean} [reverse] + * @property {number} [limit] + * @property {ValuesCallback} [parse] + */ + +/** + * @template T + * @callback EachCallback + * @param {Buffer} key + * @param {Buffer} value + * @returns {T} + */ + +/** + * @template T + * @callback KeysCallback + * @param {Buffer} key + * @returns {T} + */ + +/** + * @template T + * @callback ValuesCallback + * @param {Buffer} value + * @returns {T} + */ + /** * DB */ @@ -290,7 +361,7 @@ class DB { /** * Retrieve a record from the database. * @param {Buffer} key - * @returns {Promise} - Returns Buffer. + * @returns {Promise} - Returns Buffer. */ get(key) { @@ -383,7 +454,7 @@ class DB { /** * Create an iterator. - * @param {Object} options + * @param {IterOptions} options * @returns {Iterator} */ @@ -414,7 +485,7 @@ class DB { * Calculate approximate database size. * @param {Buffer|null} start - Start key. * @param {Buffer|null} end - End key. - * @returns {Promise} - Returns Number. + * @returns {Promise} - Returns Number. */ approximateSize(start, end) { @@ -481,7 +552,7 @@ class DB { /** * Test whether a key exists. * @param {Buffer} key - * @returns {Promise} - Returns Boolean. + * @returns {Promise} - Returns Boolean. */ async has(key) { @@ -491,8 +562,9 @@ class DB { /** * Collect all keys from iterator options. - * @param {Object} options - Iterator options. - * @returns {Promise} - Returns Array. + * @template T + * @param {RangeOptions} [options] - Iterator options. + * @returns {Promise} - Returns Array. */ async range(options) { @@ -515,8 +587,9 @@ class DB { /** * Collect all keys from iterator options. - * @param {Object} options - Iterator options. - * @returns {Promise} - Returns Array. + * @template T + * @param {KeysOptions} [options] - Iterator options. + * @returns {Promise} - Returns Array. */ async keys(options) { @@ -539,8 +612,9 @@ class DB { /** * Collect all keys from iterator options. - * @param {Object} options - Iterator options. - * @returns {Promise} - Returns Array. + * @template T + * @param {ValuesOptions} [options] - Iterator options. + * @returns {Promise} - Returns Array. */ async values(options) { @@ -1114,9 +1188,8 @@ class Iterator { /** * Create an iterator. * @constructor - * @ignore * @param {DB} db - * @param {Object} [options=null] + * @param {IterOptions} [options=null] * @param {Buffer} [prefix=null] */ @@ -1222,6 +1295,8 @@ class Iterator { /** * For each. + * @template T + * @param {EachCallback} cb * @returns {Promise} */ @@ -1379,24 +1454,33 @@ class Iterator { /** * Collect all keys and values from iterator options. - * @param {Function} parse - * @returns {Promise} - Returns Array. + * @template T + * @param {EachCallback} [parse] + * @returns {Promise} - Returns Array. */ async range(parse) { assert(!parse || typeof parse === 'function'); + if (!parse) { + /** @type {IteratorItem[]} */ + const items = []; + + await this.each((key, value) => { + items.push(new IteratorItem(key, value)); + }); + + return items; + } + + /** @type {T[]} */ const items = []; await this.each((key, value) => { - if (parse) { - const item = parse(key, value); + const item = parse(key, value); - if (item != null) - items.push(item); - } else { - items.push(new IteratorItem(key, value)); - } + if (item != null) + items.push(item); }); return items; @@ -1404,21 +1488,34 @@ class Iterator { /** * Collect all keys from iterator options. - * @param {Function} parse - * @returns {Promise} - Returns Array. + * @template T + * @param {KeysCallback} [parse] + * @returns {Promise} - Returns Array. */ async keys(parse) { assert(!parse || typeof parse === 'function'); + if (!parse) { + /** @type {Buffer[]} */ + const items = []; + + await this.each((key, value) => { + items.push(key); + }); + + return items; + } + + /** @type {T[]} */ const items = []; await this.each((key, value) => { - if (parse) - key = parse(key); + /** @type {T|null} */ + const parsed = parse(key); - if (key != null) - items.push(key); + if (parsed != null) + items.push(parsed); }); return items; @@ -1426,21 +1523,34 @@ class Iterator { /** * Collect all values from iterator options. - * @param {Function} parse - * @returns {Promise} - Returns Array. + * @template T + * @param {ValuesCallback} [parse] + * @returns {Promise} - Returns Array. */ async values(parse) { assert(!parse || typeof parse === 'function'); + if (!parse) { + /** @type {Buffer[]} */ + const items = []; + + await this.each((key, value) => { + items.push(value); + }); + + return items; + } + + /** @type {T[]} */ const items = []; await this.each((key, value) => { - if (parse) - value = parse(value); + /** @type {T|null} */ + const parsed = parse(value); - if (value != null) - items.push(value); + if (parsed != null) + items.push(parsed); }); return items; @@ -1563,7 +1673,6 @@ class IteratorItem { /** * Create an iterator item. * @constructor - * @ignore * @param {Buffer} key * @param {Buffer} value * @property {Buffer} key @@ -1674,11 +1783,22 @@ class DBOptions { */ class IteratorOptions { + /** @type {Buffer} */ + gte; + + /** @type {Buffer} */ + lte; + + /** @type {Buffer} */ + gt; + + /** @type {Buffer} */ + lt; + /** * Create iterator options. * @constructor - * @ignore - * @param {Object} options + * @param {IterOptions} options */ constructor(options) { diff --git a/package-lock.json b/package-lock.json index ef84d16..a425740 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "license": "MIT", "dependencies": { - "bsert": "~0.0.10", + "bsert": "~0.0.12", "loady": "~0.0.5" }, "devDependencies": { @@ -35,9 +35,9 @@ } }, "node_modules/bsert": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/bsert/-/bsert-0.0.10.tgz", - "integrity": "sha512-NHNwlac+WPy4t2LoNh8pXk8uaIGH3NSaIUbTTRXGpE2WEbq0te/tDykYHkFK57YKLPjv/aGHmbqvnGeVWDz57Q==", + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/bsert/-/bsert-0.0.12.tgz", + "integrity": "sha512-lUB0EMu4KhIf+VQ6RZJ7J3dFdohYSeta+gNgDi00Hi/t3k/W6xZlwm9PSSG0q7hJ2zW9Rsn5yaMPymETxroTRw==", "engines": { "node": ">=8.0.0" } @@ -65,9 +65,9 @@ "dev": true }, "bsert": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/bsert/-/bsert-0.0.10.tgz", - "integrity": "sha512-NHNwlac+WPy4t2LoNh8pXk8uaIGH3NSaIUbTTRXGpE2WEbq0te/tDykYHkFK57YKLPjv/aGHmbqvnGeVWDz57Q==" + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/bsert/-/bsert-0.0.12.tgz", + "integrity": "sha512-lUB0EMu4KhIf+VQ6RZJ7J3dFdohYSeta+gNgDi00Hi/t3k/W6xZlwm9PSSG0q7hJ2zW9Rsn5yaMPymETxroTRw==" }, "bts-type-deps": { "version": "0.0.3", From dde3eb67c0bc3a8337ff275d2c67d052d7fe26d6 Mon Sep 17 00:00:00 2001 From: Nodari Chkuaselidze Date: Fri, 1 Sep 2023 16:33:49 +0400 Subject: [PATCH 3/3] pkg: update package-lock. --- package-lock.json | 34 +++++----------------------------- 1 file changed, 5 insertions(+), 29 deletions(-) diff --git a/package-lock.json b/package-lock.json index a425740..73317d1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,7 +1,7 @@ { "name": "bdb", "version": "1.4.0", - "lockfileVersion": 2, + "lockfileVersion": 3, "requires": true, "packages": { "": { @@ -14,7 +14,7 @@ "loady": "~0.0.5" }, "devDependencies": { - "bmocha": "^2.1.0", + "bmocha": "^2.1.8", "bts-type-deps": "^0.0.3" }, "engines": { @@ -22,9 +22,9 @@ } }, "node_modules/bmocha": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/bmocha/-/bmocha-2.1.4.tgz", - "integrity": "sha512-aYDWPqYAi+rlZkIZsp4jsaaNB5E/KEa+Eq/vC+664fpRzWTeRgPi7zEHSSe7NdO/HBissuFrs6KH2JDCb3DUTg==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/bmocha/-/bmocha-2.1.8.tgz", + "integrity": "sha512-bog23Ckl9lRyBxrsi4FmX1rTz4d1WhHRpIA+q2lpoiXmNuroMHr1JUOU5sPiMZwvhLCxqffvWv3xCJC7PC126w==", "dev": true, "bin": { "_bmocha": "bin/_bmocha", @@ -56,29 +56,5 @@ "node": ">=8.0.0" } } - }, - "dependencies": { - "bmocha": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/bmocha/-/bmocha-2.1.4.tgz", - "integrity": "sha512-aYDWPqYAi+rlZkIZsp4jsaaNB5E/KEa+Eq/vC+664fpRzWTeRgPi7zEHSSe7NdO/HBissuFrs6KH2JDCb3DUTg==", - "dev": true - }, - "bsert": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/bsert/-/bsert-0.0.12.tgz", - "integrity": "sha512-lUB0EMu4KhIf+VQ6RZJ7J3dFdohYSeta+gNgDi00Hi/t3k/W6xZlwm9PSSG0q7hJ2zW9Rsn5yaMPymETxroTRw==" - }, - "bts-type-deps": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/bts-type-deps/-/bts-type-deps-0.0.3.tgz", - "integrity": "sha512-OQHGWhX5amae6Vj6ShlGaQu0sNCICgJ5YspNZPRzfR5RobrD+wjm5vkZK/J3EH5b/ymxqSWo9VkiFNpCxjaG2Q==", - "dev": true - }, - "loady": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/loady/-/loady-0.0.5.tgz", - "integrity": "sha512-uxKD2HIj042/HBx77NBcmEPsD+hxCgAtjEWlYNScuUjIsh/62Uyu39GOR68TBR68v+jqDL9zfftCWoUo4y03sQ==" - } } }