Skip to content

Commit 9f43809

Browse files
justingrantmbroadst
authored andcommitted
fix(ejson): support array for replacer parameter in EJSON.stringify
* Fix EJSON.stringify if replacer is array (not function) Currently, passing an array form of the `replacer` parameter of EJSON.stringify will not work, despite the documentation saying that it should work. The cause is that the current implementation checks whether `replacer` is of type `object`, and if it is then it assumes that the `replacer` parameter is really the `options` parameter (meaning that `replacer` and `space` have been omitted by the user). This logic breaks when `replacer` is an array (which is an `object` too). To fix this problem I added a check using `Array.isArray` so the replacement above will only happen if `replacer` is an object that's not an array. While I was at it, I also changed the weird (and eslint-defying) use of assignment expressions ( `if (...) (options = space), (space = 0);` format to a more conventional statement form of assignment. * Added test for array-valued replacers Made sure that array-valued replacers work correctly. Also making sure that function-valued replacers work too. * Fixed bugs in test cases * removed unnecessary async function to fix Node 6 * EJSON serializing of ObjectID (capital D) + perf fix While I was testing my other fix, I found and fixed two other problems with EJSON serialization: * Fixes #303 - ObjectID (capital "D") instances can't be serialized to Extended JSON * Fixes #302 - Extended JSON serializer runs twice for every nested document I also noticed two other potential problems that I didn't know how to fix, so I added TODO comments in this commit for tracking later. If you want me to split these changes up into separate PRs from my original commits, I'm happy to do so-- just let me know. * Update EJSON tests for ObjectId and ObjectID Added tests to ensure that EJSON support for ObjectId works for three variations: * import ObjectId from 'bson'; * import ObjectID from 'bson'; * `import ObjectID from 'mongodb'; // verifies the fix for #303` * fixed browser test Ignoring the require('mongodb').ObjectID tests on the browser tests where that package is not available. * another fix for browser tests * another try to avoid browser test import error * reverted changes moved to other PRs
1 parent 2e08392 commit 9f43809

File tree

2 files changed

+27
-3
lines changed

2 files changed

+27
-3
lines changed

Diff for: lib/extended_json.js

+9-3
Original file line numberDiff line numberDiff line change
@@ -169,9 +169,15 @@ const BSON_INT32_MAX = 0x7fffffff,
169169
* console.log(EJSON.stringify(doc));
170170
*/
171171
function stringify(value, replacer, space, options) {
172-
if (space != null && typeof space === 'object') (options = space), (space = 0);
173-
if (replacer != null && typeof replacer === 'object')
174-
(options = replacer), (replacer = null), (space = 0);
172+
if (space != null && typeof space === 'object') {
173+
options = space;
174+
space = 0;
175+
}
176+
if (replacer != null && typeof replacer === 'object' && !Array.isArray(replacer)) {
177+
options = replacer;
178+
replacer = null;
179+
space = 0;
180+
}
175181
options = Object.assign({}, { relaxed: true }, options);
176182

177183
const doc = Array.isArray(value)

Diff for: test/node/extended_json_tests.js

+18
Original file line numberDiff line numberDiff line change
@@ -253,4 +253,22 @@ describe('Extended JSON', function() {
253253
expect(result.test).to.equal(34.12);
254254
expect(result.test).to.be.a('number');
255255
});
256+
257+
it('should work for function-valued and array-valued replacer parameters', function() {
258+
const doc = { a: new Int32(10), b: new Int32(10) };
259+
260+
var replacerArray = ['a', '$numberInt'];
261+
var serialized = EJSON.stringify(doc, replacerArray, 0, { relaxed: false });
262+
expect(serialized).to.equal('{"a":{"$numberInt":"10"}}');
263+
264+
serialized = EJSON.stringify(doc, replacerArray);
265+
expect(serialized).to.equal('{"a":10}');
266+
267+
var replacerFunc = function (key, value) { return key === 'b' ? undefined : value; }
268+
serialized = EJSON.stringify(doc, replacerFunc, 0, { relaxed: false });
269+
expect(serialized).to.equal('{"a":{"$numberInt":"10"}}');
270+
271+
serialized = EJSON.stringify(doc, replacerFunc);
272+
expect(serialized).to.equal('{"a":10}');
273+
});
256274
});

0 commit comments

Comments
 (0)