json-stable-stringify
Advanced tools
Comparing version 1.0.1 to 1.0.2
@@ -0,7 +1,9 @@ | ||
'use strict'; | ||
var stringify = require('../'); | ||
var obj = { c: 8, b: [{z:6,y:5,x:4},7], a: 3 }; | ||
var obj = { c: 8, b: [{ z: 6, y: 5, x: 4 }, 7], a: 3 }; | ||
var s = stringify(obj, function (a, b) { | ||
return a.key < b.key ? 1 : -1; | ||
return b.key.localeCompare(a.key); | ||
}); | ||
console.log(s); |
@@ -0,3 +1,7 @@ | ||
'use strict'; | ||
var stringify = require('../'); | ||
var obj = { c: 8, b: [{z:6,y:5,x:4},7], a: 3 }; | ||
var obj = { c: 8, b: [{ z: 6, y: 5, x: 4 }, 7], a: 3 }; | ||
console.log(stringify(obj)); |
@@ -0,3 +1,7 @@ | ||
'use strict'; | ||
var stringify = require('../'); | ||
var obj = { c: 6, b: [4,5], a: 3 }; | ||
var obj = { c: 6, b: [4, 5], a: 3 }; | ||
console.log(stringify(obj)); |
@@ -0,7 +1,11 @@ | ||
'use strict'; | ||
var stringify = require('../'); | ||
var obj = { d: 6, c: 5, b: [{z:3,y:2,x:1},9], a: 10 }; | ||
var obj = { d: 6, c: 5, b: [{ z: 3, y: 2, x: 1 }, 9], a: 10 }; | ||
var s = stringify(obj, function (a, b) { | ||
return a.value < b.value ? 1 : -1; | ||
return a.value < b.value ? 1 : -1; | ||
}); | ||
console.log(s); |
141
index.js
@@ -0,84 +1,85 @@ | ||
'use strict'; | ||
var json = typeof JSON !== 'undefined' ? JSON : require('jsonify'); | ||
var isArray = Array.isArray || function (x) { | ||
return {}.toString.call(x) === '[object Array]'; | ||
}; | ||
var objectKeys = Object.keys || function (obj) { | ||
var has = Object.prototype.hasOwnProperty || function () { return true; }; | ||
var keys = []; | ||
for (var key in obj) { | ||
if (has.call(obj, key)) { keys.push(key); } | ||
} | ||
return keys; | ||
}; | ||
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 cycles = (typeof opts.cycles === 'boolean') ? opts.cycles : false; | ||
var replacer = opts.replacer || function(key, value) { return value; }; | ||
if (!opts) { 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 replacer = opts.replacer || function (key, value) { return value; }; | ||
var cmp = opts.cmp && (function (f) { | ||
return function (node) { | ||
return function (a, b) { | ||
var aobj = { key: a, value: node[a] }; | ||
var bobj = { key: b, value: node[b] }; | ||
return f(aobj, bobj); | ||
}; | ||
}; | ||
})(opts.cmp); | ||
var cmp = opts.cmp && (function (f) { | ||
return function (node) { | ||
return function (a, b) { | ||
var aobj = { key: a, value: node[a] }; | ||
var bobj = { key: b, value: node[b] }; | ||
return f(aobj, bobj); | ||
}; | ||
}; | ||
}(opts.cmp)); | ||
var seen = []; | ||
return (function stringify (parent, key, node, level) { | ||
var indent = space ? ('\n' + new Array(level + 1).join(space)) : ''; | ||
var colonSeparator = space ? ': ' : ':'; | ||
var seen = []; | ||
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(); | ||
} | ||
if (node && node.toJSON && typeof node.toJSON === 'function') { | ||
node = node.toJSON(); | ||
} | ||
node = replacer.call(parent, key, node); | ||
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, 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__'); | ||
throw new TypeError('Converting circular structure to JSON'); | ||
} | ||
else seen.push(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, node[i], level + 1) || json.stringify(null); | ||
out.push(indent + space + item); | ||
} | ||
return '[' + out.join(',') + indent + ']'; | ||
} | ||
var keys = objectKeys(node).sort(cmp && cmp(node)); | ||
var out = []; | ||
for (var i = 0; i < keys.length; i++) { | ||
var key = keys[i]; | ||
var value = stringify(node, key, node[key], level+1); | ||
if (seen.indexOf(node) !== -1) { | ||
if (cycles) { return json.stringify('__cycle__'); } | ||
throw new TypeError('Converting circular structure to JSON'); | ||
} else { seen.push(node); } | ||
if(!value) continue; | ||
var keys = objectKeys(node).sort(cmp && cmp(node)); | ||
var out = []; | ||
for (var i = 0; i < keys.length; i++) { | ||
var key = keys[i]; | ||
var value = stringify(node, key, node[key], level + 1); | ||
var keyValue = json.stringify(key) | ||
+ colonSeparator | ||
+ value; | ||
; | ||
out.push(indent + space + keyValue); | ||
} | ||
seen.splice(seen.indexOf(node), 1); | ||
return '{' + out.join(',') + indent + '}'; | ||
} | ||
})({ '': obj }, '', obj, 0); | ||
}; | ||
if (!value) { continue; } | ||
var isArray = Array.isArray || function (x) { | ||
return {}.toString.call(x) === '[object Array]'; | ||
}; | ||
var keyValue = json.stringify(key) | ||
+ colonSeparator | ||
+ value; | ||
var objectKeys = Object.keys || function (obj) { | ||
var has = Object.prototype.hasOwnProperty || function () { return true }; | ||
var keys = []; | ||
for (var key in obj) { | ||
if (has.call(obj, key)) keys.push(key); | ||
} | ||
return keys; | ||
out.push(indent + space + keyValue); | ||
} | ||
seen.splice(seen.indexOf(node), 1); | ||
return '{' + out.join(',') + indent + '}'; | ||
}({ '': obj }, '', obj, 0)); | ||
}; |
118
package.json
{ | ||
"name": "json-stable-stringify", | ||
"version": "1.0.1", | ||
"description": "deterministic JSON.stringify() with custom sorting to get deterministic hashes from stringified results", | ||
"main": "index.js", | ||
"dependencies": { | ||
"jsonify": "~0.0.0" | ||
}, | ||
"devDependencies": { | ||
"tape": "~1.0.4" | ||
}, | ||
"scripts": { | ||
"test": "tape test/*.js" | ||
}, | ||
"testling": { | ||
"files": "test/*.js", | ||
"browsers": [ | ||
"ie/8..latest", | ||
"ff/5", "ff/latest", | ||
"chrome/15", "chrome/latest", | ||
"safari/latest", | ||
"opera/latest" | ||
] | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git://github.com/substack/json-stable-stringify.git" | ||
}, | ||
"homepage": "https://github.com/substack/json-stable-stringify", | ||
"keywords": [ | ||
"json", | ||
"stringify", | ||
"deterministic", | ||
"hash", | ||
"sort", | ||
"stable" | ||
], | ||
"author": { | ||
"name": "James Halliday", | ||
"email": "mail@substack.net", | ||
"url": "http://substack.net" | ||
}, | ||
"license": "MIT" | ||
"name": "json-stable-stringify", | ||
"version": "1.0.2", | ||
"description": "deterministic JSON.stringify() with custom sorting to get deterministic hashes from stringified results", | ||
"main": "index.js", | ||
"dependencies": { | ||
"jsonify": "^0.0.1" | ||
}, | ||
"devDependencies": { | ||
"@ljharb/eslint-config": "^21.0.0", | ||
"aud": "^2.0.1", | ||
"auto-changelog": "^2.4.0", | ||
"eslint": "=8.8.0", | ||
"in-publish": "^2.0.1", | ||
"npmignore": "^0.3.0", | ||
"safe-publish-latest": "^2.0.0", | ||
"tape": "^5.6.1" | ||
}, | ||
"scripts": { | ||
"prepack": "npmignore --auto --commentLines=autogenerated", | ||
"prepublishOnly": "safe-publish-latest", | ||
"prepublish": "not-in-publish || npm run prepublishOnly", | ||
"lint": "eslint --ext=js,mjs .", | ||
"pretest": "npm run lint", | ||
"tests-only": "tape 'test/**/*.js'", | ||
"test": "npm run tests-only", | ||
"posttest": "aud --production", | ||
"version": "auto-changelog && git add CHANGELOG.md", | ||
"postversion": "auto-changelog && git add CHANGELOG.md && git commit --no-edit --amend && git tag -f \"v$(node -e \"console.log(require('./package.json').version)\")\"" | ||
}, | ||
"testling": { | ||
"files": "test/*.js", | ||
"browsers": [ | ||
"ie/8..latest", | ||
"ff/5", | ||
"ff/latest", | ||
"chrome/15", | ||
"chrome/latest", | ||
"safari/latest", | ||
"opera/latest" | ||
] | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git://github.com/ljharb/json-stable-stringify.git" | ||
}, | ||
"homepage": "https://github.com/ljharb/json-stable-stringify", | ||
"keywords": [ | ||
"json", | ||
"stringify", | ||
"deterministic", | ||
"hash", | ||
"sort", | ||
"stable" | ||
], | ||
"author": { | ||
"name": "James Halliday", | ||
"email": "mail@substack.net", | ||
"url": "http://substack.net" | ||
}, | ||
"funding": { | ||
"url": "https://github.com/sponsors/ljharb" | ||
}, | ||
"license": "MIT", | ||
"auto-changelog": { | ||
"output": "CHANGELOG.md", | ||
"template": "keepachangelog", | ||
"unreleased": false, | ||
"commitLimit": false, | ||
"backfillLimit": false, | ||
"hideCredit": true | ||
}, | ||
"publishConfig": { | ||
"ignore": [ | ||
".github/workflows" | ||
] | ||
} | ||
} |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var test = require('tape'); | ||
@@ -5,8 +7,8 @@ var stringify = require('../'); | ||
test('custom comparison function', function (t) { | ||
t.plan(1); | ||
var obj = { c: 8, b: [{z:6,y:5,x:4},7], a: 3 }; | ||
var s = stringify(obj, function (a, b) { | ||
return a.key < b.key ? 1 : -1; | ||
}); | ||
t.equal(s, '{"c":8,"b":[{"z":6,"y":5,"x":4},7],"a":3}'); | ||
t.plan(1); | ||
var obj = { c: 8, b: [{ z: 6, y: 5, x: 4 }, 7], a: 3 }; | ||
var s = stringify(obj, function (a, b) { | ||
return a.key < b.key ? 1 : -1; | ||
}); | ||
t.equal(s, '{"c":8,"b":[{"z":6,"y":5,"x":4},7],"a":3}'); | ||
}); |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var test = require('tape'); | ||
@@ -5,32 +7,39 @@ var stringify = require('../'); | ||
test('nested', function (t) { | ||
t.plan(1); | ||
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}'); | ||
t.plan(1); | ||
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'); | ||
} | ||
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__"}}'); | ||
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__"}}'); | ||
}); | ||
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}}'); | ||
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}}'); | ||
}); | ||
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}}'); | ||
}); |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var test = require('tape'); | ||
@@ -8,3 +10,3 @@ var stringify = require('../'); | ||
var obj = { a: 1, b: 2, c: false }; | ||
var replacer = function(key, value) { return 'one'; }; | ||
var replacer = function () { return 'one'; }; | ||
@@ -18,5 +20,5 @@ t.equal(stringify(obj, { replacer: replacer }), '"one"'); | ||
var obj = { a: 1, b: 2, c: false }; | ||
var replacer = function(key, value) { | ||
if(value === 1) return 'one'; | ||
if(value === 2) return 'two'; | ||
var replacer = function (key, value) { | ||
if (value === 1) { return 'one'; } | ||
if (value === 2) { return 'two'; } | ||
return value; | ||
@@ -32,5 +34,5 @@ }; | ||
var obj = { a: 1, b: 2, c: false }; | ||
var replacer = function(key, value) { | ||
if(key === 'b') return { d: 1 }; | ||
if(value === 1) return 'one'; | ||
var replacer = function (key, value) { | ||
if (key === 'b') { return { d: 1 }; } | ||
if (value === 1) { return 'one'; } | ||
return value; | ||
@@ -46,4 +48,4 @@ }; | ||
var obj = { a: 1, b: 2, c: false }; | ||
var replacer = function(key, value) { | ||
if(value === false) return; | ||
var replacer = function (key, value) { | ||
if (value === false) { return; } | ||
return value; | ||
@@ -59,4 +61,4 @@ }; | ||
var obj = { a: 1, b: 2, c: false }; | ||
var replacer = function(key, value) { | ||
if(key === 'b') return ['one', 'two']; | ||
var replacer = function (key, value) { | ||
if (key === 'b') { return ['one', 'two']; } | ||
return value; | ||
@@ -71,6 +73,6 @@ }; | ||
var obj = { a: 1, b: 2, c: [1,2] }; | ||
var replacer = function(key, value) { | ||
if(value === 1) return 'one'; | ||
if(value === 2) return 'two'; | ||
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; | ||
@@ -77,0 +79,0 @@ }; |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var test = require('tape'); | ||
@@ -5,5 +7,7 @@ var stringify = require('../'); | ||
test('space parameter', function (t) { | ||
t.plan(1); | ||
var obj = { one: 1, two: 2 }; | ||
t.equal(stringify(obj, {space: ' '}), '' | ||
t.plan(1); | ||
var obj = { one: 1, two: 2 }; | ||
t.equal( | ||
stringify(obj, { space: ' ' }), | ||
'' | ||
+ '{\n' | ||
@@ -13,49 +17,58 @@ + ' "one": 1,\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' | ||
+ '}' | ||
); | ||
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' | ||
+ '}' | ||
); | ||
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' | ||
+ '}' | ||
); | ||
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, ' ')); | ||
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, ' ') | ||
); | ||
}); |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var test = require('tape'); | ||
@@ -5,5 +7,5 @@ var stringify = require('../'); | ||
test('simple object', function (t) { | ||
t.plan(1); | ||
var obj = { c: 6, b: [4,5], a: 3, z: null }; | ||
t.equal(stringify(obj), '{"a":3,"b":[4,5],"c":6,"z":null}'); | ||
t.plan(1); | ||
var obj = { c: 6, b: [4, 5], a: 3, z: null }; | ||
t.equal(stringify(obj), '{"a":3,"b":[4,5],"c":6,"z":null}'); | ||
}); | ||
@@ -10,0 +12,0 @@ |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var test = require('tape'); | ||
@@ -5,5 +7,5 @@ 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}' ); | ||
t.plan(1); | ||
var obj = { one: 1, two: 2, toJSON: function () { return { one: 1 }; } }; | ||
t.equal(stringify(obj), '{"one":1}'); | ||
}); | ||
@@ -13,3 +15,3 @@ | ||
t.plan(1); | ||
var obj = { one: 1, two: 2, toJSON: function() { return 'one'; } }; | ||
var obj = { one: 1, two: 2, toJSON: function () { return 'one'; } }; | ||
t.equal(stringify(obj), '"one"'); | ||
@@ -20,4 +22,4 @@ }); | ||
t.plan(1); | ||
var obj = { one: 1, two: 2, toJSON: function() { return ['one']; } }; | ||
var obj = { one: 1, two: 2, toJSON: function () { return ['one']; } }; | ||
t.equal(stringify(obj), '["one"]'); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
23776
18
310
0
159
8
1
Updatedjsonify@^0.0.1