cbor-x 0.8.0 → 0.9.0

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/encode.js CHANGED
@@ -43,11 +43,8 @@ export class Encoder extends Decoder {
43
43
  let recordIdsToRemove = []
44
44
  let transitionsCount = 0
45
45
  let serializationsSinceTransitionRebuild = 0
46
- if (this.structures && this.structures.length > maxSharedStructures) {
47
- throw new Error('Too many shared structures')
48
- }
49
46
 
50
- this.encode = function(value) {
47
+ this.encode = function(value, encodeOptions) {
51
48
  if (!target) {
52
49
  target = new ByteArrayAllocate(8192)
53
50
  targetView = new DataView(target.buffer, 0, 8192)
@@ -60,7 +57,8 @@ export class Encoder extends Decoder {
60
57
  targetView = new DataView(target.buffer, 0, target.length)
61
58
  safeEnd = target.length - 10
62
59
  position = 0
63
- }
60
+ } else if (encodeOptions === REUSE_BUFFER_MODE)
61
+ position = (position + 7) & 0x7ffffff8 // Word align to make any future copying of this buffer faster
64
62
  start = position
65
63
  referenceMap = encoder.structuredClone ? new Map() : null
66
64
  sharedStructures = encoder.structures
@@ -68,7 +66,7 @@ export class Encoder extends Decoder {
68
66
  if (sharedStructures.uninitialized)
69
67
  encoder.structures = sharedStructures = encoder.getStructures()
70
68
  let sharedStructuresLength = sharedStructures.length
71
- if (sharedStructuresLength > maxSharedStructures && !isSequential)
69
+ if (sharedStructuresLength > maxSharedStructures && !isSequential)
72
70
  sharedStructuresLength = maxSharedStructures
73
71
  if (!sharedStructures.transitions) {
74
72
  // rebuild our structure transitions
@@ -78,8 +76,8 @@ export class Encoder extends Decoder {
78
76
  if (!keys)
79
77
  continue
80
78
  let nextTransition, transition = sharedStructures.transitions
81
- for (let i =0, l = keys.length; i < l; i++) {
82
- let key = keys[i]
79
+ for (let j = 0, l = keys.length; j < l; j++) {
80
+ let key = keys[j]
83
81
  nextTransition = transition[key]
84
82
  if (!nextTransition) {
85
83
  nextTransition = transition[key] = Object.create(null)
@@ -108,7 +106,12 @@ export class Encoder extends Decoder {
108
106
  referenceMap = null
109
107
  return serialized
110
108
  }
111
- return target.subarray(start, position) // position can change if we call encode again in saveStructures, so we get the buffer now
109
+ if (encodeOptions === REUSE_BUFFER_MODE) {
110
+ target.start = start
111
+ target.end = position
112
+ return target
113
+ }
114
+ return target.subarray(start, position) // position can change if we call pack again in saveStructures, so we get the buffer now
112
115
  } finally {
113
116
  if (sharedStructures) {
114
117
  if (serializationsSinceTransitionRebuild < 10)
@@ -122,7 +125,7 @@ export class Encoder extends Decoder {
122
125
  recordIdsToRemove = []
123
126
  } else if (recordIdsToRemove.length > 0 && !isSequential) {
124
127
  for (let i = 0, l = recordIdsToRemove.length; i < l; i++) {
125
- recordIdsToRemove[i][RECORD_SYMBOL] = 0
128
+ recordIdsToRemove[i][RECORD_SYMBOL] = undefined
126
129
  }
127
130
  recordIdsToRemove = []
128
131
  }
@@ -130,13 +133,15 @@ export class Encoder extends Decoder {
130
133
  if (encoder.structures.length > maxSharedStructures) {
131
134
  encoder.structures = encoder.structures.slice(0, maxSharedStructures)
132
135
  }
133
-
136
+ // we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save
137
+ let returnBuffer = target.subarray(start, position)
134
138
  if (encoder.saveStructures(encoder.structures, lastSharedStructuresLength) === false) {
135
139
  // get updated structures and try again if the update failed
136
140
  encoder.structures = encoder.getStructures() || []
137
141
  return encoder.encode(value)
138
142
  }
139
143
  lastSharedStructuresLength = encoder.structures.length
144
+ return returnBuffer
140
145
  }
141
146
  }
142
147
  }
@@ -257,7 +262,7 @@ export class Encoder extends Decoder {
257
262
  targetView.setFloat32(position, value)
258
263
  let xShifted
259
264
  if (useFloat32 < 4 ||
260
- // this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
265
+ // this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
261
266
  ((xShifted = value * mult10[((target[position] & 0x7f) << 1) | (target[position + 1] >> 7)]) >> 0) === xShifted) {
262
267
  position += 4
263
268
  return
@@ -303,6 +308,12 @@ export class Encoder extends Decoder {
303
308
  encode(value[i])
304
309
  }
305
310
  } else if (constructor === Map) {
311
+ if (this.mapsAsObjects ? this.useTag259ForMaps !== false : this.useTag259ForMaps) {
312
+ // use Tag 259 (https://github.com/shanewholloway/js-cbor-codec/blob/master/docs/CBOR-259-spec--explicit-maps.md) for maps if the user wants it that way
313
+ target[position++] = 0xd9
314
+ target[position++] = 1
315
+ target[position++] = 3
316
+ }
306
317
  length = value.size
307
318
  if (length < 0x18) {
308
319
  target[position++] = 0xa0 | length
@@ -380,10 +391,9 @@ export class Encoder extends Decoder {
380
391
  }
381
392
  position += 8
382
393
  } else if (type === 'undefined') {
383
- //target[position++] = 0xc1 // this is the "never-used" byte
384
394
  target[position++] = 0xf7
385
395
  } else {
386
- throw new Error('Unknown type ' + type)
396
+ throw new Error('Unknown type: ' + type)
387
397
  }
388
398
  }
389
399
 
@@ -472,7 +482,7 @@ export class Encoder extends Decoder {
472
482
  let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null))
473
483
  let newTransitions = 0
474
484
  let length = keys.length
475
- for (let i =0; i < length; i++) {
485
+ for (let i = 0; i < length; i++) {
476
486
  let key = keys[i]
477
487
  nextTransition = transition[key]
478
488
  if (!nextTransition) {
@@ -482,7 +492,7 @@ export class Encoder extends Decoder {
482
492
  transition = nextTransition
483
493
  }
484
494
  let recordId = transition[RECORD_SYMBOL]
485
- if (recordId) {
495
+ if (recordId !== undefined) {
486
496
  target[position++] = 0xd9 // tag two byte
487
497
  target[position++] = RECORD_STARTING_ID_PREFIX
488
498
  target[position++] = recordId
@@ -509,7 +519,7 @@ export class Encoder extends Decoder {
509
519
  transitionsCount += serializationsSinceTransitionRebuild * newTransitions
510
520
  // record the removal of the id, we can maintain our shared structure
511
521
  if (recordIdsToRemove.length >= MAX_STRUCTURES - maxSharedStructures)
512
- recordIdsToRemove.shift()[RECORD_SYMBOL] = 0 // we are cycling back through, and have to remove old ones
522
+ recordIdsToRemove.shift()[RECORD_SYMBOL] = undefined // we are cycling back through, and have to remove old ones
513
523
  recordIdsToRemove.push(transition)
514
524
  if (length < 0x16)
515
525
  target[position++] = 0x82 + length // array header, length of values + 2
@@ -655,7 +665,9 @@ function typedArrayEncoder(tag) {
655
665
  }
656
666
  function writeBuffer(buffer, makeRoom) {
657
667
  let length = buffer.byteLength
658
- if (length < 0x100) {
668
+ if (length < 0x18) {
669
+ target[position++] = 0x40 + length
670
+ } else if (length < 0x100) {
659
671
  target[position++] = 0x58
660
672
  target[position++] = length
661
673
  } else if (length < 0x10000) {
@@ -713,3 +725,4 @@ export const encode = defaultEncoder.encode
713
725
  export { FLOAT32_OPTIONS } from './decode.js'
714
726
  import { FLOAT32_OPTIONS } from './decode.js'
715
727
  export const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS
728
+ export const REUSE_BUFFER_MODE = 1000
package/index.d.ts CHANGED
@@ -1,10 +1,11 @@
1
- export { Decoder, decode, addExtension, FLOAT32_OPTIONS } from './decode.js'
1
+ export { Decoder, decode, addExtension, FLOAT32_OPTIONS, clearSource, roundFloat32 } from './decode.js'
2
2
  export { Encoder, encode } from './encode.js'
3
+ import { Transform, Readable } from 'stream'
3
4
 
4
- export as namespace msgpackr;
5
- export class DecoderStream {
5
+ export as namespace CBOR;
6
+ export class DecoderStream extends Transform {
7
+ constructor(options?: Options | { highWaterMark: number, emitClose: boolean, allowHalfOpen: boolean })
6
8
  }
7
- export class EncoderStream {
8
- write(value: any): void
9
- end(value?: any): void
9
+ export class EncoderStream extends Transform {
10
+ constructor(options?: Options | { highWaterMark: number, emitClose: boolean, allowHalfOpen: boolean })
10
11
  }
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export { Encoder, addExtension, encode, NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } from './encode.js'
2
- export { Tag, Decoder, decodeMultiple, decode, FLOAT32_OPTIONS } from './decode.js'
2
+ export { Tag, Decoder, decodeMultiple, decode, FLOAT32_OPTIONS, clearSource, roundFloat32 } from './decode.js'
3
+ export { decodeIter, encodeIter } from './iterators.js'
3
4
  export const useRecords = false
4
5
  export const mapsAsObjects = true
5
-
package/iterators.js ADDED
@@ -0,0 +1,85 @@
1
+ import { Encoder } from './encode.js'
2
+ import { Decoder } from './decode.js'
3
+
4
+ /**
5
+ * Given an Iterable first argument, returns an Iterable where each value is encoded as a Buffer
6
+ * If the argument is only Async Iterable, the return value will be an Async Iterable.
7
+ * @param {Iterable|Iterator|AsyncIterable|AsyncIterator} objectIterator - iterable source, like a Readable object stream, an array, Set, or custom object
8
+ * @param {options} [options] - cbor-x Encoder options
9
+ * @returns {IterableIterator|Promise.<AsyncIterableIterator>}
10
+ */
11
+ export function encodeIter (objectIterator, options = {}) {
12
+ if (!objectIterator || typeof objectIterator !== 'object') {
13
+ throw new Error('first argument must be an Iterable, Async Iterable, or a Promise for an Async Iterable')
14
+ } else if (typeof objectIterator[Symbol.iterator] === 'function') {
15
+ return encodeIterSync(objectIterator, options)
16
+ } else if (typeof objectIterator.then === 'function' || typeof objectIterator[Symbol.asyncIterator] === 'function') {
17
+ return encodeIterAsync(objectIterator, options)
18
+ } else {
19
+ throw new Error('first argument must be an Iterable, Async Iterable, Iterator, Async Iterator, or a Promise')
20
+ }
21
+ }
22
+
23
+ function * encodeIterSync (objectIterator, options) {
24
+ const encoder = new Encoder(options)
25
+ for (const value of objectIterator) {
26
+ yield encoder.encode(value)
27
+ }
28
+ }
29
+
30
+ async function * encodeIterAsync (objectIterator, options) {
31
+ const encoder = new Encoder(options)
32
+ for await (const value of objectIterator) {
33
+ yield encoder.encode(value)
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Given an Iterable/Iterator input which yields buffers, returns an IterableIterator which yields sync decoded objects
39
+ * Or, given an Async Iterable/Iterator which yields promises resolving in buffers, returns an AsyncIterableIterator.
40
+ * @param {Iterable|Iterator|AsyncIterable|AsyncIterableIterator} bufferIterator
41
+ * @param {object} [options] - Decoder options
42
+ * @returns {IterableIterator|Promise.<AsyncIterableIterator}
43
+ */
44
+ export function decodeIter (bufferIterator, options = {}) {
45
+ if (!bufferIterator || typeof bufferIterator !== 'object') {
46
+ throw new Error('first argument must be an Iterable, Async Iterable, Iterator, Async Iterator, or a promise')
47
+ }
48
+
49
+ const decoder = new Decoder(options)
50
+ let incomplete
51
+ const parser = (chunk) => {
52
+ let yields
53
+ // if there's incomplete data from previous chunk, concatinate and try again
54
+ if (incomplete) {
55
+ chunk = Buffer.concat([incomplete, chunk])
56
+ incomplete = undefined
57
+ }
58
+
59
+ try {
60
+ yields = decoder.decodeMultiple(chunk)
61
+ } catch (err) {
62
+ if (err.incomplete) {
63
+ incomplete = chunk.slice(err.lastPosition)
64
+ yields = err.values
65
+ } else {
66
+ throw err
67
+ }
68
+ }
69
+ return yields
70
+ }
71
+
72
+ if (typeof bufferIterator[Symbol.iterator] === 'function') {
73
+ return (function * iter () {
74
+ for (const value of bufferIterator) {
75
+ yield * parser(value)
76
+ }
77
+ })()
78
+ } else if (typeof bufferIterator[Symbol.asyncIterator] === 'function') {
79
+ return (async function * iter () {
80
+ for await (const value of bufferIterator) {
81
+ yield * parser(value)
82
+ }
83
+ })()
84
+ }
85
+ }
package/node-index.js ADDED
@@ -0,0 +1,24 @@
1
+ export { Encoder, addExtension, encode, NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT, REUSE_BUFFER_MODE } from './encode.js'
2
+ export { Tag, Decoder, decodeMultiple, decode, FLOAT32_OPTIONS, clearSource, roundFloat32 } from './decode.js'
3
+ export { EncoderStream, DecoderStream } from './stream.js'
4
+ export { decodeIter, encodeIter } from './iterators.js'
5
+ export const useRecords = false
6
+ export const mapsAsObjects = true
7
+ import { setExtractor } from './decode.js'
8
+ import { createRequire } from 'module'
9
+
10
+ const extractor = tryRequire('cbor-extract')
11
+ if (extractor)
12
+ setExtractor(extractor.extractStrings)
13
+
14
+ function tryRequire(moduleId) {
15
+ try {
16
+ let require = createRequire(import.meta.url)
17
+ return require(moduleId)
18
+ } catch (error) {
19
+ if (typeof window == 'undefined')
20
+ console.warn('Native extraction module not loaded, cbor-x will still run, but with decreased performance. ' + error.message.split('\n')[0])
21
+ else
22
+ console.warn('For browser usage, directly use cbor-x/decode or cbor-x/encode modules. ' + error.message.split('\n')[0])
23
+ }
24
+ }
package/package.json CHANGED
@@ -1,10 +1,12 @@
1
1
  {
2
2
  "name": "cbor-x",
3
3
  "author": "Kris Zyp",
4
- "version": "0.8.0",
4
+ "version": "0.9.0",
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,52 @@
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.2.2"
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-babel-minify": "^9.0.0"
69
68
  }
70
69
  }
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",
@@ -16,7 +16,7 @@ export default [
16
16
  output: {
17
17
  file: "dist/index.js",
18
18
  format: "umd",
19
- name: "msgpackr"
19
+ name: "CBOR"
20
20
  }
21
21
  },
22
22
  {
@@ -26,7 +26,7 @@ export default [
26
26
  output: {
27
27
  file: "dist/index.min.js",
28
28
  format: "umd",
29
- name: "msgpackr"
29
+ name: "CBOR"
30
30
  }
31
31
  },
32
32
  {
@@ -38,8 +38,8 @@ export default [
38
38
  format: "iife",
39
39
  globals: {
40
40
  chai: 'chai',
41
- './index.js': 'msgpackr',
41
+ './index.js': 'CBOR',
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");
@@ -43,12 +43,6 @@ console.log(rpad("", COL1, "-"), "|", lpad(":", COL2, "-"), "|", lpad(":", COL3,
43
43
 
44
44
  var buf, obj;
45
45
 
46
- if (JSON) {
47
- buf = bench('buf = Buffer(JSON.stringify(obj));', JSON_stringify, data);
48
- obj = bench('obj = JSON.parse(buf);', JSON.parse, buf);
49
- test(obj);
50
- }
51
-
52
46
  if (cborX) {
53
47
  // let packr = new msgpackr.Packr({ objectsAsMaps: true })
54
48
  buf = bench('require("cbor-x").encode(obj);', cborX.encode, data);
@@ -63,6 +57,18 @@ if (cborX) {
63
57
  obj = bench('cbor-x w/ shared structures: encoder.decode(buf);', encoder.decode.bind(encoder), buf);
64
58
  test(obj);
65
59
  }
60
+ if (JSON) {
61
+ buf = bench('buf = Buffer(JSON.stringify(obj));', JSON_stringify, data);
62
+ obj = bench('obj = JSON.parse(buf);', JSON.parse, buf);
63
+ test(obj);
64
+ }
65
+
66
+
67
+ if (JSON) {
68
+ buf = bench('buf = Buffer(JSON.stringify(obj));', JSON_stringify, data);
69
+ obj = bench('obj = JSON.parse(buf);', JSON.parse, buf);
70
+ test(obj);
71
+ }
66
72
 
67
73
  if (msgpack_lite) {
68
74
  buf = bench('buf = require("msgpack-lite").encode(obj);', msgpack_lite.encode, data);
@@ -1,26 +1,21 @@
1
- import * as data from './example4.json';
2
- import * as msgpackr from '..'
3
- import * as chai from 'chai'
1
+ const data = require('./example4.json');
2
+ const cborX = require('..');
3
+ const chai = require('chai');
4
4
 
5
- /*function tryRequire(module) {
5
+ 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') }
12
- assert = chai.assert
13
- if (typeof cborX === 'undefined') { cborX = require('..') }
13
+ const assert = chai.assert
14
14
  var cbor_module = tryRequire('cbor');
15
15
  var decode = cborX.decode
16
16
  var encode = cborX.encode
17
- //if (typeof msgpackr === 'undefined') { msgpackr = require('..') }
18
- var msgpack_msgpack = tryRequire('@msgpack/msgpack');
19
- var msgpack_lite = tryRequire('msgpack-lite');*/
20
- var unpack = msgpackr.unpack
21
- var pack = msgpackr.pack
22
17
 
23
- addCompatibilitySuite = (data) => () => {
18
+ const addCompatibilitySuite = (data) => () => {
24
19
  if (cbor_module) {
25
20
  test('from cbor', function(){
26
21
  var serialized = cbor_module.encode(data)
@@ -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
+ })