From 21c6592cf357c972387284b96999ba8273f08035 Mon Sep 17 00:00:00 2001 From: Damien Arrachequesne Date: Sat, 21 May 2022 02:11:09 +0200 Subject: [PATCH] feat: match JSON.stringify() behavior The library will now match the behavior of the JSON.stringify() method: - undefined is now encoded as nil (0xc0) - undefined values in objects are now ignored --- README.md | 2 +- browser/decode.js | 4 ---- browser/encode.js | 7 +++---- lib/decode.js | 4 ---- lib/encode.js | 8 ++++---- test/browser.js | 2 +- test/test.js | 19 ++++++++++++++++--- 7 files changed, 25 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index b4b743a..f9d4eff 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ A fast [Node.js](http://nodejs.org) implementation of the latest [MessagePack](h ## Notes * This implementation is not backwards compatible with those that use the older spec. It is recommended that this library is only used in isolated systems. -* `undefined` is encoded as `fixext 1 [0, 0]`, i.e. `` +* `undefined` is encoded as `nil` * `Date` objects are encoded as `fixext 8 [0, ms]`, e.g. `new Date('2000-06-13T00:00:00.000Z')` => `` * `ArrayBuffer` are encoded as `ext 8/16/32 [0, data]`, e.g. `Uint8Array.of(1, 2, 3, 4)` => `` diff --git a/browser/decode.js b/browser/decode.js index 95bd420..6bec7bf 100644 --- a/browser/decode.js +++ b/browser/decode.js @@ -203,10 +203,6 @@ Decoder.prototype._parse = function () { case 0xd4: type = this._view.getInt8(this._offset); this._offset += 1; - if (type === 0x00) { - this._offset += 1; - return void 0; - } return [type, this._bin(1)]; case 0xd5: type = this._view.getInt8(this._offset); diff --git a/browser/encode.js b/browser/encode.js index 394e830..77caf97 100644 --- a/browser/encode.js +++ b/browser/encode.js @@ -218,7 +218,7 @@ function _encode(bytes, defers, value) { var allKeys = Object.keys(value); for (i = 0, l = allKeys.length; i < l; i++) { key = allKeys[i]; - if (typeof value[key] !== 'function') { + if (value[key] !== undefined && typeof value[key] !== 'function') { keys.push(key); } } @@ -254,10 +254,9 @@ function _encode(bytes, defers, value) { bytes.push(value ? 0xc3 : 0xc2); return 1; } - // fixext 1 / undefined if (type === 'undefined') { - bytes.push(0xd4, 0, 0); - return 3; + bytes.push(0xc0); + return 1; } // custom types like BigInt (typeof value === 'bigint') if (typeof value.toJSON === 'function') { diff --git a/lib/decode.js b/lib/decode.js index 5692c76..c67dac5 100644 --- a/lib/decode.js +++ b/lib/decode.js @@ -189,10 +189,6 @@ Decoder.prototype.parse = function () { case 0xd4: type = this.buffer.readInt8(this.offset); this.offset += 1; - if (type === 0x00) { - this.offset += 1; - return void 0; - } return [type, this.bin(1)]; case 0xd5: type = this.buffer.readInt8(this.offset); diff --git a/lib/encode.js b/lib/encode.js index e976515..a6b54e1 100644 --- a/lib/encode.js +++ b/lib/encode.js @@ -246,7 +246,7 @@ function _encode(bytes, defers, value) { for (let i = 0, l = allKeys.length; i < l; i++) { key = allKeys[i]; - if (typeof value[key] !== 'function') { + if (value[key] !== undefined && typeof value[key] !== 'function') { keys.push(key); } } @@ -274,9 +274,9 @@ function _encode(bytes, defers, value) { case 'boolean': // false/true bytes.push(value ? 0xc3 : 0xc2); return 1; - case 'undefined': // fixext 1 / undefined - bytes.push(0xd4, 0, 0); - return 3; + case 'undefined': + bytes.push(0xc0); + return 1; default: // custom types like BigInt (typeof value === 'bigint') if (typeof value.toJSON === 'function') { diff --git a/test/browser.js b/test/browser.js index 3b2e89a..2e6ced2 100644 --- a/test/browser.js +++ b/test/browser.js @@ -73,7 +73,7 @@ describe('notepack (browser build)', function() { map: {}, nil: null, bool: { 'true': true, 'false': false, both: [true, false, false, false, true] }, - fixext: [undefined, new Date('2140-01-01T13:14:15.678Z'), undefined, new Date('2005-12-31T23:59:59.999Z')], + fixext: [null, new Date('2140-01-01T13:14:15.678Z'), null, new Date('2005-12-31T23:59:59.999Z')], utf8: ['α', '亜', '\uD83D\uDC26'], float: [1.1, 1234567891234567.5, Infinity, -Infinity, NaN] }; diff --git a/test/test.js b/test/test.js index 2975b7b..03c5566 100644 --- a/test/test.js +++ b/test/test.js @@ -71,6 +71,7 @@ describe('notepack', function () { it('nil', function () { check(null, 'c0'); + checkEncode(undefined, 'c0'); }); it('false', function () { @@ -208,8 +209,7 @@ describe('notepack', function () { check(-Math.pow(2, 63) - 1024, 'd38000000000000000'); }); - it('fixext 1 / undefined', function () { - check(undefined, 'd40000'); + it('fixext 1', function () { checkDecode([127, Buffer.from('a')], 'd4' + '7f' + '61'); }); @@ -311,7 +311,7 @@ describe('notepack', function () { map: {}, nil: null, bool: { 'true': true, 'false': false, both: [true, false, false, false, true] }, - fixext: [undefined, new Date('2140-01-01T13:14:15.678Z'), undefined, new Date('2005-12-31T23:59:59.999Z')] + fixext: [null, new Date('2140-01-01T13:14:15.678Z'), null, new Date('2005-12-31T23:59:59.999Z')] }; expected.map['a'.repeat(32)] = { a: 'a', b: 'b', c: 'c' }; expected.map['b'.repeat(256)] = { a: { b: 1, c: 1, d: 1, e: { f: { g: 2, h: 2 } } } }; @@ -322,6 +322,19 @@ describe('notepack', function () { expect(notepack.decode(notepack.encode(expected))).to.deep.equal(expected); }); + it('undefined as array elem or map value', function () { + const value = { + a: undefined, + b: null, + c: [undefined, null] + }; + const expected = { + b: null, + c: [null, null] + }; + expect(notepack.decode(notepack.encode(value))).to.deep.equal(expected); + }); + it('10000', function () { const fixture = require('./fixtures/10000.json');