├── .airtap.yml ├── .github ├── dependabot.yml └── workflows │ └── test.yml ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTORS.md ├── LICENSE.md ├── README.md ├── UPGRADING.md ├── index.js ├── lib └── encodings.js ├── package.json └── test ├── as-buffer.js ├── batch.js ├── codec.js ├── decoder.js ├── kv.js └── ltgt.js /.airtap.yml: -------------------------------------------------------------------------------- 1 | providers: 2 | - airtap-playwright 3 | 4 | browsers: 5 | - name: chromium 6 | - name: firefox 7 | - name: webkit 8 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: / 5 | schedule: 6 | interval: monthly 7 | ignore: 8 | - dependency-name: dependency-check 9 | - dependency-name: standard 10 | - dependency-name: hallmark 11 | - package-ecosystem: github-actions 12 | directory: / 13 | schedule: 14 | interval: monthly 15 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | on: [push, pull_request] 3 | jobs: 4 | test: 5 | runs-on: ubuntu-latest 6 | strategy: 7 | matrix: 8 | node: [10, 12, 14] 9 | name: Node ${{ matrix.node }} 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v4 13 | - name: Use node ${{ matrix.node }} 14 | uses: actions/setup-node@v3 15 | with: 16 | node-version: ${{ matrix.node }} 17 | - name: Install 18 | run: npm install 19 | - name: Test 20 | run: npm test 21 | - name: Coverage 22 | run: npm run coverage 23 | - name: Codecov 24 | uses: codecov/codecov-action@v3 25 | with: 26 | file: coverage/lcov.info 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .nyc_output/ 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | _**If you are upgrading:** please see [`UPGRADING.md`](UPGRADING.md)._ 4 | 5 | ## [10.0.0] - 2021-04-09 6 | 7 | ### Changed 8 | 9 | - **Breaking:** remove legacy range options ([Level/community#86](https://github.com/Level/community/issues/86)) ([`73b19b4`](https://github.com/Level/codec/commit/73b19b4)) (Vincent Weevers) 10 | - **Breaking:** drop node 6 and 8 ([`38dc04c`](https://github.com/Level/codec/commit/38dc04c)) ([Level/community#98](https://github.com/Level/community/issues/98)) (Vincent Weevers) 11 | - **Breaking:** modernize syntax & bump `standard` to 16.x ([`874956f`](https://github.com/Level/codec/commit/874956f), [`e3ed6e4`](https://github.com/Level/codec/commit/e3ed6e4)) ([Level/community#98](https://github.com/Level/community/issues/98)) (Vincent Weevers). 12 | - **Breaking:** bump `buffer` from 15.x to 16.x ([#62](https://github.com/Level/codec/issues/62)) ([Level/community#98](https://github.com/Level/community/issues/98)) ([`78d2ea0`](https://github.com/Level/codec/commit/78d2ea0)) (Alex Potsides). 13 | 14 | ## [9.0.2] - 2020-06-26 15 | 16 | ### Changed 17 | 18 | - Upgrade `hallmark` devDependency from `^0.1.0` to `^2.0.0` ([#53](https://github.com/Level/codec/issues/53), [#56](https://github.com/Level/codec/issues/56)) ([**@vweevers**](https://github.com/vweevers)) 19 | - Upgrade `standard` devDependency from `^12.0.0` to `^14.0.0` ([#52](https://github.com/Level/codec/issues/52), [#55](https://github.com/Level/codec/issues/55)) ([**@vweevers**](https://github.com/vweevers)) 20 | - Upgrade `nyc` devDependency from `^13.2.0` to `^14.0.0` ([#50](https://github.com/Level/codec/issues/50)) ([**@vweevers**](https://github.com/vweevers)) 21 | 22 | ### Fixed 23 | 24 | - Add `buffer` dependency for browsers ([#58](https://github.com/Level/codec/issues/58)) ([**@hugomrdias**](https://github.com/hugomrdias)) 25 | 26 | ## [9.0.1] - 2019-04-01 27 | 28 | ### Changed 29 | 30 | - Upgrade `standard` devDependency from `^11.0.1` to `^12.0.0` ([#38](https://github.com/Level/codec/issues/38)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) 31 | - Update description in README and `package.json` ([#47](https://github.com/Level/codec/issues/47)) ([**@vweevers**](https://github.com/vweevers)) 32 | - Apply common project tweaks ([#39](https://github.com/Level/codec/issues/39), [#40](https://github.com/Level/codec/issues/40), [#41](https://github.com/Level/codec/issues/41)) ([**@vweevers**](https://github.com/vweevers)) 33 | - Tweak copyright year for less maintenance ([`79d2d02`](https://github.com/Level/codec/commit/79d2d02)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) 34 | 35 | ### Added 36 | 37 | - Add `nyc` and `coveralls` ([#36](https://github.com/Level/codec/issues/36), [#44](https://github.com/Level/codec/issues/44)) ([**@ralphtheninja**](https://github.com/ralphtheninja), [**@vweevers**](https://github.com/vweevers)) 38 | - Add `CHANGELOG.md` and `UPGRADING.md` ([#47](https://github.com/Level/codec/issues/47)) ([**@vweevers**](https://github.com/vweevers)) 39 | 40 | ### Removed 41 | 42 | - Remove node 9 from travis ([`ffe3f92`](https://github.com/Level/codec/commit/ffe3f92)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) 43 | - Remove experimental typings ([`1cfd23f`](https://github.com/Level/codec/commit/1cfd23f)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) 44 | 45 | ### Fixed 46 | 47 | - Fix subtests by adding `t.plan()` ([#46](https://github.com/Level/codec/issues/46)) ([**@vweevers**](https://github.com/vweevers)) 48 | 49 | ## [9.0.0] - 2018-05-12 50 | 51 | ### Changed 52 | 53 | - Update README ([#31](https://github.com/Level/codec/issues/31)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) 54 | 55 | ### Added 56 | 57 | - Add `standard` ([#29](https://github.com/Level/codec/issues/29)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) 58 | - Add node 9 and 10 ([`9476e58`](https://github.com/Level/codec/commit/9476e58)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) 59 | 60 | ### Removed 61 | 62 | - Drop node 0.12, 4, 5 and 7 ([`9476e58`](https://github.com/Level/codec/commit/9476e58), [#32](https://github.com/Level/codec/issues/32)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) 63 | 64 | ### Fixed 65 | 66 | - Fix constructor to work without `new` ([#30](https://github.com/Level/codec/issues/30)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) 67 | 68 | ## [8.0.0] - 2017-10-21 69 | 70 | ### Changed 71 | 72 | - Revert "fix utf-8 encoding returning buffers" ([#23](https://github.com/Level/codec/issues/23)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) 73 | 74 | ### Added 75 | 76 | - Add badges to `README` and stylize "levelup" ([#22](https://github.com/Level/codec/issues/22)) ([**@vweevers**](https://github.com/vweevers)) 77 | - Document encodings and their format in greater detail ([#22](https://github.com/Level/codec/issues/22)) ([**@vweevers**](https://github.com/vweevers)) 78 | 79 | ## [7.1.0] - 2017-09-12 80 | 81 | ### Changed 82 | 83 | - Update copyright year from 2015 to 2017 ([`aceb6ff`](https://github.com/Level/codec/commit/aceb6ff)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) 84 | 85 | ### Added 86 | 87 | - Add basic typings ([#18](https://github.com/Level/codec/issues/18)) ([**@MeirionHughes**](https://github.com/MeirionHughes)) 88 | - Add node 4, 5, 6, 7 and 8 ([`5c00a1c`](https://github.com/Level/codec/commit/5c00a1c)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) 89 | 90 | ### Removed 91 | 92 | - Drop node 0.10 and iojs ([`5c00a1c`](https://github.com/Level/codec/commit/5c00a1c)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) 93 | 94 | ## [7.0.1] - 2017-08-14 95 | 96 | ### Added 97 | 98 | - Add Greenkeeper ([#17](https://github.com/Level/codec/issues/17)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) 99 | 100 | ### Fixed 101 | 102 | - Use `identity` function consistently ([#14](https://github.com/Level/codec/issues/14)) ([**@dcousens**](https://github.com/dcousens)) 103 | 104 | ## [7.0.0] - 2017-01-26 105 | 106 | ### Fixed 107 | 108 | - Fix utf-8 encoding returning buffers ([#12](https://github.com/Level/codec/issues/12)) ([**@juliangruber**](https://github.com/juliangruber)) 109 | 110 | ## [6.2.0] - 2016-02-24 111 | 112 | ### Changed 113 | 114 | - Rename "id" encoding to "none", add "id" alias ([#10](https://github.com/Level/codec/issues/10)) ([**@juliangruber**](https://github.com/juliangruber)) 115 | - Upgrade `tape` devDependency ([#9](https://github.com/Level/codec/issues/9)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) 116 | 117 | ### Added 118 | 119 | - Document available encodings ([#10](https://github.com/Level/codec/issues/10)) ([**@juliangruber**](https://github.com/juliangruber)) 120 | 121 | ## [6.1.0] - 2015-10-21 122 | 123 | ### Added 124 | 125 | - Fallback to legacy `encoding` option if `valueEncoding` is not provided ([#8](https://github.com/Level/codec/issues/8)) ([**@dominictarr**](https://github.com/dominictarr)) 126 | 127 | ## [6.0.0] - 2015-05-04 128 | 129 | ### Changed 130 | 131 | - Replace `createDecodeStream()` with `createStreamDecoder()` ([#6](https://github.com/Level/codec/issues/6)) ([**@juliangruber**](https://github.com/juliangruber)) 132 | 133 | ## [5.5.0] - 2015-04-17 134 | 135 | ### Added 136 | 137 | - Add `createDecodeStream()` ([#5](https://github.com/Level/codec/issues/5)) ([**@juliangruber**](https://github.com/juliangruber)) 138 | 139 | ## [5.4.0] - 2015-04-17 140 | 141 | ### Changed 142 | 143 | - Simplify `encodeLtgt()` ([`24f3817`](https://github.com/Level/codec/commit/24f3817)) ([**@juliangruber**](https://github.com/juliangruber)) 144 | 145 | ## [5.3.0] - 2015-04-17 146 | 147 | ### Added 148 | 149 | - Add `encodeLtgt()` ([#4](https://github.com/Level/codec/issues/4)) ([**@juliangruber**](https://github.com/juliangruber)) 150 | 151 | ## [5.2.0] - 2015-03-24 152 | 153 | ### Changed 154 | 155 | - Make all options optional ([`4f942eb`](https://github.com/Level/codec/commit/4f942eb)) ([**@juliangruber**](https://github.com/juliangruber)) 156 | 157 | ## [5.1.0] - 2015-03-24 158 | 159 | ### Changed 160 | 161 | - Make member options optional ([`0c98ccb`](https://github.com/Level/codec/commit/0c98ccb)) ([**@juliangruber**](https://github.com/juliangruber)) 162 | 163 | ## [5.0.0] - 2015-03-24 164 | 165 | **Historical Note** 4.3.0 was meant to be a major release. 166 | 167 | ## [4.3.0] - 2015-03-24 168 | 169 | ### Changed 170 | 171 | - Rewrite ([`37f103e`](https://github.com/Level/codec/commit/37f103e), [`054fb3f`](https://github.com/Level/codec/commit/054fb3f), [`f510a90`](https://github.com/Level/codec/commit/f510a90)) ([**@juliangruber**](https://github.com/juliangruber)) 172 | 173 | ### Added 174 | 175 | - Add [**@ralphtheninja**](https://github.com/ralphtheninja) to contributors ([`dd2b9a0`](https://github.com/Level/codec/commit/dd2b9a0)) ([**@juliangruber**](https://github.com/juliangruber)) 176 | - Add travis and licensing ([#1](https://github.com/Level/codec/issues/1)) ([**@ralphtheninja**](https://github.com/ralphtheninja)) 177 | 178 | ## [4.2.0] - 2015-03-19 179 | 180 | ### Fixed 181 | 182 | - Keep batch `.prefix` for `level-sublevel` ([`f706482`](https://github.com/Level/codec/commit/f706482)) ([**@juliangruber**](https://github.com/juliangruber)) 183 | 184 | ## [4.1.0] - 2015-03-19 185 | 186 | ### Fixed 187 | 188 | - Set `batch` encodings to binary if `{key,value}AsBuffer` is true ([`bcf6feb`](https://github.com/Level/codec/commit/bcf6feb)) ([**@juliangruber**](https://github.com/juliangruber)) 189 | 190 | ## [4.0.1] - 2015-03-19 191 | 192 | ### Fixed 193 | 194 | - Skip falsy objects in `walk` ([`270ea17`](https://github.com/Level/codec/commit/270ea17)) ([**@juliangruber**](https://github.com/juliangruber)) 195 | 196 | ## [4.0.0] - 2015-03-19 197 | 198 | ### Removed 199 | 200 | - Remove default encoding ([`28a63b2`](https://github.com/Level/codec/commit/28a63b2)) ([**@juliangruber**](https://github.com/juliangruber)) 201 | 202 | ## [3.1.0] - 2015-03-19 203 | 204 | ### Added 205 | 206 | - Add experimental `Codec` class ([`8a189f4`](https://github.com/Level/codec/commit/8a189f4)) ([**@juliangruber**](https://github.com/juliangruber)) 207 | 208 | ## [3.0.0] - 2015-03-18 209 | 210 | ### Removed 211 | 212 | - Remove `encoding` option in favor of `keyEncoding` and `valueEncoding` ([`9fed84d`](https://github.com/Level/codec/commit/9fed84d)) ([**@juliangruber**](https://github.com/juliangruber)) 213 | 214 | ## [2.0.1] - 2015-03-18 215 | 216 | ### Fixed 217 | 218 | - Fix `encoding` option to only be an alias for `valueEncoding` ([`b4de4d1`](https://github.com/Level/codec/commit/b4de4d1)) ([**@juliangruber**](https://github.com/juliangruber)) 219 | 220 | ## [2.0.0] - 2015-03-18 221 | 222 | ### Changed 223 | 224 | - Remove side effects from `batch()` ([`bedaa26`](https://github.com/Level/codec/commit/bedaa26), [`6f5b373`](https://github.com/Level/codec/commit/6f5b373), [`abef01b`](https://github.com/Level/codec/commit/abef01b)) ([**@juliangruber**](https://github.com/juliangruber)) 225 | 226 | ## [1.2.1] - 2015-03-18 227 | 228 | ### Fixed 229 | 230 | - Fix `require` statements for `{key,value}AsBuffer()` ([`71bf7a5`](https://github.com/Level/codec/commit/71bf7a5)) ([**@juliangruber**](https://github.com/juliangruber)) 231 | 232 | ## [1.2.0] - 2015-03-18 233 | 234 | ### Added 235 | 236 | - Add `{key,value}AsBuffer()` ([`796a540`](https://github.com/Level/codec/commit/796a540)) ([**@juliangruber**](https://github.com/juliangruber)) 237 | 238 | ## [1.1.0] - 2015-03-18 239 | 240 | ### Added 241 | 242 | - Add `decode{Key,Value}` ([`029fbd7`](https://github.com/Level/codec/commit/029fbd7)) ([**@juliangruber**](https://github.com/juliangruber)) 243 | 244 | ## 1.0.1 - 2015-03-18 245 | 246 | :seedling: Initial release. 247 | 248 | [10.0.0]: https://github.com/Level/codec/compare/v9.0.2...v10.0.0 249 | 250 | [9.0.2]: https://github.com/Level/codec/compare/v9.0.1...v9.0.2 251 | 252 | [9.0.1]: https://github.com/Level/codec/compare/v9.0.0...v9.0.1 253 | 254 | [9.0.0]: https://github.com/Level/codec/compare/v8.0.0...v9.0.0 255 | 256 | [8.0.0]: https://github.com/Level/codec/compare/v7.1.0...v8.0.0 257 | 258 | [7.1.0]: https://github.com/Level/codec/compare/v7.0.1...v7.1.0 259 | 260 | [7.0.1]: https://github.com/Level/codec/compare/v7.0.0...v7.0.1 261 | 262 | [7.0.0]: https://github.com/Level/codec/compare/v6.2.0...v7.0.0 263 | 264 | [6.2.0]: https://github.com/Level/codec/compare/v6.1.0...v6.2.0 265 | 266 | [6.1.0]: https://github.com/Level/codec/compare/v6.0.0...v6.1.0 267 | 268 | [6.0.0]: https://github.com/Level/codec/compare/v5.5.0...v6.0.0 269 | 270 | [5.5.0]: https://github.com/Level/codec/compare/v5.4.0...v5.5.0 271 | 272 | [5.4.0]: https://github.com/Level/codec/compare/v5.3.0...v5.4.0 273 | 274 | [5.3.0]: https://github.com/Level/codec/compare/v5.2.0...v5.3.0 275 | 276 | [5.2.0]: https://github.com/Level/codec/compare/v5.1.0...v5.2.0 277 | 278 | [5.1.0]: https://github.com/Level/codec/compare/v5.0.0...v5.1.0 279 | 280 | [5.0.0]: https://github.com/Level/codec/compare/v4.3.0...v5.0.0 281 | 282 | [4.3.0]: https://github.com/Level/codec/compare/v4.2.0...v4.3.0 283 | 284 | [4.2.0]: https://github.com/Level/codec/compare/v4.1.0...v4.2.0 285 | 286 | [4.1.0]: https://github.com/Level/codec/compare/v4.0.1...v4.1.0 287 | 288 | [4.0.1]: https://github.com/Level/codec/compare/v4.0.0...v4.0.1 289 | 290 | [4.0.0]: https://github.com/Level/codec/compare/v3.1.0...v4.0.0 291 | 292 | [3.1.0]: https://github.com/Level/codec/compare/v3.0.0...v3.1.0 293 | 294 | [3.0.0]: https://github.com/Level/codec/compare/v2.0.1...v3.0.0 295 | 296 | [2.0.1]: https://github.com/Level/codec/compare/v2.0.0...v2.0.1 297 | 298 | [2.0.0]: https://github.com/Level/codec/compare/v1.2.1...v2.0.0 299 | 300 | [1.2.1]: https://github.com/Level/codec/compare/v1.2.0...v1.2.1 301 | 302 | [1.2.0]: https://github.com/Level/codec/compare/v1.1.0...v1.2.0 303 | 304 | [1.1.0]: https://github.com/Level/codec/compare/v1.0.1...v1.1.0 305 | -------------------------------------------------------------------------------- /CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | # Contributors 2 | 3 | | Name | GitHub | Social | 4 | | :------------------- | :----------------------------------------------------------- | :------------------------------------------------------------ | 5 | | **Julian Gruber** | [**@juliangruber**](https://github.com/juliangruber) | [**@juliangruber@twitter**](https://twitter.com/juliangruber) | 6 | | **Vincent Weevers** | [**@vweevers**](https://github.com/vweevers) | [**@vweevers@twitter**](https://twitter.com/vweevers) | 7 | | **Lars-Magnus Skog** | [**@ralphtheninja**](https://github.com/ralphtheninja) | [**@ralph@social.weho.st**](https://social.weho.st/@ralph) | 8 | | **Dominic Tarr** | [**@dominictarr**](https://github.com/dominictarr) | [**@dominictarr@twitter**](https://twitter.com/dominictarr) | 9 | | **Alex Potsides** | | | 10 | | **Daniel Cousens** | [**@dcousens**](https://github.com/dcousens) | | 11 | | **Hugo Dias** | | | 12 | | **Meirion Hughes** | [**@MeirionHughes**](https://github.com/MeirionHughes) | | 13 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | **Copyright © 2012-present [Contributors](CONTRIBUTORS.md).** 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # level-codec 2 | 3 | **Superseded by [`level-transcoder`](https://github.com/Level/transcoder). Please see [Frequently Asked Questions](https://github.com/Level/community#faq).** 4 | 5 | ## Usage 6 | 7 | **If you are upgrading:** please see [`UPGRADING.md`](UPGRADING.md). 8 | 9 | ```js 10 | const Codec = require('level-codec') 11 | const codec = Codec({ keyEncoding: 'json' }) 12 | const key = codec.encodeKey({ foo: 'bar' }) 13 | console.log(key) // -> '{"foo":"bar"}' 14 | console.log(codec.decodeKey(key)) // -> { foo: 'bar' } 15 | ``` 16 | 17 | ## API 18 | 19 | ### `codec = Codec([opts])` 20 | 21 | Create a new codec, with a global options object. 22 | 23 | ### `codec.encodeKey(key[, opts])` 24 | 25 | Encode `key` with given `opts`. 26 | 27 | ### `codec.encodeValue(value[, opts])` 28 | 29 | Encode `value` with given `opts`. 30 | 31 | ### `codec.encodeBatch(batch[, opts])` 32 | 33 | Encode `batch` ops with given `opts`. 34 | 35 | ### `codec.encodeLtgt(ltgt)` 36 | 37 | Encode the ltgt values of option object `ltgt`. 38 | 39 | ### `codec.decodeKey(key[, opts])` 40 | 41 | Decode `key` with given `opts`. 42 | 43 | ### `codec.decodeValue(value[, opts])` 44 | 45 | Decode `value` with given `opts`. 46 | 47 | ### `codec.createStreamDecoder([opts])` 48 | 49 | Create a function with signature `(key, value)`, that for each key-value pair returned from a levelup read stream returns the decoded value to be emitted. 50 | 51 | ### `codec.keyAsBuffer([opts])` 52 | 53 | Check whether `opts` and the global `opts` call for a binary key encoding. 54 | 55 | ### `codec.valueAsBuffer([opts])` 56 | 57 | Check whether `opts` and the global `opts` call for a binary value encoding. 58 | 59 | ### `codec.encodings` 60 | 61 | The builtin encodings as object of form 62 | 63 | ```js 64 | { 65 | [type]: encoding 66 | } 67 | ``` 68 | 69 | See below for a list and the format of `encoding`. 70 | 71 | ## Builtin Encodings 72 | 73 | | Type | Input | Stored as | Output | 74 | | :---------------------------------------------------------------- | :--------------------------- | :--------------- | :-------- | 75 | | `utf8` | String or Buffer | String or Buffer | String | 76 | | `json` | Any JSON type | JSON string | Input | 77 | | `binary` | Buffer, string or byte array | Buffer | As stored | 78 | | `hex`
`ascii`
`base64`
`ucs2`
`utf16le`
`utf-16le` | String or Buffer | Buffer | String | 79 | | `none` a.k.a. `id` | Any type (bypass encoding) | Input\* | As stored | 80 | 81 | \* Stores may have their own type coercion. Whether type information is preserved depends on the [`abstract-leveldown`] implementation as well as the underlying storage (`LevelDB`, `IndexedDB`, etc). 82 | 83 | ## Encoding Format 84 | 85 | An encoding is an object of the form: 86 | 87 | ```js 88 | { 89 | encode: function (data) { 90 | return data 91 | }, 92 | decode: function (data) { 93 | return data 94 | }, 95 | buffer: Boolean, 96 | type: 'example' 97 | } 98 | ``` 99 | 100 | All of these properties are required. 101 | 102 | The `buffer` boolean tells consumers whether to fetch data as a Buffer, before calling your `decode()` function on that data. If `buffer` is true, it is assumed that `decode()` takes a Buffer. If false, it is assumed that `decode` takes any other type (usually a string). 103 | 104 | To explain this in the grand scheme of things, consider a store like [`leveldown`] which has the ability to return either a Buffer or string, both sourced from the same byte array. Wrap this store with [`encoding-down`] and it'll select the most optimal data type based on the `buffer` property of the active encoding. If your `decode()` function needs a string (and the data can legitimately become a UTF8 string), you should set `buffer` to `false`. This avoids the cost of having to convert a Buffer to a string. 105 | 106 | The `type` string should be a unique name. 107 | 108 | ## Contributing 109 | 110 | [`Level/codec`](https://github.com/Level/codec) is an **OPEN Open Source Project**. This means that: 111 | 112 | > 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. 113 | 114 | See the [Contribution Guide](https://github.com/Level/community/blob/master/CONTRIBUTING.md) for more details. 115 | 116 | ## License 117 | 118 | [MIT](LICENSE.md) © 2012-present [Contributors](CONTRIBUTORS.md). 119 | 120 | [`encoding-down`]: https://github.com/Level/encoding-down 121 | 122 | [`abstract-leveldown`]: https://github.com/Level/abstract-leveldown 123 | 124 | [`leveldown`]: https://github.com/Level/leveldown 125 | -------------------------------------------------------------------------------- /UPGRADING.md: -------------------------------------------------------------------------------- 1 | # Upgrade Guide 2 | 3 | This document describes breaking changes and how to upgrade. For a complete list of changes including minor and patch releases, please refer to the [changelog](CHANGELOG.md). 4 | 5 | ## 10.0.0 6 | 7 | Legacy range options have been removed ([Level/community#86](https://github.com/Level/community/issues/86)). If you previously did: 8 | 9 | ```js 10 | codec.encodeLtgt({ start: 'a', end: 'z' }) 11 | ``` 12 | 13 | An error would now be thrown and you must instead do: 14 | 15 | ```js 16 | codec.encodeLtgt({ gte: 'a', lte: 'z' }) 17 | ``` 18 | 19 | This release also drops support of legacy runtime environments ([Level/community#98](https://github.com/Level/community/issues/98)): 20 | 21 | - Node.js 6 and 8 22 | - Internet Explorer 11 23 | - Safari 9-11 24 | - Stock Android browser (AOSP). 25 | 26 | ## 9.0.0 27 | 28 | Dropped node 0.12, 4, 5 and 7. 29 | 30 | ## 8.0.0 31 | 32 | Previously the "utf8" decoder always returned a string. This was a workaround for `encoding-down` that is no longer needed. The return type now depends on the `asBuffer` option, which is more optimal. 33 | 34 | ## 7.0.0 35 | 36 | Dropped node 0.10 and iojs. 37 | 38 | ## 6.0.0 39 | 40 | The `createDecodeStream()` method (introduced in the last 5.x version) has been replaced with `createStreamDecoder()`. 41 | 42 | ## 5.0.0 43 | 44 | This is a rewrite of both internals and the public API. Please see the README for details. 45 | 46 | ## 4.0.0 47 | 48 | Removed default encoding ("utf8"). If you relied on this behavior you must now define it yourself. 49 | 50 | ## 3.0.0 51 | 52 | Removed the `encoding` option in favor of `keyEncoding` and `valueEncoding`. Note: it was partially restored in v6.1.0. 53 | 54 | ## 2.0.0 55 | 56 | The function signature of `batch()` has changed from `batch(ops, batchOptions, dbOptions)` to `batch(ops, optionObjects)`. 57 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const encodings = require('./lib/encodings') 4 | const rangeOptions = new Set(['lt', 'gt', 'lte', 'gte']) 5 | 6 | module.exports = Codec 7 | 8 | function Codec (opts) { 9 | if (!(this instanceof Codec)) { 10 | return new Codec(opts) 11 | } 12 | this.opts = opts || {} 13 | this.encodings = encodings 14 | } 15 | 16 | Codec.prototype._encoding = function (encoding) { 17 | if (typeof encoding === 'string') encoding = encodings[encoding] 18 | if (!encoding) encoding = encodings.id 19 | return encoding 20 | } 21 | 22 | Codec.prototype._keyEncoding = function (opts, batchOpts) { 23 | return this._encoding((batchOpts && batchOpts.keyEncoding) || 24 | (opts && opts.keyEncoding) || 25 | this.opts.keyEncoding) 26 | } 27 | 28 | Codec.prototype._valueEncoding = function (opts, batchOpts) { 29 | return this._encoding((batchOpts && (batchOpts.valueEncoding || batchOpts.encoding)) || 30 | (opts && (opts.valueEncoding || opts.encoding)) || 31 | (this.opts.valueEncoding || this.opts.encoding)) 32 | } 33 | 34 | Codec.prototype.encodeKey = function (key, opts, batchOpts) { 35 | return this._keyEncoding(opts, batchOpts).encode(key) 36 | } 37 | 38 | Codec.prototype.encodeValue = function (value, opts, batchOpts) { 39 | return this._valueEncoding(opts, batchOpts).encode(value) 40 | } 41 | 42 | Codec.prototype.decodeKey = function (key, opts) { 43 | return this._keyEncoding(opts).decode(key) 44 | } 45 | 46 | Codec.prototype.decodeValue = function (value, opts) { 47 | return this._valueEncoding(opts).decode(value) 48 | } 49 | 50 | Codec.prototype.encodeBatch = function (ops, opts) { 51 | return ops.map((_op) => { 52 | const op = { 53 | type: _op.type, 54 | key: this.encodeKey(_op.key, opts, _op) 55 | } 56 | if (this.keyAsBuffer(opts, _op)) op.keyEncoding = 'binary' 57 | if (_op.prefix) op.prefix = _op.prefix 58 | if ('value' in _op) { 59 | op.value = this.encodeValue(_op.value, opts, _op) 60 | if (this.valueAsBuffer(opts, _op)) op.valueEncoding = 'binary' 61 | } 62 | return op 63 | }) 64 | } 65 | 66 | Codec.prototype.encodeLtgt = function (ltgt) { 67 | const ret = {} 68 | 69 | for (const key of Object.keys(ltgt)) { 70 | if (key === 'start' || key === 'end') { 71 | throw new Error('Legacy range options ("start" and "end") have been removed') 72 | } 73 | 74 | ret[key] = rangeOptions.has(key) 75 | ? this.encodeKey(ltgt[key], ltgt) 76 | : ltgt[key] 77 | } 78 | 79 | return ret 80 | } 81 | 82 | Codec.prototype.createStreamDecoder = function (opts) { 83 | if (opts.keys && opts.values) { 84 | return (key, value) => { 85 | return { 86 | key: this.decodeKey(key, opts), 87 | value: this.decodeValue(value, opts) 88 | } 89 | } 90 | } else if (opts.keys) { 91 | return (key) => { 92 | return this.decodeKey(key, opts) 93 | } 94 | } else if (opts.values) { 95 | return (_, value) => { 96 | return this.decodeValue(value, opts) 97 | } 98 | } else { 99 | return function () {} 100 | } 101 | } 102 | 103 | Codec.prototype.keyAsBuffer = function (opts) { 104 | return this._keyEncoding(opts).buffer 105 | } 106 | 107 | Codec.prototype.valueAsBuffer = function (opts) { 108 | return this._valueEncoding(opts).buffer 109 | } 110 | -------------------------------------------------------------------------------- /lib/encodings.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const { Buffer } = require('buffer') 4 | 5 | exports.utf8 = exports['utf-8'] = { 6 | encode: function (data) { 7 | return isBinary(data) ? data : String(data) 8 | }, 9 | decode: identity, 10 | buffer: false, 11 | type: 'utf8' 12 | } 13 | 14 | exports.json = { 15 | encode: JSON.stringify, 16 | decode: JSON.parse, 17 | buffer: false, 18 | type: 'json' 19 | } 20 | 21 | exports.binary = { 22 | encode: function (data) { 23 | return isBinary(data) ? data : Buffer.from(data) 24 | }, 25 | decode: identity, 26 | buffer: true, 27 | type: 'binary' 28 | } 29 | 30 | exports.none = { 31 | encode: identity, 32 | decode: identity, 33 | buffer: false, 34 | type: 'id' 35 | } 36 | 37 | exports.id = exports.none 38 | 39 | const bufferEncodings = [ 40 | 'hex', 41 | 'ascii', 42 | 'base64', 43 | 'ucs2', 44 | 'ucs-2', 45 | 'utf16le', 46 | 'utf-16le' 47 | ] 48 | 49 | for (const type of bufferEncodings) { 50 | exports[type] = { 51 | encode: function (data) { 52 | return isBinary(data) ? data : Buffer.from(data, type) 53 | }, 54 | decode: function (buffer) { 55 | return buffer.toString(type) 56 | }, 57 | buffer: true, 58 | type: type 59 | } 60 | } 61 | 62 | function identity (value) { 63 | return value 64 | } 65 | 66 | function isBinary (data) { 67 | return data === undefined || data === null || Buffer.isBuffer(data) 68 | } 69 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "level-codec", 3 | "version": "10.0.0", 4 | "description": "Encode keys, values and range options, with built-in or custom encodings", 5 | "license": "MIT", 6 | "main": "index.js", 7 | "scripts": { 8 | "test": "standard && hallmark && nyc tape test/*.js", 9 | "test-browsers-local": "airtap --coverage --verbose test/*.js", 10 | "coverage": "nyc report -r lcovonly", 11 | "hallmark": "hallmark --fix", 12 | "dependency-check": "dependency-check . test/*.js", 13 | "prepublishOnly": "npm run dependency-check" 14 | }, 15 | "files": [ 16 | "lib", 17 | "index.js", 18 | "CHANGELOG.md", 19 | "CONTRIBUTORS.md", 20 | "LICENSE.md", 21 | "UPGRADING.md" 22 | ], 23 | "dependencies": { 24 | "buffer": "^6.0.3" 25 | }, 26 | "devDependencies": { 27 | "airtap": "^4.0.3", 28 | "airtap-playwright": "^1.0.1", 29 | "dependency-check": "^3.3.0", 30 | "hallmark": "^3.1.0", 31 | "level-community": "^3.0.0", 32 | "nyc": "^15.1.0", 33 | "standard": "^17.0.0", 34 | "tape": "^5.0.1" 35 | }, 36 | "hallmark": { 37 | "community": "level-community" 38 | }, 39 | "repository": "Level/codec", 40 | "homepage": "https://github.com/Level/codec", 41 | "keywords": [ 42 | "level" 43 | ], 44 | "engines": { 45 | "node": ">=10" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /test/as-buffer.js: -------------------------------------------------------------------------------- 1 | const test = require('tape') 2 | const Codec = require('..') 3 | 4 | test('key as buffer', function (t) { 5 | const codec = new Codec({ keyEncoding: 'hex' }) 6 | t.ok(codec.keyAsBuffer({})) 7 | t.ok(codec.keyAsBuffer()) 8 | t.notOk(codec.keyAsBuffer({ keyEncoding: 'utf8' })) 9 | t.end() 10 | }) 11 | 12 | test('value as buffer', function (t) { 13 | const codec = new Codec({ valueEncoding: 'hex' }) 14 | t.ok(codec.valueAsBuffer({})) 15 | t.ok(codec.valueAsBuffer()) 16 | t.notOk(codec.valueAsBuffer({ valueEncoding: 'utf8' })) 17 | t.end() 18 | }) 19 | -------------------------------------------------------------------------------- /test/batch.js: -------------------------------------------------------------------------------- 1 | const test = require('tape') 2 | const Codec = require('..') 3 | 4 | test('batch', function (t) { 5 | const codec = new Codec({}) 6 | const ops = [ 7 | { type: 'put', key: 'string', value: 'string', valueEncoding: 'utf8' }, 8 | { type: 'put', key: 'json', value: {} } 9 | ] 10 | const opsSerialized = JSON.stringify(ops) 11 | 12 | let encoded = codec.encodeBatch(ops, { valueEncoding: 'json' }) 13 | 14 | t.equal(opsSerialized, JSON.stringify(ops), 'ops not changed') 15 | 16 | t.deepEqual(encoded, [ 17 | { type: 'put', key: 'string', value: 'string' }, 18 | { type: 'put', key: 'json', value: '{}' } 19 | ]) 20 | 21 | encoded = codec.encodeBatch(ops) 22 | t.deepEqual(encoded, [ 23 | { type: 'put', key: 'string', value: 'string' }, 24 | { type: 'put', key: 'json', value: {} } 25 | ]) 26 | 27 | t.end() 28 | }) 29 | 30 | test('batch - legacy', function (t) { 31 | const codec = new Codec({}) 32 | const ops = [ 33 | { type: 'put', key: 'string', value: 'string', encoding: 'utf8' }, 34 | { type: 'put', key: 'json', value: {} } 35 | ] 36 | const opsSerialized = JSON.stringify(ops) 37 | 38 | let encoded = codec.encodeBatch(ops, { encoding: 'json' }) 39 | 40 | t.equal(opsSerialized, JSON.stringify(ops), 'ops not changed') 41 | 42 | t.deepEqual(encoded, [ 43 | { type: 'put', key: 'string', value: 'string' }, 44 | { type: 'put', key: 'json', value: '{}' } 45 | ]) 46 | 47 | encoded = codec.encodeBatch(ops) 48 | t.deepEqual(encoded, [ 49 | { type: 'put', key: 'string', value: 'string' }, 50 | { type: 'put', key: 'json', value: {} } 51 | ]) 52 | 53 | t.end() 54 | }) 55 | -------------------------------------------------------------------------------- /test/codec.js: -------------------------------------------------------------------------------- 1 | const test = require('tape') 2 | const Codec = require('..') 3 | 4 | test('codec', function (t) { 5 | let codec = new Codec({ keyEncoding: 'hex' }) 6 | t.ok(codec.keyAsBuffer()) 7 | codec = new Codec() 8 | t.notOk(codec.keyAsBuffer()) 9 | t.end() 10 | }) 11 | 12 | test('codec, new not needed', function (t) { 13 | let codec = Codec({ keyEncoding: 'hex' }) 14 | t.ok(codec.keyAsBuffer()) 15 | codec = Codec() 16 | t.notOk(codec.keyAsBuffer()) 17 | t.end() 18 | }) 19 | -------------------------------------------------------------------------------- /test/decoder.js: -------------------------------------------------------------------------------- 1 | const test = require('tape') 2 | const Codec = require('..') 3 | 4 | test('createStreamDecoder', function (t) { 5 | const codec = new Codec({ keyEncoding: 'hex' }) 6 | 7 | t.plan(3) 8 | 9 | t.test('keys and values', function (t) { 10 | const decoder = codec.createStreamDecoder({ 11 | valueEncoding: 'json', 12 | keys: true, 13 | values: true 14 | }) 15 | t.deepEqual(decoder(Buffer.from('hey'), '"you"'), { 16 | key: '686579', 17 | value: 'you' 18 | }) 19 | t.end() 20 | }) 21 | 22 | t.test('keys', function (t) { 23 | const decoder = codec.createStreamDecoder({ 24 | keys: true 25 | }) 26 | t.equal(decoder(Buffer.from('hey')), '686579') 27 | t.end() 28 | }) 29 | 30 | t.test('values', function (t) { 31 | const decoder = codec.createStreamDecoder({ 32 | valueEncoding: 'hex', 33 | values: true 34 | }) 35 | t.equal(decoder(null, Buffer.from('hey')), '686579') 36 | t.end() 37 | }) 38 | }) 39 | 40 | test('createStreamDecoder - legacy', function (t) { 41 | const codec = new Codec({ keyEncoding: 'hex' }) 42 | 43 | t.plan(3) 44 | 45 | t.test('keys and values', function (t) { 46 | const decoder = codec.createStreamDecoder({ 47 | encoding: 'json', 48 | keys: true, 49 | values: true 50 | }) 51 | t.deepEqual(decoder(Buffer.from('hey'), '"you"'), { 52 | key: '686579', 53 | value: 'you' 54 | }) 55 | t.end() 56 | }) 57 | 58 | t.test('keys', function (t) { 59 | const decoder = codec.createStreamDecoder({ 60 | keys: true 61 | }) 62 | t.equal(decoder(Buffer.from('hey')), '686579') 63 | t.end() 64 | }) 65 | 66 | t.test('values', function (t) { 67 | const decoder = codec.createStreamDecoder({ 68 | encoding: 'hex', 69 | values: true 70 | }) 71 | t.equal(decoder(null, Buffer.from('hey')), '686579') 72 | t.end() 73 | }) 74 | }) 75 | -------------------------------------------------------------------------------- /test/kv.js: -------------------------------------------------------------------------------- 1 | const test = require('tape') 2 | const Codec = require('..') 3 | 4 | test('encode key', function (t) { 5 | const codec = new Codec({ keyEncoding: 'hex' }) 6 | 7 | let buf = codec.encodeKey('686579', {}) 8 | t.equal(buf.toString(), 'hey') 9 | 10 | buf = codec.encodeKey('686579') 11 | t.equal(buf.toString(), 'hey') 12 | 13 | buf = codec.encodeKey('686579', { 14 | keyEncoding: 'binary' 15 | }) 16 | t.equal(buf.toString(), '686579') 17 | 18 | buf = codec.encodeKey({ foo: 'bar' }, { 19 | keyEncoding: 'none' 20 | }) 21 | t.deepEqual(buf, { foo: 'bar' }) 22 | 23 | t.end() 24 | }) 25 | 26 | test('encode value', function (t) { 27 | const codec = new Codec({ valueEncoding: 'hex' }) 28 | 29 | let buf = codec.encodeValue('686579', {}) 30 | t.equal(buf.toString(), 'hey') 31 | 32 | buf = codec.encodeValue('686579') 33 | t.equal(buf.toString(), 'hey') 34 | 35 | buf = codec.encodeValue('686579', { 36 | valueEncoding: 'binary' 37 | }) 38 | t.equal(buf.toString(), '686579') 39 | 40 | t.end() 41 | }) 42 | 43 | test('decode key', function (t) { 44 | const codec = new Codec({ keyEncoding: 'hex' }) 45 | 46 | let buf = codec.decodeKey(Buffer.from('hey'), {}) 47 | t.equal(buf, '686579') 48 | 49 | buf = codec.decodeKey(Buffer.from('hey')) 50 | t.equal(buf, '686579') 51 | 52 | buf = codec.decodeKey(Buffer.from('hey'), { 53 | keyEncoding: 'binary' 54 | }) 55 | t.equal(buf.toString(), 'hey') 56 | 57 | t.end() 58 | }) 59 | 60 | test('decode value', function (t) { 61 | const codec = new Codec({ valueEncoding: 'hex' }) 62 | 63 | let buf = codec.decodeValue(Buffer.from('hey'), {}) 64 | t.equal(buf, '686579') 65 | 66 | buf = codec.decodeValue(Buffer.from('hey')) 67 | t.equal(buf, '686579') 68 | 69 | buf = codec.decodeValue(Buffer.from('hey'), { 70 | valueEncoding: 'binary' 71 | }) 72 | t.equal(buf.toString(), 'hey') 73 | 74 | t.end() 75 | }) 76 | 77 | test('encode value - legacy', function (t) { 78 | const codec = new Codec({ encoding: 'hex' }) 79 | 80 | let buf = codec.encodeValue('686579', {}) 81 | t.equal(buf.toString(), 'hey') 82 | 83 | buf = codec.encodeValue('686579') 84 | t.equal(buf.toString(), 'hey') 85 | 86 | buf = codec.encodeValue('686579', { 87 | encoding: 'binary' 88 | }) 89 | t.equal(buf.toString(), '686579') 90 | 91 | t.end() 92 | }) 93 | 94 | test('decode value - legacy', function (t) { 95 | const codec = new Codec({ encoding: 'hex' }) 96 | 97 | let buf = codec.decodeValue(Buffer.from('hey'), {}) 98 | t.equal(buf, '686579') 99 | 100 | buf = codec.decodeValue(Buffer.from('hey')) 101 | t.equal(buf, '686579') 102 | 103 | buf = codec.decodeValue(Buffer.from('hey'), { 104 | encoding: 'binary' 105 | }) 106 | t.equal(buf.toString(), 'hey') 107 | 108 | t.end() 109 | }) 110 | -------------------------------------------------------------------------------- /test/ltgt.js: -------------------------------------------------------------------------------- 1 | const test = require('tape') 2 | const Codec = require('..') 3 | 4 | test('encode ltgt', function (t) { 5 | const codec = new Codec({ keyEncoding: 'hex' }) 6 | 7 | let ltgt = { 8 | gte: '686579', 9 | lte: '686579' 10 | } 11 | let encoded = codec.encodeLtgt(ltgt) 12 | t.equal(encoded.gte.toString(), 'hey') 13 | t.equal(encoded.lte.toString(), 'hey') 14 | 15 | ltgt = { 16 | gte: '686579', 17 | lte: '686579', 18 | keyEncoding: 'json' 19 | } 20 | encoded = codec.encodeLtgt(ltgt) 21 | t.equal(encoded.gte, '"686579"') 22 | t.equal(encoded.lte, '"686579"') 23 | 24 | t.end() 25 | }) 26 | 27 | test('rejects legacy range options', function (t) { 28 | t.plan(2) 29 | 30 | const codec = new Codec() 31 | 32 | for (const k of ['start', 'end']) { 33 | try { 34 | codec.encodeLtgt({ [k]: 123 }) 35 | } catch (err) { 36 | t.is(err.message, 'Legacy range options ("start" and "end") have been removed') 37 | } 38 | } 39 | }) 40 | --------------------------------------------------------------------------------