cbor-x 0.8.2 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,10 +1,12 @@
1
1
  {
2
2
  "name": "cbor-x",
3
3
  "author": "Kris Zyp",
4
- "version": "0.8.2",
4
+ "version": "0.9.2",
5
5
  "description": "Ultra-fast CBOR implementation with tag extensions for records and structured cloning",
6
6
  "license": "MIT",
7
7
  "types": "./index.d.ts",
8
+ "main": "./dist/node.cjs",
9
+ "module": "./index.js",
8
10
  "keywords": [
9
11
  "CBOR",
10
12
  "performance",
@@ -16,55 +18,53 @@
16
18
  "url": "http://github.com/kriszyp/cbor-x"
17
19
  },
18
20
  "scripts": {
19
- "benchmark": "node ./tests/benchmark.js",
21
+ "benchmark": "node ./tests/benchmark.cjs",
20
22
  "build": "rollup -c",
23
+ "dry-run": "npm publish --dry-run",
21
24
  "prepare": "npm run build",
22
- "test": "./node_modules/.bin/mocha --experimental-json-modules tests/test**.*js -u tdd"
25
+ "test": "mocha tests/test**.*js -u tdd --experimental-json-modules"
23
26
  },
24
27
  "type": "module",
25
- "main": "./dist/node.cjs",
26
28
  "exports": {
27
29
  ".": {
28
30
  "node": {
29
31
  "require": "./dist/node.cjs",
30
- "import": "./node.js"
32
+ "import": "./node-index.js"
31
33
  },
32
- "default": {
33
- "import": "./index.js"
34
- }
34
+ "default": "./index.js"
35
35
  },
36
- "./pack": {
36
+ "./encode": {
37
37
  "node": {
38
38
  "import": "./index.js",
39
39
  "require": "./dist/node.cjs"
40
40
  },
41
41
  "default": {
42
- "import": "./pack.js"
42
+ "import": "./encode.js"
43
43
  }
44
44
  },
45
- "./unpack": {
45
+ "./decode": {
46
46
  "node": {
47
47
  "import": "./index.js",
48
48
  "require": "./dist/node.cjs"
49
49
  },
50
50
  "default": {
51
- "import": "./unpack.js"
51
+ "import": "./decode.js"
52
52
  }
53
53
  }
54
54
  },
55
55
  "optionalDependencies": {
56
- "cbor-extract": "^0.3.0"
56
+ "cbor-extract": "^0.3.2"
57
57
  },
58
58
  "devDependencies": {
59
+ "@types/node": "latest",
59
60
  "async": "^3",
60
61
  "cbor": "^5",
61
62
  "cbor-sync": "^1.0.4",
62
- "@types/node": "latest",
63
- "chai": "^4",
63
+ "chai": "^4.3.4",
64
64
  "esm": "^3.2.25",
65
65
  "mocha": "^8.1.3",
66
66
  "rollup": "^1.20.3",
67
- "rollup-plugin-babel-minify": "^9.0.0",
68
- "@rollup/plugin-json": "^4.1.0"
67
+ "@rollup/plugin-json": "^4.1.0",
68
+ "rollup-plugin-babel-minify": "^9.0.0"
69
69
  }
70
70
  }
package/rollup.config.js CHANGED
@@ -3,7 +3,7 @@ import json from "@rollup/plugin-json";
3
3
 
4
4
  export default [
5
5
  {
6
- input: "node.js",
6
+ input: "node-index.js",
7
7
  output: [
8
8
  {
9
9
  file: "dist/node.cjs",
@@ -42,4 +42,4 @@ export default [
42
42
  },
43
43
  }
44
44
  }
45
- ];
45
+ ];
package/stream.js CHANGED
@@ -1,24 +1,20 @@
1
1
  import { Transform } from 'stream'
2
2
  import { Encoder } from './encode.js'
3
- import { read, getPosition, Decoder, clearSource } from './decode.js'
3
+ import { checkedRead, getPosition, Decoder, clearSource } from './decode.js'
4
4
  var DEFAULT_OPTIONS = {objectMode: true}
5
5
 
6
6
  export class EncoderStream extends Transform {
7
7
  constructor(options) {
8
8
  if (!options)
9
9
  options = {}
10
+ options.writableObjectMode = true
10
11
  super(options)
11
12
  options.sequential = true
12
- this.encoder = new Encoder(options)
13
+ this.encoder = options.encoder || new Encoder(options)
13
14
  }
14
- write(value) {
15
+ _transform(value, encoding, callback) {
15
16
  this.push(this.encoder.encode(value))
16
- }
17
-
18
- end(value) {
19
- if (value != null)
20
- this.push(this.encoder.encode(value))
21
- this.push(null)
17
+ callback()
22
18
  }
23
19
  }
24
20
 
@@ -29,31 +25,33 @@ export class DecoderStream extends Transform {
29
25
  options.objectMode = true
30
26
  super(options)
31
27
  options.structures = []
32
- this.decoder = new Decoder(options)
28
+ this.decoder = options.decoder || new Decoder(options)
33
29
  }
34
30
  _transform(chunk, encoding, callback) {
35
31
  if (this.incompleteBuffer) {
36
32
  chunk = Buffer.concat([this.incompleteBuffer, chunk])
37
33
  this.incompleteBuffer = null
38
34
  }
39
- let position = 0
40
- let size = chunk.length
35
+ let values
41
36
  try {
42
- this.push(this.decoder.decode(chunk, size, true))
43
- position = getPosition()
44
- while (position < size) {
45
- let value = read()
46
- this.push(value)
47
- position = getPosition()
48
- }
37
+ values = this.decoder.decodeMultiple(chunk)
49
38
  } catch(error) {
50
- if (error.incomplete)
51
- this.incompleteBuffer = chunk.slice(position)
39
+ if (error.incomplete) {
40
+ this.incompleteBuffer = chunk.slice(error.lastPosition)
41
+ values = error.values
42
+ }
52
43
  else
53
44
  throw error
54
45
  } finally {
55
- clearSource()
46
+ for (let value of values || []) {
47
+ if (value === null)
48
+ value = this.getNullValue()
49
+ this.push(value)
50
+ }
56
51
  }
57
52
  if (callback) callback()
58
53
  }
54
+ getNullValue() {
55
+ return Symbol.for(null)
56
+ }
59
57
  }
@@ -1,4 +1,4 @@
1
- var cborX = tryRequire("..");
1
+ var cborX = tryRequire("../dist/node.cjs");
2
2
  var msgpack_node = tryRequire("msgpack");
3
3
  var msgpack_msgpack = tryRequire("@msgpack/msgpack");
4
4
  var msgpack_lite = tryRequire("msgpack-lite");
@@ -12,6 +12,12 @@ var what_the_pack = tryRequire("what-the-pack");
12
12
  var avro = tryRequire('avsc')
13
13
  var cbor = tryRequire('cbor')
14
14
  var cborSync = tryRequire('cbor-sync')
15
+ var zlib = require('zlib')
16
+ var deflateSync = zlib.deflateSync
17
+ var inflateSync = zlib.inflateSync
18
+ //var deflateSync = zlib.brotliCompressSync
19
+ //var inflateSync = zlib.brotliDecompressSync
20
+ var constants = zlib.constants
15
21
 
16
22
  msgpack5 = msgpack5 && msgpack5();
17
23
  msgpack_codec = msgpack_codec && msgpack_codec.msgpack;
@@ -43,25 +49,59 @@ console.log(rpad("", COL1, "-"), "|", lpad(":", COL2, "-"), "|", lpad(":", COL3,
43
49
 
44
50
  var buf, obj;
45
51
 
46
- if (JSON) {
47
- buf = bench('buf = Buffer(JSON.stringify(obj));', JSON_stringify, data);
48
- obj = bench('obj = JSON.parse(buf);', JSON.parse, buf);
52
+ if (cborX) {
53
+ let encoder = new cborX.Encoder({ useRecords: false, pack: true })
54
+ buf = bench('cbor-x packed and compress: encoder.encode(obj);', (data) => deflateSync(encoder.encode(data), { level: constants.Z_BEST_SPEED}), data);
55
+ console.log('size', buf.length)
56
+
57
+ buf = bench('cbor-x packed: encoder.encode(obj);', encoder.encode.bind(encoder), data);
58
+
59
+ obj = bench('cbor-x packed: encoder.decode(buf);', encoder.decode.bind(encoder), buf);
49
60
  test(obj);
50
- }
61
+ console.log('size', buf.length)
51
62
 
52
- if (cborX) {
53
- // let packr = new msgpackr.Packr({ objectsAsMaps: true })
63
+
64
+ encoder = new cborX.Encoder({ useRecords: true, pack: true })
65
+ buf = bench('cbor-x packed and useRecords and compress: encoder.encode(obj);', (data) => deflateSync(encoder.encode(data), { level: constants.Z_BEST_SPEED}), data);
66
+ console.log('size', buf.length)
67
+
68
+ buf = bench('cbor-x packed and useRecords: encoder.encode(obj);', encoder.encode.bind(encoder), data);
69
+
70
+ obj = bench('cbor-x packed and useRecords: encoder.decode(buf);', encoder.decode.bind(encoder), buf);
71
+ test(obj);
72
+ console.log('size', buf.length)
73
+
74
+ buf = bench('require("cbor-x").encode(obj) and compress;', (data) => deflateSync(cborX.encode(data)), data);
75
+ console.log('size', buf.length)
54
76
  buf = bench('require("cbor-x").encode(obj);', cborX.encode, data);
55
77
  // buf = bench('require("msgpack").serialize(obj);', data => {let result = packr.serialize(data); packr.resetMemory(); return result;}, data);
56
78
 
57
79
  obj = bench('require("cbor-x").decode(buf);', cborX.decode, buf);
58
80
  test(obj);
81
+ console.log('size', buf.length)
82
+
59
83
 
60
- encoder = new cborX.Encoder({ structures: [] })
84
+ encoder = new cborX.Encoder({ })
85
+ buf = bench('cbor-x w/ shared structures: encoder.encode(obj);', (data) => deflateSync(encoder.encode(data), { level: constants.Z_BEST_SPEED}), data);
86
+ console.log('size', buf.length)
87
+
61
88
  buf = bench('cbor-x w/ shared structures: encoder.encode(obj);', encoder.encode.bind(encoder), data);
62
89
 
63
90
  obj = bench('cbor-x w/ shared structures: encoder.decode(buf);', encoder.decode.bind(encoder), buf);
64
91
  test(obj);
92
+ console.log('size', buf.length)
93
+ }
94
+ if (JSON) {
95
+ buf = bench('buf = Buffer(JSON.stringify(obj));', JSON_stringify, data);
96
+ obj = bench('obj = JSON.parse(buf);', JSON.parse, buf);
97
+ test(obj);
98
+ }
99
+
100
+
101
+ if (JSON) {
102
+ buf = bench('buf = Buffer(JSON.stringify(obj));', JSON_stringify, data);
103
+ obj = bench('obj = JSON.parse(buf);', JSON.parse, buf);
104
+ test(obj);
65
105
  }
66
106
 
67
107
  if (msgpack_lite) {
@@ -6,6 +6,7 @@ function tryRequire(module) {
6
6
  try {
7
7
  return require(module)
8
8
  } catch(error) {
9
+ console.log(error)
9
10
  }
10
11
  }
11
12
  //if (typeof chai === 'undefined') { chai = require('chai') }
@@ -0,0 +1,41 @@
1
+ import { encode } from '../index.js'
2
+ import { assert } from 'chai'
3
+ import { Encoder } from '../encode.js'
4
+
5
+ const tests = {
6
+ string: 'interesting string',
7
+ number: 12345,
8
+ buffer: Buffer.from('hello world'),
9
+ bigint: 12345678910n,
10
+ array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
11
+ 'many-strings': [],
12
+ set: new Set('abcdefghijklmnopqrstuvwxyz'.split('')),
13
+ object: { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6 }
14
+ }
15
+ for (let i = 0; i < 100; i++) {
16
+ tests['many-strings'].push('test-data-' + i)
17
+ }
18
+
19
+ suite('encode and decode tests with partial values', function () {
20
+ const encoder = new Encoder({ objectMode: true, structures: [] })
21
+
22
+ for (const [label, testData] of Object.entries(tests)) {
23
+ test(label, () => {
24
+ const encoded = encoder.encode(testData)
25
+ assert.isTrue(Buffer.isBuffer(encoded), 'encode returns a Buffer')
26
+ assert.deepStrictEqual(encoder.decode(encoded, encoded.length, true), testData, 'full buffer decodes well')
27
+ const firstHalf = encoded.slice(0, Math.floor(encoded.length / 2))
28
+ let value
29
+ try {
30
+ value = encoder.decode(firstHalf, firstHalf.length, true)
31
+ } catch (err) {
32
+ if (err.incomplete !== true) {
33
+ assert.fail(`Should throw an error with .incomplete set to true, instead threw error <${err}>`)
34
+ } else {
35
+ return; // victory! correct outcome!
36
+ }
37
+ }
38
+ assert.fail(`Should throw an error with .incomplete set to true, instead returned value ${JSON.stringify(value)}`)
39
+ })
40
+ }
41
+ })
@@ -0,0 +1,72 @@
1
+ import { encodeIter, decodeIter } from '../index.js'
2
+ import { decode } from '../index.js'
3
+ import { assert } from 'chai'
4
+
5
+ const tests = [
6
+ null,
7
+ false,
8
+ true,
9
+ 'interesting string',
10
+ 12345,
11
+ 123456789n,
12
+ 123.456,
13
+ Buffer.from('Hello World'),
14
+ new Set('abcdefghijklmnopqrstuvwxyz'.split(''))
15
+ ]
16
+
17
+ suite('cbor-x iterators interface tests', function () {
18
+ test('sync encode iterator', () => {
19
+ const encodings = [...encodeIter(tests)]
20
+ const decodings = encodings.map(x => decode(x))
21
+ assert.deepStrictEqual(decodings, tests)
22
+ })
23
+
24
+ test('async encode iterator', async () => {
25
+ async function * generate () {
26
+ for (const test of tests) {
27
+ await new Promise((resolve, reject) => setImmediate(resolve))
28
+ yield test
29
+ }
30
+ }
31
+
32
+ const chunks = []
33
+ for await (const chunk of encodeIter(generate())) {
34
+ chunks.push(chunk)
35
+ }
36
+
37
+ const decodings = chunks.map(x => decode(x))
38
+ assert.deepStrictEqual(decodings, tests)
39
+ })
40
+
41
+ test('sync encode and decode iterator', () => {
42
+ const encodings = [...encodeIter(tests)]
43
+ assert.isTrue(encodings.every(v => Buffer.isBuffer(v)))
44
+ const decodings = [...decodeIter(encodings)]
45
+ assert.deepStrictEqual(decodings, tests)
46
+
47
+ // also test decodings work with buffers multiple values in a buffer
48
+ const concatEncoding = Buffer.concat([...encodings])
49
+ const decodings2 = [...decodeIter([concatEncoding])]
50
+ assert.deepStrictEqual(decodings2, tests)
51
+
52
+ // also test decodings work with partial buffers that don't align to values perfectly
53
+ const half1 = concatEncoding.slice(0, Math.floor(concatEncoding.length / 2))
54
+ const half2 = concatEncoding.slice(Math.floor(concatEncoding.length / 2))
55
+ const decodings3 = [...decodeIter([half1, half2])]
56
+ assert.deepStrictEqual(decodings3, tests)
57
+ })
58
+
59
+ test('async encode and decode iterator', async () => {
60
+ async function * generator () {
61
+ for (const obj of tests) {
62
+ await new Promise((resolve, reject) => setImmediate(resolve))
63
+ yield obj
64
+ }
65
+ }
66
+ const yields = []
67
+ for await (const value of decodeIter(encodeIter(generator()))) {
68
+ yields.push(value)
69
+ }
70
+ assert.deepStrictEqual(yields, tests)
71
+ })
72
+ })
@@ -1,6 +1,9 @@
1
- import { EncoderStream, DecoderStream } from '../node.js'
1
+ import { EncoderStream, DecoderStream } from '../node-index.js'
2
2
  import stream from 'stream'
3
3
  import chai from 'chai'
4
+ import util from 'util'
5
+ import fs from 'fs'
6
+ const finished = util.promisify(stream.finished)
4
7
  var assert = chai.assert
5
8
 
6
9
  suite('cbor-x node stream tests', function(){
@@ -47,4 +50,11 @@ suite('cbor-x node stream tests', function(){
47
50
  bufferStream.push(new Uint8Array([1, 2]))
48
51
  bufferStream.push(null)
49
52
  }))
53
+
54
+ teardown(function() {
55
+ try {
56
+ fs.unlinkSync('test-output.msgpack')
57
+ }catch(error){}
58
+ })
50
59
  })
60
+
package/tests/test.js CHANGED
@@ -1,8 +1,7 @@
1
1
  import * as CBOR from '../index.js'
2
2
  import chai from 'chai'
3
- //import('./test.mjs')
4
3
  import sampleData from './example4.json'
5
- //import inspector from 'inspector'; inspector.open(9330, null, true); debugger
4
+ //import inspector from 'inspector'; inspector.open(9229, null, true); debugger
6
5
  function tryRequire(module) {
7
6
  try {
8
7
  return require(module)
@@ -85,6 +84,13 @@ suite('CBOR basic tests', function(){
85
84
  assert.deepEqual(deserialized, data)
86
85
  })
87
86
 
87
+ test('255 chars', function() {
88
+ const data = 'RRZG9A6I7xupPeOZhxcOcioFsuhszGOdyDUcbRf4Zef2kdPIfC9RaLO4jTM5JhuZvTsF09fbRHMGtqk7YAgu3vespeTe9l61ziZ6VrMnYu2CamK96wCkmz0VUXyqaiUoTPgzk414LS9yYrd5uh7w18ksJF5SlC2e91rukWvNqAZJjYN3jpkqHNOFchCwFrhbxq2Lrv1kSJPYCx9blRg2hGmYqTbElLTZHv20iNqwZeQbRMgSBPT6vnbCBPnOh1W'
89
+ var serialized = CBOR.encode(data)
90
+ var deserialized = CBOR.decode(serialized)
91
+ assert.equal(deserialized, data)
92
+ })
93
+
88
94
  test('encode/decode sample data', function(){
89
95
  var data = sampleData
90
96
  var serialized = CBOR.encode(data)
@@ -102,6 +108,55 @@ suite('CBOR basic tests', function(){
102
108
  var deserialized = encoder.decode(serialized)
103
109
  assert.deepEqual(deserialized, data)
104
110
  })
111
+ test('encode/decode sample data with packing', function(){
112
+ var data = sampleData
113
+ let encoder = new Encoder({ pack: true, useRecords: false })
114
+ var serialized = encoder.encode(data)
115
+ var deserialized = encoder.decode(serialized)
116
+ assert.deepEqual(deserialized, data)
117
+ })
118
+ test('encode/decode sample data with packing and records', function(){
119
+ var data = sampleData
120
+ let structures = []
121
+ let encoder = new Encoder({ structures, pack: true, useRecords: true })
122
+ var serialized = encoder.encode(data)
123
+ var deserialized = encoder.decode(serialized)
124
+ assert.deepEqual(deserialized, data)
125
+ })
126
+ test('encode/decode sample data with shared packing and records', function(){
127
+ let encoder = new Encoder({ useRecords: true })
128
+ let finishPack = encoder.findCommonStringsToPack()
129
+ for (let i = 0; i < 20; i++) {
130
+ let data = {
131
+ shouldShare: 'same each time',
132
+ shouldShare2: 'same each time 2',
133
+ shouldntShare: 'different each time ' + i
134
+ }
135
+ if (i == 10)
136
+ finishPack({})
137
+ var serialized = encoder.encode(data)
138
+ var deserialized = encoder.decode(serialized)
139
+ assert.deepEqual(deserialized, data)
140
+ }
141
+ })
142
+ test('encode/decode sample data with individual packing, shared packing and records', function(){
143
+ let encoder = new Encoder({ pack: true, useRecords: true })
144
+ let finishPack = encoder.findCommonStringsToPack()
145
+ for (let i = 0; i < 20; i++) {
146
+ let data = {
147
+ shouldShare: 'same each time',
148
+ shouldShare2: 'same each time',
149
+ shouldntShare: 'different each time ' + i,
150
+ shouldntShare2: 'different each time ' + i,
151
+ noPack: 'no packing ' + i,
152
+ }
153
+ if (i == 10)
154
+ finishPack({ threshold: 5 })
155
+ var serialized = encoder.encode(data)
156
+ var deserialized = encoder.decode(serialized)
157
+ assert.deepEqual(deserialized, data)
158
+ }
159
+ })
105
160
  if (typeof Buffer != 'undefined')
106
161
  test('replace data', function(){
107
162
  var data1 = {
@@ -215,10 +270,13 @@ suite('CBOR basic tests', function(){
215
270
  let fa = new Float32Array(b.buffer, 8, 2)
216
271
  fa[0] = 2.25
217
272
  fa[1] = 6
273
+ let map = new Map()
274
+ map.set('key', 'value')
218
275
  let object = {
219
276
  error: new Error('test'),
220
277
  set: new Set(['a', 'b']),
221
278
  regexp: /test/gi,
279
+ map,
222
280
  float32Array: fa,
223
281
  uint16Array: new Uint16Array([3,4])
224
282
  }
@@ -228,6 +286,7 @@ suite('CBOR basic tests', function(){
228
286
  var serialized = encoder.encode(object)
229
287
  var deserialized = encoder.decode(serialized)
230
288
  assert.deepEqual(Array.from(deserialized.set), Array.from(object.set))
289
+ assert.equal(deserialized.map.get('key'), 'value')
231
290
  assert.equal(deserialized.error.message, object.error.message)
232
291
  assert.equal(deserialized.regexp.test('TEST'), true)
233
292
  assert.equal(deserialized.float32Array.constructor.name, 'Float32Array')
@@ -238,6 +297,19 @@ suite('CBOR basic tests', function(){
238
297
  assert.equal(deserialized.uint16Array[1], 4)
239
298
  })
240
299
 
300
+ test('explicit maps and sets', function () {
301
+ let map = new Map()
302
+ map.set('key', { inside: 'value'})
303
+ let object = {
304
+ set: new Set(['a', 'b']),
305
+ map,
306
+ }
307
+ var serialized = encode(object) // default encoder
308
+ var deserialized = decode(serialized)
309
+ assert.deepEqual(Array.from(deserialized.set), Array.from(object.set))
310
+ assert.equal(deserialized.map.get('key').inside, 'value')
311
+ })
312
+
241
313
  test('object without prototype', function(){
242
314
  var data = Object.create(null)
243
315
  data.test = 3
@@ -253,6 +325,13 @@ suite('CBOR basic tests', function(){
253
325
  var decoded = decode(encoded)
254
326
  assert.equal(decoded.length, size)
255
327
  })
328
+ test('little buffer', function() {
329
+ var data = typeof Buffer == 'undefined' ? new Uint8Array(0) : Buffer.alloc(0)
330
+ var encoded = encode(data)
331
+ assert.equal(encoded.length, 1) // make sure to use canonical form
332
+ var decoded = decode(encoded)
333
+ assert.equal(decoded.length, 0)
334
+ })
256
335
 
257
336
  test('random strings', function(){
258
337
  var data = []
@@ -300,6 +379,7 @@ suite('CBOR basic tests', function(){
300
379
  let encoder = new Encoder({
301
380
  mapsAsObjects: true,
302
381
  useTimestamp32: true,
382
+ useTag259ForMaps: false,
303
383
  })
304
384
  var serialized = encoder.encode(data)
305
385
  var deserialized = encoder.decode(serialized)
package/pack.d.ts DELETED
@@ -1,9 +0,0 @@
1
- import { Unpackr } from './unpack'
2
- export { addExtension, FLOAT32_OPTIONS } from './unpack'
3
- export class Packr extends Unpackr {
4
- pack(value: any): Buffer
5
- encode(value: any): Buffer
6
- }
7
- export class Encoder extends Packr {}
8
- export function pack(value: any): Buffer
9
- export function encode(value: any): Buffer