diff --git a/README.md b/README.md index aae2b13..ded57fd 100644 --- a/README.md +++ b/README.md @@ -316,6 +316,11 @@ jsesc([ 'foo\x00bar', [1, '©', { 'foo': true, 'qux': null }], 42 ], { 'json': true }); // → '["foo\\u0000bar",[1,"\\u00A9",{"foo":true,"qux":null}],42]' +// Undefined object properties are skipped, similarily to `JSON.stringify()`: +jsesc({ foo: undefined, bar: null }, { + 'json': true +}); +// → '{"bar": null}' // Values that aren’t allowed in JSON are run through `JSON.stringify()`: jsesc([ undefined, -Infinity ], { 'json': true diff --git a/jsesc.js b/jsesc.js index 7b8b923..46b25a6 100644 --- a/jsesc.js +++ b/jsesc.js @@ -2,9 +2,11 @@ const object = {}; const hasOwnProperty = object.hasOwnProperty; -const forOwn = (object, callback) => { +const forOwn = (object, callback, noUndefined) => { for (const key in object) { - if (hasOwnProperty.call(object, key)) { + if (hasOwnProperty.call(object, key) && + (!noUndefined || (typeof object[key] !== 'undefined')) + ) { callback(key, object[key]); } } @@ -225,7 +227,7 @@ const jsesc = (argument, options) => { (compact ? '' : ' ') + jsesc(value, options) ); - }); + }, !!json); if (isEmpty) { return '{}'; } diff --git a/src/jsesc.js b/src/jsesc.js index d3eaff1..fe677b4 100644 --- a/src/jsesc.js +++ b/src/jsesc.js @@ -2,9 +2,11 @@ const object = {}; const hasOwnProperty = object.hasOwnProperty; -const forOwn = (object, callback) => { +const forOwn = (object, callback, noUndefined) => { for (const key in object) { - if (hasOwnProperty.call(object, key)) { + if (hasOwnProperty.call(object, key) && + (!noUndefined || (typeof object[key] !== 'undefined')) + ) { callback(key, object[key]); } } @@ -225,7 +227,7 @@ const jsesc = (argument, options) => { (compact ? '' : ' ') + jsesc(value, options) ); - }); + }, !!json); if (isEmpty) { return '{}'; } diff --git a/tests/tests.js b/tests/tests.js index 403b9c0..4eab5ca 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -605,7 +605,7 @@ describe('advanced tests', function() { // Some of these depend on `JSON.parse()`, so only test them in Node const testArray = [ - undefined, Infinity, new Number(Infinity), -Infinity, + undefined, { foo: undefined }, Infinity, new Number(Infinity), -Infinity, new Number(-Infinity), 0, new Number(0), -0, new Number(-0), +0, new Number(+0), new Function(), 'str', function zomg() { return 'desu'; }, null, true, new Boolean(true), @@ -617,14 +617,14 @@ describe('advanced tests', function() { jsesc(testArray, { 'json': false }), - '[undefined,Infinity,Infinity,-Infinity,-Infinity,0,0,0,0,0,0,function anonymous() {\n\n},\'str\',function zomg() { return \'desu\'; },null,true,true,false,false,{\'foo\':42,\'hah\':[1,2,3,{\'foo\':42}]}]', + '[undefined,{\'foo\':undefined},Infinity,Infinity,-Infinity,-Infinity,0,0,0,0,0,0,function anonymous() {\n\n},\'str\',function zomg() { return \'desu\'; },null,true,true,false,false,{\'foo\':42,\'hah\':[1,2,3,{\'foo\':42}]}]', 'Escaping a non-flat array with all kinds of values' ); assert.equal( jsesc(testArray, { 'json': true }), - '[null,null,null,null,null,0,0,0,0,0,0,null,"str",null,null,true,true,false,false,{"foo":42,"hah":[1,2,3,{"foo":42}]}]', + '[null,{},null,null,null,null,0,0,0,0,0,0,null,"str",null,null,true,true,false,false,{"foo":42,"hah":[1,2,3,{"foo":42}]}]', 'Escaping a non-flat array with all kinds of values, with `json: true`' ); assert.equal( @@ -632,8 +632,8 @@ describe('advanced tests', function() { 'json': true, 'compact': false }), - '[\n\tnull,\n\tnull,\n\tnull,\n\tnull,\n\tnull,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\tnull,\n\t"str",\n\tnull,\n\tnull,\n\ttrue,\n\ttrue,\n\tfalse,\n\tfalse,\n\t{\n\t\t"foo": 42,\n\t\t"hah": [\n\t\t\t1,\n\t\t\t2,\n\t\t\t3,\n\t\t\t{\n\t\t\t\t"foo": 42\n\t\t\t}\n\t\t]\n\t}\n]', + '[\n\tnull,\n\t{},\n\tnull,\n\tnull,\n\tnull,\n\tnull,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\tnull,\n\t"str",\n\tnull,\n\tnull,\n\ttrue,\n\ttrue,\n\tfalse,\n\tfalse,\n\t{\n\t\t"foo": 42,\n\t\t"hah": [\n\t\t\t1,\n\t\t\t2,\n\t\t\t3,\n\t\t\t{\n\t\t\t\t"foo": 42\n\t\t\t}\n\t\t]\n\t}\n]', 'Escaping a non-flat array with all kinds of values, with `json: true, compact: false`' ); - }).timeout(25000); + }).timeout(30000); });