pax_global_header00006660000000000000000000000064135506170750014523gustar00rootroot0000000000000052 comment=07c4f8001644090ba2099cf259d688f25a7139f1 supports-1.0.1/000077500000000000000000000000001355061707500134215ustar00rootroot00000000000000supports-1.0.1/.gitignore000066400000000000000000000001121355061707500154030ustar00rootroot00000000000000npm-debug.log node_modules .idea yarn.lock package-lock.json .nyc_output/ supports-1.0.1/.travis.yml000066400000000000000000000001271355061707500155320ustar00rootroot00000000000000language: node_js node_js: - 6 - 8 - 10 - 12 after_success: npm run coverage supports-1.0.1/CHANGELOG.md000066400000000000000000000007371355061707500152410ustar00rootroot00000000000000# Changelog ## [1.0.1] - 2019-10-13 ### Added - Document format of `additionalMethods` ([`192bc9e`](https://github.com/Level/supports/commit/192bc9e)) ([**@vweevers**](https://github.com/vweevers)) ### Fixed - Clone `additionalMethods` to prevent mutation ([#4](https://github.com/Level/supports/issues/4)) ([**@vweevers**](https://github.com/vweevers)) ## 1.0.0 - 2019-09-22 :seedling: Initial release. [1.0.1]: https://github.com/Level/supports/compare/v1.0.0...v1.0.1 supports-1.0.1/CONTRIBUTORS.md000066400000000000000000000006151355061707500157020ustar00rootroot00000000000000# Contributors | Name | GitHub | Social | | :------------------ | :------------------------------------------- | :---------------------------------------------------- | | **Vincent Weevers** | [**@vweevers**](https://github.com/vweevers) | [**@vweevers@twitter**](https://twitter.com/vweevers) | supports-1.0.1/LICENSE.md000066400000000000000000000021301355061707500150210ustar00rootroot00000000000000# The MIT License (MIT) **Copyright © 2019-present [Contributors](CONTRIBUTORS.md).** Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. supports-1.0.1/README.md000066400000000000000000000153031355061707500147020ustar00rootroot00000000000000# level-supports > **Create a manifest describing the abilities of a [`levelup`](https://github.com/Level/levelup) or [`abstract-leveldown`](https://github.com/Level/abstract-leveldown) db.** [![level badge][level-badge]](https://github.com/Level/awesome) [![npm](https://img.shields.io/npm/v/level-supports.svg?label=&logo=npm)](https://www.npmjs.com/package/level-supports) [![Node version](https://img.shields.io/node/v/level-supports.svg)](https://www.npmjs.com/package/level-supports) [![Travis](https://img.shields.io/travis/com/Level/supports.svg?logo=travis&label=)](https://travis-ci.com/Level/supports) [![Coverage Status](https://coveralls.io/repos/github/Level/supports/badge.svg)](https://coveralls.io/github/Level/supports) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) [![Backers on Open Collective](https://opencollective.com/level/backers/badge.svg?color=orange)](#backers) [![Sponsors on Open Collective](https://opencollective.com/level/sponsors/badge.svg?color=orange)](#sponsors) ## Usage ```js const supports = require('level-supports') db.supports = supports({ bufferKeys: true, additionalMethods: { approximateSize: true } }) ``` Receivers of the db can then use it like so: ```js if (!db.supports.permanence) { throw new Error('Persistent storage is required') } if (db.supports.bufferKeys && db.supports.promises) { await db.put(Buffer.from('key'), 'value') } ``` ## API ### `manifest = supports([manifest, ..])` Given zero or more manifest objects, returns a merged and enriched manifest object that has: - Truthy properties for each of the features listed below - An `additionalMethods` object For future extensibility, the properties are truthy rather than strictly typed booleans. Falsy or absent properties are converted to `false`, other values are allowed: ```js supports().streams // false supports({ streams: true }).streams // true supports({ streams: {} }).streams // {} supports({ streams: 1 }, { streams: 2 }).streams // 2 ``` For consumers of the manifest this means they should check support like so: ```js if (db.supports.streams) ``` Rather than: ```js if (db.supports.streams === true) ``` **Note:** the manifest describes high-level features that typically encompass multiple methods of a db. It is currently not a goal to describe a full API, or versions of it. ## Features ### `bufferKeys` (boolean) Does the db support [Buffer](https://nodejs.org/api/buffer.html) keys? May depend on runtime environment as well. Does _not_ include support of other binary types like typed arrays (which is why this is called `bufferKeys` rather than `binaryKeys`). ### `snapshots` (boolean) Does the db have snapshot guarantees (meaning that reads are unaffected by simultaneous writes)? Must be `false` if any of the following is true: - Reads don't operate on a [snapshot](https://github.com/Level/abstract-leveldown#iterator) - Snapshots are created asynchronously. ### `permanence` (boolean) Does data survive after process exit? Is `false` for e.g. [`memdown`](https://github.com/Level/memdown), typically `true`. ### `seek` (boolean) Does `db.iterator()` support [`seek(..)`](https://github.com/Level/abstract-leveldown/#iteratorseektarget)? #### `clear` (boolean) Does db support [`db.clear(..)`](https://github.com/Level/abstract-leveldown/#dbclearoptions-callback)? For an overview, see [Level/community#79](https://github.com/Level/community/issues/79). ### `status` (boolean) Does db have a [`status`](https://github.com/Level/abstract-leveldown/#dbstatus) property? Currently available on `abstract-leveldown` implementations, but not `levelup`. ### `deferredOpen` (boolean) Can operations like `db.put()` be called without explicitly opening the db? Like so: ```js var db = level() db.put('key', 'value', callback) ``` Rather than: ```js var db = level() db.open(function (err) { if (err) throw err db.put('key', 'value', callback) }) ``` _TBD: whether this also includes methods like `isOpen()` and `isClosed()`._ ### `openCallback` (boolean) Does the db constructor take a callback? ```js var db = level(.., callback) ``` To the same effect as: ```js var db = level() db.open(.., callback) ``` ### `createIfMissing`, `errorIfExists` (boolean) Does `db.open(options, ..)` support these (`leveldown`) options? ### `promises` (boolean) Do all db methods (that don't otherwise have a return value) support promises, in addition to callbacks? Such that, when a callback argument is omitted, a promise is returned: ```js db.put('key', 'value', callback) await db.put('key', 'value') ``` _Note: iterators are currently exonerated because they, at the time of writing, don't support promises anywhere._ ### `streams` (boolean) Does db have the methods `createReadStream`, `createKeyStream` and `createValueStream`, following the API currently documented in `levelup`? ### `encodings` (boolean) Do all relevant db methods take `keyEncoding` and `valueEncoding` options? _TBD: what this means for `*asBuffer` options._ ### `additionalMethods` (object) In the form of: ```js { foo: true, bar: true } ``` Which says the db has two methods, `foo` and `bar`, that are not part of the `abstract-leveldown` interface. It might be used like so: ```js if (db.supports.additionalMethods.foo) { db.foo() } ``` For future extensibility, the properties of `additionalMethods` should be taken as truthy rather than strictly typed booleans. We may add additional metadata (see [#1](https://github.com/Level/supports/issues/1)). ## Install With [npm](https://npmjs.org) do: ``` npm install level-supports ``` ## Contributing [`Level/supports`](https://github.com/Level/supports) is an **OPEN Open Source Project**. This means that: > Individuals making significant and valuable contributions are given commit-access to the project to contribute as they see fit. This project is more like an open wiki than a standard guarded open source project. See the [Contribution Guide](https://github.com/Level/community/blob/master/CONTRIBUTING.md) for more details. ## Donate To sustain [`Level`](https://github.com/Level) and its activities, become a backer or sponsor on [Open Collective](https://opencollective.com/level). Your logo or avatar will be displayed on our 28+ [GitHub repositories](https://github.com/Level) and [npm](https://www.npmjs.com/) packages. 💖 ### Backers [![Open Collective backers](https://opencollective.com/level/backers.svg?width=890)](https://opencollective.com/level) ### Sponsors [![Open Collective sponsors](https://opencollective.com/level/sponsors.svg?width=890)](https://opencollective.com/level) ## License [MIT](LICENSE.md) © 2019-present [Contributors](CONTRIBUTORS.md). [level-badge]: https://leveljs.org/img/badge.svg supports-1.0.1/index.js000066400000000000000000000022041355061707500150640ustar00rootroot00000000000000'use strict' // For (old) browser support var xtend = require('xtend') var assign = require('xtend/mutable') module.exports = function supports () { var manifest = xtend.apply(null, arguments) return assign(manifest, { // Features of abstract-leveldown bufferKeys: manifest.bufferKeys || false, snapshots: manifest.snapshots || false, permanence: manifest.permanence || false, seek: manifest.seek || false, clear: manifest.clear || false, // Features of abstract-leveldown that levelup doesn't have status: manifest.status || false, // Features of disk-based implementations createIfMissing: manifest.createIfMissing || false, errorIfExists: manifest.errorIfExists || false, // Features of level(up) that abstract-leveldown doesn't have yet deferredOpen: manifest.deferredOpen || false, openCallback: manifest.openCallback || false, promises: manifest.promises || false, streams: manifest.streams || false, encodings: manifest.encodings || false, // Methods that are not part of abstract-leveldown or levelup additionalMethods: xtend(manifest.additionalMethods) }) } supports-1.0.1/package.json000066400000000000000000000024461355061707500157150ustar00rootroot00000000000000{ "name": "level-supports", "version": "1.0.1", "description": "Create a manifest describing the abilities of a levelup or abstract-leveldown db", "license": "MIT", "scripts": { "test": "standard && hallmark && (nyc -s node test/self.js | faucet) && nyc report", "test-browser-local": "airtap --coverage --local test/self.js", "coverage": "nyc report --reporter=text-lcov | coveralls", "hallmark": "hallmark --fix", "dependency-check": "dependency-check --no-dev . test/*.js", "prepublishOnly": "npm run dependency-check" }, "files": [ "test", "CHANGELOG.md", "CONTRIBUTORS.md", "index.js" ], "dependencies": { "xtend": "^4.0.2" }, "devDependencies": { "airtap": "^2.0.4", "coveralls": "^3.0.6", "dependency-check": "^4.1.0", "faucet": "^0.0.1", "hallmark": "^2.0.0", "level-community": "^3.0.0", "nyc": "^14.1.1", "standard": "^14.3.1", "tape": "^4.11.0" }, "hallmark": { "community": "level-community" }, "repository": { "type": "git", "url": "https://github.com/Level/supports.git" }, "homepage": "https://github.com/Level/supports", "keywords": [ "abstract-leveldown", "database", "db", "level", "levelup", "manifest" ], "engines": { "node": ">=6" } } supports-1.0.1/test/000077500000000000000000000000001355061707500144005ustar00rootroot00000000000000supports-1.0.1/test/cloneable.js000066400000000000000000000014331355061707500166630ustar00rootroot00000000000000'use strict' var supports = require('..') // Every object in a manifest must have a unique identity, to avoid accidental // mutation. In supports() we only shallowly clone the manifest object itself // and additionalMethods. If in the future we add more objects to manifests, // this test will break and we'll know to start performing a deep clone. module.exports = function cloneable (t, manifest) { var copy = supports(manifest) verifyUnique(t, 'manifest', manifest, copy) } function verifyUnique (t, path, a, b) { if (isObject(a) && isObject(b)) { t.ok(a !== b, path + ' has unique identity') Object.keys(a).forEach(function (key) { verifyUnique(t, path + '.' + key, a[key], b[key]) }) } } function isObject (o) { return typeof o === 'object' && o !== null } supports-1.0.1/test/index.js000066400000000000000000000013621355061707500160470ustar00rootroot00000000000000'use strict' var xtend = require('xtend') var shape = require('./shape') var cloneable = require('./cloneable') module.exports = function suite (test, testCommon) { test('db has manifest', function (t) { var db = testCommon.factory() var manifest = db.supports shape(t, manifest) cloneable(t, manifest) var before = xtend(manifest, { additionalMethods: xtend(manifest.additionalMethods) }) db.open(function (err) { t.ifError(err, 'no open error') t.same(db.supports, before, 'manifest did not change after open') db.close(function (err) { t.ifError(err, 'no close error') t.same(db.supports, before, 'manifest did not change after close') t.end() }) }) }) } supports-1.0.1/test/self.js000066400000000000000000000034341355061707500156730ustar00rootroot00000000000000'use strict' var test = require('tape') var supports = require('..') var shape = require('./shape') var cloneable = require('./cloneable') test('no options', function (t) { shape(t, supports()) cloneable(t, supports()) t.end() }) test('falsy options', function (t) { ;[null, false, undefined, 0, ''].forEach(function (value) { var manifest = supports({ bufferKeys: value, additionalMethods: { foo: value } }) shape(t, manifest) t.is(manifest.bufferKeys, false) }) t.end() }) test('truthy options', function (t) { ;[true, {}, 'yes', 1, []].forEach(function (value) { var manifest = supports({ streams: value, additionalMethods: { foo: value } }) shape(t, manifest) t.same(manifest.streams, value) t.same(manifest.additionalMethods.foo, value) }) t.end() }) test('merges input objects without mutating them', function (t) { var input1 = { bufferKeys: null, streams: false } var input2 = { streams: true, additionalMethods: {} } var manifest = supports(input1, input2) manifest.foobar = true manifest.additionalMethods.baz = true t.same(input1, { bufferKeys: null, streams: false }) t.same(input2, { streams: true, additionalMethods: {} }) t.is(manifest.bufferKeys, false) t.is(manifest.streams, true) shape(t, manifest) t.end() }) test('inherits additionalMethods', function (t) { var manifest = supports({ additionalMethods: { foo: true } }, {}) t.same(manifest.additionalMethods, { foo: true }) t.end() }) test('does not merge additionalMethods', function (t) { var input1 = { additionalMethods: { foo: true } } var input2 = { additionalMethods: { bar: true } } var manifest = supports(input1, input2) t.same(manifest.additionalMethods, { bar: true }) t.end() }) supports-1.0.1/test/shape.js000066400000000000000000000010211355061707500160300ustar00rootroot00000000000000'use strict' var hasOwnProperty = Object.prototype.hasOwnProperty module.exports = function shape (t, manifest) { t.ok(isObject(manifest), 'manifest is object') t.ok(isObject(manifest.additionalMethods), 'additionalMethods is object') for (var k in manifest) { if (!hasOwnProperty.call(manifest, k)) continue if (manifest[k]) { t.ok(manifest[k], 'truthy: ' + k) } else { t.is(manifest[k], false, 'false: ' + k) } } } function isObject (o) { return typeof o === 'object' && o !== null }