From 3f4e9c78befc32f7d36af68e408e25cdc84be202 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Wed, 17 Jul 2013 17:43:46 -0700 Subject: [PATCH 01/23] don't choke on null --- index.js | 2 +- test/str.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index ef30c9b..1d609bf 100644 --- a/index.js +++ b/index.js @@ -14,7 +14,7 @@ module.exports = function (obj, opts) { })(opts.cmp); return (function stringify (node) { - if (typeof node !== 'object') { + if (typeof node !== 'object' || node === null) { return json.stringify(node); } if (isArray(node)) { diff --git a/test/str.js b/test/str.js index 02c97fb..d0e9159 100644 --- a/test/str.js +++ b/test/str.js @@ -3,6 +3,6 @@ var stringify = require('../'); test('simple object', function (t) { t.plan(1); - var obj = { c: 6, b: [4,5], a: 3 }; - t.equal(stringify(obj), '{"a":3,"b":[4,5],"c":6}'); + var obj = { c: 6, b: [4,5], a: 3, z: null }; + t.equal(stringify(obj), '{"a":3,"b":[4,5],"c":6,"z":null}'); }); From 20a2e830b5fc42f776e5c348ff4967f2b8481ef9 Mon Sep 17 00:00:00 2001 From: James Halliday Date: Wed, 17 Jul 2013 17:47:32 -0700 Subject: [PATCH 02/23] 0.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3693d85..7034e3f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "json-stable-stringify", - "version": "0.0.0", + "version": "0.0.1", "description": "deterministic JSON.stringify() with custom sorting to get deterministic hashes from stringified results", "main": "index.js", "dependencies": { From e6815c9dd8ca4052023d2bbd5c5b78b44f0efef0 Mon Sep 17 00:00:00 2001 From: rprieto Date: Sat, 21 Dec 2013 23:49:27 +1100 Subject: [PATCH 03/23] =?UTF-8?q?New=20=E2=80=9Cspace=E2=80=9D=20option=20?= =?UTF-8?q?to=20enable=20pretty=20printing=20(same=20as=20ES5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.js | 18 ++++++++++----- readme.markdown | 32 +++++++++++++++++++++++++++ test/space.js | 59 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+), 6 deletions(-) create mode 100644 test/space.js diff --git a/index.js b/index.js index 1d609bf..ddfa0b1 100644 --- a/index.js +++ b/index.js @@ -3,6 +3,8 @@ var json = typeof JSON !== 'undefined' ? JSON : require('jsonify'); module.exports = function (obj, opts) { if (!opts) opts = {}; if (typeof opts === 'function') opts = { cmp: opts }; + var space = opts.space || ''; + if (typeof space === 'number') space = Array(space+1).join(' '); var cmp = opts.cmp && (function (f) { return function (node) { return function (a, b) { @@ -13,27 +15,31 @@ module.exports = function (obj, opts) { }; })(opts.cmp); - return (function stringify (node) { + return (function stringify (node, level) { + var indent = space ? ('\n' + new Array(level + 1).join(space)) : ''; + var colonSeparator = space ? ': ' : ':'; if (typeof node !== 'object' || node === null) { return json.stringify(node); } if (isArray(node)) { var out = []; for (var i = 0; i < node.length; i++) { - out.push(stringify(node[i])); + var item = stringify(node[i], level+1); + out.push(indent + space + item); } - return '[' + out.join(',') + ']'; + return '[' + out.join(',') + indent + ']'; } else { var keys = objectKeys(node).sort(cmp && cmp(node)); var out = []; for (var i = 0; i < keys.length; i++) { var key = keys[i]; - out.push(stringify(key) + ':' + stringify(node[key])); + var keyValue = stringify(key,0) + colonSeparator + stringify(node[key],level+1); + out.push(indent + space + keyValue); } - return '{' + out.join(',') + '}'; + return '{' + out.join(',') + indent + '}'; } - })(obj); + })(obj, 0); }; var isArray = Array.isArray || function (x) { diff --git a/readme.markdown b/readme.markdown index 3a3d00c..38a1305 100644 --- a/readme.markdown +++ b/readme.markdown @@ -33,6 +33,10 @@ var stringify = require('json-stable-stringify') Return a deterministic stringified string `str` from the object `obj`. +## options + +### cmp + If `opts` is given, you can supply an `opts.cmp` to have a custom comparison function for object keys. Your function `opts.cmp` is called with these parameters: @@ -77,6 +81,34 @@ which outputs: {"d":6,"c":5,"b":[{"z":3,"y":2,"x":1},9],"a":10} ``` +### space + +If you specify `opts.space`, it will indent the output for pretty-printing. Valid values are strings (e.g. `{space: \t}`) or a number of spaces (`{space: 3}`). + +For example: + +```js +var obj = { b: 1, a: { foo: 'bar', and: [1, 2, 3] } }; +var s = stringify(obj, { space: ' ' }); +console.log(s); +``` + +which outputs: + +``` +{ + "a": { + "and": [ + 1, + 2, + 3 + ], + "foo": "bar" + }, + "b": 1 +} +``` + # install With [npm](https://npmjs.org) do: diff --git a/test/space.js b/test/space.js new file mode 100644 index 0000000..2621122 --- /dev/null +++ b/test/space.js @@ -0,0 +1,59 @@ +var test = require('tape'); +var stringify = require('../'); + +test('space parameter', function (t) { + t.plan(1); + var obj = { one: 1, two: 2 }; + t.equal(stringify(obj, {space: ' '}), '' + + '{\n' + + ' "one": 1,\n' + + ' "two": 2\n' + + '}' + ); +}); + +test('space parameter (with tabs)', function (t) { + t.plan(1); + var obj = { one: 1, two: 2 }; + t.equal(stringify(obj, {space: '\t'}), '' + + '{\n' + + '\t"one": 1,\n' + + '\t"two": 2\n' + + '}' + ); +}); + +test('space parameter (with a number)', function (t) { + t.plan(1); + var obj = { one: 1, two: 2 }; + t.equal(stringify(obj, {space: 3}), '' + + '{\n' + + ' "one": 1,\n' + + ' "two": 2\n' + + '}' + ); +}); + +test('space parameter (nested objects)', function (t) { + t.plan(1); + var obj = { one: 1, two: { b: 4, a: [2,3] } }; + t.equal(stringify(obj, {space: ' '}), '' + + '{\n' + + ' "one": 1,\n' + + ' "two": {\n' + + ' "a": [\n' + + ' 2,\n' + + ' 3\n' + + ' ],\n' + + ' "b": 4\n' + + ' }\n' + + '}' + ); +}); + +test('space parameter (same as native)', function (t) { + t.plan(1); + // for this test, properties need to be in alphabetical order + var obj = { one: 1, two: { a: [2,3], b: 4 } }; + t.equal(stringify(obj, {space: ' '}), JSON.stringify(obj, null, ' ')); +}); From 962edf4abb96189546b4f78f8719d747fd90fd43 Mon Sep 17 00:00:00 2001 From: James Halliday Date: Sat, 21 Dec 2013 20:01:28 -0800 Subject: [PATCH 04/23] formatting --- readme.markdown | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/readme.markdown b/readme.markdown index 38a1305..81adb49 100644 --- a/readme.markdown +++ b/readme.markdown @@ -83,7 +83,9 @@ which outputs: ### space -If you specify `opts.space`, it will indent the output for pretty-printing. Valid values are strings (e.g. `{space: \t}`) or a number of spaces (`{space: 3}`). +If you specify `opts.space`, it will indent the output for pretty-printing. +Valid values are strings (e.g. `{space: \t}`) or a number of spaces +(`{space: 3}`). For example: From d03f90cd3fbf08ed002da19190e74f3b9bbd70ae Mon Sep 17 00:00:00 2001 From: James Halliday Date: Sat, 21 Dec 2013 20:01:59 -0800 Subject: [PATCH 05/23] 0.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7034e3f..d9ac9f6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "json-stable-stringify", - "version": "0.0.1", + "version": "0.1.0", "description": "deterministic JSON.stringify() with custom sorting to get deterministic hashes from stringified results", "main": "index.js", "dependencies": { From 7e139e8bbeb37b4dfd44991f4d6c98bba446b949 Mon Sep 17 00:00:00 2001 From: James Halliday Date: Sat, 21 Dec 2013 20:06:32 -0800 Subject: [PATCH 06/23] fixed merge conflicts --- index.js | 10 ++++++++++ test/nested.js | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/index.js b/index.js index ddfa0b1..f307a63 100644 --- a/index.js +++ b/index.js @@ -5,6 +5,8 @@ module.exports = function (obj, opts) { if (typeof opts === 'function') opts = { cmp: opts }; var space = opts.space || ''; if (typeof space === 'number') space = Array(space+1).join(' '); + var cycles = (typeof opts.cycles === 'boolean') ? opts.cycles : false; + var cmp = opts.cmp && (function (f) { return function (node) { return function (a, b) { @@ -15,9 +17,11 @@ module.exports = function (obj, opts) { }; })(opts.cmp); + var seen = []; return (function stringify (node, level) { var indent = space ? ('\n' + new Array(level + 1).join(space)) : ''; var colonSeparator = space ? ': ' : ':'; + if (typeof node !== 'object' || node === null) { return json.stringify(node); } @@ -30,6 +34,12 @@ module.exports = function (obj, opts) { return '[' + out.join(',') + indent + ']'; } else { + if (seen.indexOf(node) !== -1) { + if (cycles) return stringify('__cycle__'); + else throw new TypeError('Converting circular structure to JSON'); + } else { + seen.push(node); + } var keys = objectKeys(node).sort(cmp && cmp(node)); var out = []; for (var i = 0; i < keys.length; i++) { diff --git a/test/nested.js b/test/nested.js index 43459f2..78aeaed 100644 --- a/test/nested.js +++ b/test/nested.js @@ -6,3 +6,23 @@ test('nested', function (t) { var obj = { c: 8, b: [{z:6,y:5,x:4},7], a: 3 }; t.equal(stringify(obj), '{"a":3,"b":[{"x":4,"y":5,"z":6},7],"c":8}'); }); + +test('cyclic (default)', function (t) { + t.plan(1); + var one = { a: 1 }; + var two = { a: 2, one: one }; + one.two = two; + try { + stringify(one); + } catch (ex) { + t.equal(ex.toString(), 'TypeError: Converting circular structure to JSON'); + } +}); + +test('cyclic (specifically allowed)', function (t) { + t.plan(1); + var one = { a: 1 }; + var two = { a: 2, one: one }; + one.two = two; + t.equal(stringify(one, {cycles:true}), '{"a":1,"two":{"a":2,"one":"__cycle__"}}'); +}); From b5df6b9ec0f5a5826eebb5d93424923041e43405 Mon Sep 17 00:00:00 2001 From: James Halliday Date: Sat, 21 Dec 2013 20:07:45 -0800 Subject: [PATCH 07/23] fix formatting --- index.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index f307a63..3f764af 100644 --- a/index.js +++ b/index.js @@ -36,15 +36,18 @@ module.exports = function (obj, opts) { else { if (seen.indexOf(node) !== -1) { if (cycles) return stringify('__cycle__'); - else throw new TypeError('Converting circular structure to JSON'); - } else { - seen.push(node); + throw new TypeError('Converting circular structure to JSON'); } + else seen.push(node); + var keys = objectKeys(node).sort(cmp && cmp(node)); var out = []; for (var i = 0; i < keys.length; i++) { var key = keys[i]; - var keyValue = stringify(key,0) + colonSeparator + stringify(node[key],level+1); + var keyValue = stringify(key,0) + + colonSeparator + + stringify(node[key],level+1) + ; out.push(indent + space + keyValue); } return '{' + out.join(',') + indent + '}'; From 82b5eab6b7883b59c2e48e0806dab70537bae1ad Mon Sep 17 00:00:00 2001 From: James Halliday Date: Sat, 21 Dec 2013 20:07:52 -0800 Subject: [PATCH 08/23] 0.1.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d9ac9f6..7cf7dc1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "json-stable-stringify", - "version": "0.1.0", + "version": "0.1.1", "description": "deterministic JSON.stringify() with custom sorting to get deterministic hashes from stringified results", "main": "index.js", "dependencies": { From c1de9d193e8d6755d6ea2c2e5ead0544a8122040 Mon Sep 17 00:00:00 2001 From: Rick Eyre Date: Tue, 4 Feb 2014 17:48:34 -0500 Subject: [PATCH 09/23] Should call 'toJSON' if it is defined on the object being stringified. --- index.js | 5 ++++- test/to-json.js | 8 ++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 test/to-json.js diff --git a/index.js b/index.js index 3f764af..2222fc9 100644 --- a/index.js +++ b/index.js @@ -39,7 +39,10 @@ module.exports = function (obj, opts) { throw new TypeError('Converting circular structure to JSON'); } else seen.push(node); - + + if (node.toJSON && typeof node.toJSON === 'function') { + node = node.toJSON(); + } var keys = objectKeys(node).sort(cmp && cmp(node)); var out = []; for (var i = 0; i < keys.length; i++) { diff --git a/test/to-json.js b/test/to-json.js new file mode 100644 index 0000000..cd9e83e --- /dev/null +++ b/test/to-json.js @@ -0,0 +1,8 @@ +var test = require('tape'); +var stringify = require('../'); + +test('toJSON function', function (t) { + t.plan(1); + var obj = { one: 1, two: 2, toJSON: function() { return { one: 1 }; } }; + t.equal(stringify(obj), '{"one":1}' ); +}); From 7ff314fabf3b40074a4aff906b16e087897c6040 Mon Sep 17 00:00:00 2001 From: James Halliday Date: Wed, 2 Apr 2014 21:39:22 -0700 Subject: [PATCH 10/23] reindent --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 2222fc9..25e7f1e 100644 --- a/index.js +++ b/index.js @@ -39,7 +39,7 @@ module.exports = function (obj, opts) { throw new TypeError('Converting circular structure to JSON'); } else seen.push(node); - + if (node.toJSON && typeof node.toJSON === 'function') { node = node.toJSON(); } From 7da89fddfd8fcbe8911eb802dbcc26dec6c396f7 Mon Sep 17 00:00:00 2001 From: James Halliday Date: Wed, 2 Apr 2014 21:39:36 -0700 Subject: [PATCH 11/23] 0.1.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7cf7dc1..bf1973f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "json-stable-stringify", - "version": "0.1.1", + "version": "0.1.2", "description": "deterministic JSON.stringify() with custom sorting to get deterministic hashes from stringified results", "main": "index.js", "dependencies": { From a723f705dd13fcbab1aa0ffa51849395712aaa13 Mon Sep 17 00:00:00 2001 From: James Halliday Date: Wed, 2 Apr 2014 21:40:37 -0700 Subject: [PATCH 12/23] guard the reference --- index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index 25e7f1e..17b2885 100644 --- a/index.js +++ b/index.js @@ -40,9 +40,9 @@ module.exports = function (obj, opts) { } else seen.push(node); - if (node.toJSON && typeof node.toJSON === 'function') { - node = node.toJSON(); - } + if (node && node.toJSON && typeof node.toJSON === 'function') { + node = node.toJSON(); + } var keys = objectKeys(node).sort(cmp && cmp(node)); var out = []; for (var i = 0; i < keys.length; i++) { From de0debff3a36604010279af1868c6172674f9cc9 Mon Sep 17 00:00:00 2001 From: Mirza Kapetanovic Date: Tue, 27 May 2014 10:34:56 +0200 Subject: [PATCH 13/23] Enable toJSON function to return different types --- index.js | 14 +++++++------- test/to-json.js | 12 ++++++++++++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/index.js b/index.js index 17b2885..e320408 100644 --- a/index.js +++ b/index.js @@ -6,7 +6,7 @@ module.exports = function (obj, opts) { var space = opts.space || ''; if (typeof space === 'number') space = Array(space+1).join(' '); var cycles = (typeof opts.cycles === 'boolean') ? opts.cycles : false; - + var cmp = opts.cmp && (function (f) { return function (node) { return function (a, b) { @@ -16,12 +16,15 @@ module.exports = function (obj, opts) { }; }; })(opts.cmp); - + var seen = []; return (function stringify (node, level) { var indent = space ? ('\n' + new Array(level + 1).join(space)) : ''; var colonSeparator = space ? ': ' : ':'; - + + if (node && node.toJSON && typeof node.toJSON === 'function') { + node = node.toJSON(); + } if (typeof node !== 'object' || node === null) { return json.stringify(node); } @@ -39,10 +42,7 @@ module.exports = function (obj, opts) { throw new TypeError('Converting circular structure to JSON'); } else seen.push(node); - - if (node && node.toJSON && typeof node.toJSON === 'function') { - node = node.toJSON(); - } + var keys = objectKeys(node).sort(cmp && cmp(node)); var out = []; for (var i = 0; i < keys.length; i++) { diff --git a/test/to-json.js b/test/to-json.js index cd9e83e..ef9a980 100644 --- a/test/to-json.js +++ b/test/to-json.js @@ -6,3 +6,15 @@ test('toJSON function', function (t) { var obj = { one: 1, two: 2, toJSON: function() { return { one: 1 }; } }; t.equal(stringify(obj), '{"one":1}' ); }); + +test('toJSON returns string', function (t) { + t.plan(1); + var obj = { one: 1, two: 2, toJSON: function() { return 'one'; } }; + t.equal(stringify(obj), '"one"'); +}); + +test('toJSON returns array', function (t) { + t.plan(1); + var obj = { one: 1, two: 2, toJSON: function() { return ['one']; } }; + t.equal(stringify(obj), '["one"]'); +}); From 9ad5deb9220c0254b2779ff43764f789978e9fdd Mon Sep 17 00:00:00 2001 From: James Halliday Date: Tue, 27 May 2014 03:48:37 -0700 Subject: [PATCH 14/23] 0.1.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bf1973f..db6c709 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "json-stable-stringify", - "version": "0.1.2", + "version": "0.1.3", "description": "deterministic JSON.stringify() with custom sorting to get deterministic hashes from stringified results", "main": "index.js", "dependencies": { From ccf5e636803a55d062e97aaf4e2c27d5c787aff0 Mon Sep 17 00:00:00 2001 From: Mirza Kapetanovic Date: Tue, 27 May 2014 13:26:21 +0200 Subject: [PATCH 15/23] Added options.replacer for custom object serialization --- index.js | 23 +++++++++++---- test/replacer.js | 74 ++++++++++++++++++++++++++++++++++++++++++++++++ test/str.js | 24 ++++++++++++++++ 3 files changed, 115 insertions(+), 6 deletions(-) create mode 100644 test/replacer.js diff --git a/index.js b/index.js index e320408..87b1555 100644 --- a/index.js +++ b/index.js @@ -6,6 +6,7 @@ module.exports = function (obj, opts) { var space = opts.space || ''; if (typeof space === 'number') space = Array(space+1).join(' '); var cycles = (typeof opts.cycles === 'boolean') ? opts.cycles : false; + var replacer = opts.replacer || function(key, value) { return value; }; var cmp = opts.cmp && (function (f) { return function (node) { @@ -18,27 +19,33 @@ module.exports = function (obj, opts) { })(opts.cmp); var seen = []; - return (function stringify (node, level) { + return (function stringify (parent, key, node, level) { var indent = space ? ('\n' + new Array(level + 1).join(space)) : ''; var colonSeparator = space ? ': ' : ':'; if (node && node.toJSON && typeof node.toJSON === 'function') { node = node.toJSON(); } + + node = replacer.call(parent, key, node); + + if (node === undefined) { + return; + } if (typeof node !== 'object' || node === null) { return json.stringify(node); } if (isArray(node)) { var out = []; for (var i = 0; i < node.length; i++) { - var item = stringify(node[i], level+1); + var item = stringify(node, i, node[i], level+1) || json.stringify(null); out.push(indent + space + item); } return '[' + out.join(',') + indent + ']'; } else { if (seen.indexOf(node) !== -1) { - if (cycles) return stringify('__cycle__'); + if (cycles) return json.stringify('__cycle__'); throw new TypeError('Converting circular structure to JSON'); } else seen.push(node); @@ -47,15 +54,19 @@ module.exports = function (obj, opts) { var out = []; for (var i = 0; i < keys.length; i++) { var key = keys[i]; - var keyValue = stringify(key,0) + var value = stringify(node, key, node[key], level+1); + + if(!value) continue; + + var keyValue = json.stringify(key) + colonSeparator - + stringify(node[key],level+1) + + value; ; out.push(indent + space + keyValue); } return '{' + out.join(',') + indent + '}'; } - })(obj, 0); + })({ '': obj }, '', obj, 0); }; var isArray = Array.isArray || function (x) { diff --git a/test/replacer.js b/test/replacer.js new file mode 100644 index 0000000..98802a7 --- /dev/null +++ b/test/replacer.js @@ -0,0 +1,74 @@ +var test = require('tape'); +var stringify = require('../'); + +test('replace root', function (t) { + t.plan(1); + + var obj = { a: 1, b: 2, c: false }; + var replacer = function(key, value) { return 'one'; }; + + t.equal(stringify(obj, { replacer: replacer }), '"one"'); +}); + +test('replace numbers', function (t) { + t.plan(1); + + var obj = { a: 1, b: 2, c: false }; + var replacer = function(key, value) { + if(value === 1) return 'one'; + if(value === 2) return 'two'; + return value; + }; + + t.equal(stringify(obj, { replacer: replacer }), '{"a":"one","b":"two","c":false}'); +}); + +test('replace with object', function (t) { + t.plan(1); + + var obj = { a: 1, b: 2, c: false }; + var replacer = function(key, value) { + if(key === 'b') return { d: 1 }; + if(value === 1) return 'one'; + return value; + }; + + t.equal(stringify(obj, { replacer: replacer }), '{"a":"one","b":{"d":"one"},"c":false}'); +}); + +test('replace with undefined', function (t) { + t.plan(1); + + var obj = { a: 1, b: 2, c: false }; + var replacer = function(key, value) { + if(value === false) return; + return value; + }; + + t.equal(stringify(obj, { replacer: replacer }), '{"a":1,"b":2}'); +}); + +test('replace with array', function (t) { + t.plan(1); + + var obj = { a: 1, b: 2, c: false }; + var replacer = function(key, value) { + if(key === 'b') return ['one', 'two']; + return value; + }; + + t.equal(stringify(obj, { replacer: replacer }), '{"a":1,"b":["one","two"],"c":false}'); +}); + +test('replace array item', function (t) { + t.plan(1); + + var obj = { a: 1, b: 2, c: [1,2] }; + var replacer = function(key, value) { + if(value === 1) return 'one'; + if(value === 2) return 'two'; + return value; + }; + + t.equal(stringify(obj, { replacer: replacer }), '{"a":"one","b":"two","c":["one","two"]}'); +}); diff --git a/test/str.js b/test/str.js index d0e9159..67426b9 100644 --- a/test/str.js +++ b/test/str.js @@ -6,3 +6,27 @@ test('simple object', function (t) { var obj = { c: 6, b: [4,5], a: 3, z: null }; t.equal(stringify(obj), '{"a":3,"b":[4,5],"c":6,"z":null}'); }); + +test('object with undefined', function (t) { + t.plan(1); + var obj = { a: 3, z: undefined }; + t.equal(stringify(obj), '{"a":3}'); +}); + +test('array with undefined', function (t) { + t.plan(1); + var obj = [4, undefined, 6]; + t.equal(stringify(obj), '[4,null,6]'); +}); + +test('object with empty string', function (t) { + t.plan(1); + var obj = { a: 3, z: '' }; + t.equal(stringify(obj), '{"a":3,"z":""}'); +}); + +test('array with empty string', function (t) { + t.plan(1); + var obj = [4, '', 6]; + t.equal(stringify(obj), '[4,"",6]'); +}); From 894f43b633724bf0c6c2741143addfe20e149015 Mon Sep 17 00:00:00 2001 From: James Halliday Date: Tue, 27 May 2014 05:48:34 -0700 Subject: [PATCH 16/23] document replacer --- readme.markdown | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/readme.markdown b/readme.markdown index 81adb49..406c3c7 100644 --- a/readme.markdown +++ b/readme.markdown @@ -111,6 +111,12 @@ which outputs: } ``` +### replacer + +The replacer parameter is a function `opts.replacer(key, value)` that behaves +the same as the replacer +[from the core JSON object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_native_JSON#The_replacer_parameter). + # install With [npm](https://npmjs.org) do: From f70d44441a4a4161796e779952312b35ec336442 Mon Sep 17 00:00:00 2001 From: James Halliday Date: Tue, 27 May 2014 05:48:59 -0700 Subject: [PATCH 17/23] 1.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index db6c709..72f9280 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "json-stable-stringify", - "version": "0.1.3", + "version": "1.0.0", "description": "deterministic JSON.stringify() with custom sorting to get deterministic hashes from stringified results", "main": "index.js", "dependencies": { From c26c700f0b1d078512d2eba0eb16d6e5110a5538 Mon Sep 17 00:00:00 2001 From: Blake Thomson Date: Wed, 15 Apr 2015 12:56:27 -0400 Subject: [PATCH 18/23] Correctly stringify non-cyclic shared references --- .gitignore | 1 + index.js | 1 + test/nested.js | 7 +++++++ 3 files changed, 9 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/index.js b/index.js index 87b1555..6a4131d 100644 --- a/index.js +++ b/index.js @@ -64,6 +64,7 @@ module.exports = function (obj, opts) { ; out.push(indent + space + keyValue); } + seen.splice(seen.indexOf(node), 1); return '{' + out.join(',') + indent + '}'; } })({ '': obj }, '', obj, 0); diff --git a/test/nested.js b/test/nested.js index 78aeaed..026ebd5 100644 --- a/test/nested.js +++ b/test/nested.js @@ -26,3 +26,10 @@ test('cyclic (specifically allowed)', function (t) { one.two = two; t.equal(stringify(one, {cycles:true}), '{"a":1,"two":{"a":2,"one":"__cycle__"}}'); }); + +test('repeated non-cyclic value', function(t) { + t.plan(1); + var one = { x: 1 }; + var two = { a: one, b: one }; + t.equal(stringify(two), '{"a":{"x":1},"b":{"x":1}}'); +}); From 7f5f443e90402a520f1413833318b02bbb11ad67 Mon Sep 17 00:00:00 2001 From: Mark Vayngrib Date: Tue, 13 Oct 2015 19:09:44 +0100 Subject: [PATCH 19/23] add breaking test (acyclic detected as cyclic) --- test/nested.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/nested.js b/test/nested.js index 78aeaed..12be32c 100644 --- a/test/nested.js +++ b/test/nested.js @@ -26,3 +26,10 @@ test('cyclic (specifically allowed)', function (t) { one.two = two; t.equal(stringify(one, {cycles:true}), '{"a":1,"two":{"a":2,"one":"__cycle__"}}'); }); + +test('acyclic but with reused obj-property pointers', function (t) { + t.plan(1); + var x = { a: 1 } + var y = { b: x, c: x } + t.equal(stringify(y), '{"b":{"a":1},"c":{"a":1}}'); +}); From 4a3ac9cc006a91e64901f8ebe78d23bf9fc9fbd0 Mon Sep 17 00:00:00 2001 From: James Halliday Date: Tue, 2 Feb 2016 10:05:52 -0800 Subject: [PATCH 20/23] 1.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 72f9280..4fbcc34 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "json-stable-stringify", - "version": "1.0.0", + "version": "1.0.1", "description": "deterministic JSON.stringify() with custom sorting to get deterministic hashes from stringified results", "main": "index.js", "dependencies": { From 0bbbe0e52344459aa3c01021c779d455811e3888 Mon Sep 17 00:00:00 2001 From: Sam Neubardt Date: Thu, 15 Dec 2016 16:57:29 -0500 Subject: [PATCH 21/23] Remove dependency on jsonify it's unlicensed which means that packages that depend on it (even transitively) can't be used in organizations that require explicit permission to use or copy a work. --- index.js | 10 ++++------ package.json | 9 ++++----- readme.markdown | 2 ++ 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/index.js b/index.js index 6a4131d..a6f40c7 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,3 @@ -var json = typeof JSON !== 'undefined' ? JSON : require('jsonify'); - module.exports = function (obj, opts) { if (!opts) opts = {}; if (typeof opts === 'function') opts = { cmp: opts }; @@ -33,19 +31,19 @@ module.exports = function (obj, opts) { return; } if (typeof node !== 'object' || node === null) { - return json.stringify(node); + return JSON.stringify(node); } if (isArray(node)) { var out = []; for (var i = 0; i < node.length; i++) { - var item = stringify(node, i, node[i], level+1) || json.stringify(null); + var item = stringify(node, i, node[i], level+1) || JSON.stringify(null); out.push(indent + space + item); } return '[' + out.join(',') + indent + ']'; } else { if (seen.indexOf(node) !== -1) { - if (cycles) return json.stringify('__cycle__'); + if (cycles) return JSON.stringify('__cycle__'); throw new TypeError('Converting circular structure to JSON'); } else seen.push(node); @@ -58,7 +56,7 @@ module.exports = function (obj, opts) { if(!value) continue; - var keyValue = json.stringify(key) + var keyValue = JSON.stringify(key) + colonSeparator + value; ; diff --git a/package.json b/package.json index 4fbcc34..2129f4b 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,9 @@ { - "name": "json-stable-stringify", + "name": "@samn/json-stable-stringify", "version": "1.0.1", - "description": "deterministic JSON.stringify() with custom sorting to get deterministic hashes from stringified results", + "description": "deterministic JSON.stringify() with custom sorting to get deterministic hashes from stringified results, with no public domain dependencies", "main": "index.js", "dependencies": { - "jsonify": "~0.0.0" }, "devDependencies": { "tape": "~1.0.4" @@ -24,9 +23,9 @@ }, "repository": { "type": "git", - "url": "git://github.com/substack/json-stable-stringify.git" + "url": "git://github.com/samn/json-stable-stringify.git" }, - "homepage": "https://github.com/substack/json-stable-stringify", + "homepage": "https://github.com/samn/json-stable-stringify", "keywords": [ "json", "stringify", diff --git a/readme.markdown b/readme.markdown index 406c3c7..e95b468 100644 --- a/readme.markdown +++ b/readme.markdown @@ -1,5 +1,7 @@ # json-stable-stringify +This is the same as https://github.com/substack/json-stable-stringify but it doesn't depend on libraries without licenses (jsonify). + deterministic version of `JSON.stringify()` so you can get a consistent hash from stringified results From c0b3c36d976c54e31a814c492cd1c2557a4d3758 Mon Sep 17 00:00:00 2001 From: Sam Neubardt Date: Thu, 15 Dec 2016 17:00:06 -0500 Subject: [PATCH 22/23] Change package name to json-stable-stringify-without-jsonify --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2129f4b..c59c87e 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "@samn/json-stable-stringify", + "name": "json-stable-stringify-without-jsonify", "version": "1.0.1", "description": "deterministic JSON.stringify() with custom sorting to get deterministic hashes from stringified results, with no public domain dependencies", "main": "index.js", From 08f7d956e83277dd40aad6df91179ab25e66748d Mon Sep 17 00:00:00 2001 From: stefnotch Date: Fri, 8 May 2020 15:00:55 +0200 Subject: [PATCH 23/23] Specify files to publish to npm Currently the `example` and `test` folders and various dotfiles such as `.travis.yml` are being published to npm. Considering that they make up about half of the file size of this package, it would be worthwhile to exclude them. This PR excludes them using the using the [`files`](https://docs.npmjs.com/files/package.json#files) whitelist in the `package.json`. --- package.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index c59c87e..2184fea 100644 --- a/package.json +++ b/package.json @@ -39,5 +39,8 @@ "email": "mail@substack.net", "url": "http://substack.net" }, - "license": "MIT" + "license": "MIT", + "files": [ + "index.js" + ] }