From 933f645da8aae1d91a1fc6d9e8b5f2589c506d15 Mon Sep 17 00:00:00 2001 From: DigitalBrainJS Date: Thu, 10 Nov 2022 20:43:55 +0200 Subject: [PATCH] Added toJSONObject util; Fixed AxiosError.toJSON method to avoid circular references; --- lib/core/AxiosError.js | 2 +- lib/utils.js | 34 +++++++++++++++++++++++++++++++++- test/unit/utils/utils.js | 26 ++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/lib/core/AxiosError.js b/lib/core/AxiosError.js index 1539e9acbf..7141a8cdbf 100644 --- a/lib/core/AxiosError.js +++ b/lib/core/AxiosError.js @@ -45,7 +45,7 @@ utils.inherits(AxiosError, Error, { columnNumber: this.columnNumber, stack: this.stack, // Axios - config: this.config, + config: utils.toJSONObject(this.config), code: this.code, status: this.response && this.response.status ? this.response.status : null }; diff --git a/lib/utils.js b/lib/utils.js index 849d0444b1..2267723967 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -592,6 +592,37 @@ const toFiniteNumber = (value, defaultValue) => { return Number.isFinite(value) ? value : defaultValue; } +const toJSONObject = (obj) => { + const stack = new Array(10); + + const visit = (source, i) => { + + if (isObject(source)) { + if (stack.indexOf(source) >= 0) { + return; + } + + if(!('toJSON' in source)) { + stack[i] = source; + const target = isArray(source) ? [] : {}; + + forEach(source, (value, key) => { + const reducedValue = visit(value, i + 1); + !isUndefined(reducedValue) && (target[key] = reducedValue); + }); + + stack[i] = undefined; + + return target; + } + } + + return source; + } + + return visit(obj, 0); +} + export default { isArray, isArrayBuffer, @@ -637,5 +668,6 @@ export default { toFiniteNumber, findKey, global: _global, - isContextDefined + isContextDefined, + toJSONObject }; diff --git a/test/unit/utils/utils.js b/test/unit/utils/utils.js index 57a183a2fe..73f378878b 100644 --- a/test/unit/utils/utils.js +++ b/test/unit/utils/utils.js @@ -23,4 +23,30 @@ describe('utils', function (){ assert.equal(utils.isFormData(new FormData()), true); }); }); + + describe('toJSON', function (){ + it('should convert to a plain object without circular references', function () { + const obj= {a: [0]} + const source = {x:1, y:2, obj}; + source.circular1 = source; + obj.a[1] = obj; + + assert.deepStrictEqual(utils.toJSONObject(source), { + x: 1, y:2, obj: {a: [0]} + }); + }); + + it('should use objects with defined toJSON method without rebuilding', function () { + const objProp = {}; + const obj= {objProp, toJSON(){ + return {ok: 1} + }}; + const source = {x:1, y:2, obj}; + + const jsonObject = utils.toJSONObject(source); + + assert.strictEqual(jsonObject.obj.objProp, objProp); + assert.strictEqual(JSON.stringify(jsonObject), JSON.stringify({x: 1, y:2, obj: {ok: 1}})) + }); + }); });