Skip to content

Commit

Permalink
fixed issue with undefined values in objects and arrays
Browse files Browse the repository at this point in the history
  • Loading branch information
erdtman committed Nov 16, 2020
1 parent b196dbc commit 242580b
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 29 deletions.
49 changes: 20 additions & 29 deletions lib/canonicalize.js
Expand Up @@ -2,35 +2,26 @@
/* jslint node: true */
'use strict';

module.exports = function (object) {
return serialize(object);
module.exports = function serialize (object) {
if (object === null || typeof object !== 'object' || object.toJSON != null) {
return JSON.stringify(object);
}

function serialize (object) {
if (object === null || typeof object !== 'object' || object.toJSON != null) {
return JSON.stringify(object);
}
if (Array.isArray(object) && object.length === 0) {
return '[]';
}
if (Array.isArray(object) && object.length === 1) {
return '[' + serialize(object[0]) + ']';
}
if (Array.isArray(object)) {
return '[' + object.reduce((t, cv, ci) => {
t = (ci === 1 ? serialize(t) : t);
return t + ',' + serialize(cv);
}) + ']';
}
const keys = Object.keys(object);
if (keys.length === 0) {
return '{}';
}
if (keys.length === 1) {
return '{' + serialize(keys[0]) + ':' + serialize(object[keys[0]]) + '}';
}
return '{' + keys.sort().reduce((t, cv, ci) => {
t = (ci === 1 ? serialize(t) + ':' + serialize(object[t]) : t);
return t + ',' + serialize(cv) + ':' + serialize(object[cv]);
}) + '}';
if (Array.isArray(object)) {
return '[' + object.reduce((t, cv, ci) => {
const comma = ci === 0 ? '' : ',';
const value = cv === undefined ? null : cv;
return t + comma + serialize(value);
}, '') + ']';
}

let atFirstKey = true;
return '{' + Object.keys(object).sort().reduce((t, cv, ci) => {
if (object[cv] === undefined) {
return t;
}
const comma = atFirstKey ? '' : ',';
atFirstKey = false;
return t + comma + serialize(cv) + ':' + serialize(object[cv]);
}, '') + '}';
};
69 changes: 69 additions & 0 deletions test/simpletests.js
@@ -0,0 +1,69 @@
/* jshint esversion: 6 */
/* jslint node: true */
'use strict';

JSON.canonicalize = require('../');
const test = require('ava');

test('empty array', t => {
const input = [];
const expected = '[]';
const actual = JSON.canonicalize(input);
t.is(actual, expected);
});

test('one element array', t => {
const input = [123];
const expected = '[123]';
const actual = JSON.canonicalize(input);
t.is(actual, expected);
});

test('multi element array', t => {
const input = [123, 456, 'hello'];
const expected = '[123,456,"hello"]';
const actual = JSON.canonicalize(input);
t.is(actual, expected);
});

test('null and undefined values in array', t => {
const input = [null, undefined, 'hello'];
const expected = '[null,null,"hello"]';
const actual = JSON.canonicalize(input);
t.is(actual, expected);
});

test('empty object', t => {
const input = {};
const expected = '{}';
const actual = JSON.canonicalize(input);
t.is(actual, expected);
});

test('object with undefined value', t => {
const input = { test: undefined };
const expected = '{}';
const actual = JSON.canonicalize(input);
t.is(actual, expected);
});

test('object with null value', t => {
const input = { test: null };
const expected = '{"test":null}';
const actual = JSON.canonicalize(input);
t.is(actual, expected);
});

test('object with one property', t => {
const input = { hello: 'world' };
const expected = '{"hello":"world"}';
const actual = JSON.canonicalize(input);
t.is(actual, expected);
});

test('object with more than one property', t => {
const input = { hello: 'world', number: 123 };
const expected = '{"hello":"world","number":123}';
const actual = JSON.canonicalize(input);
t.is(actual, expected);
});

0 comments on commit 242580b

Please sign in to comment.