diff --git a/jsdoc.js b/jsdoc.js index 5ea476d4..6f63faa2 100755 --- a/jsdoc.js +++ b/jsdoc.js @@ -136,10 +136,10 @@ global.app = { global.dump = function() { 'use strict'; - var doop = require('./lib/jsdoc/util/doop').doop; var _dump = require('./lib/jsdoc/util/dumper').dump; + for (var i = 0, l = arguments.length; i < l; i++) { - console.log( _dump(doop(arguments[i])) ); + console.log( _dump(arguments[i]) ); } }; diff --git a/lib/jsdoc/util/doop.js b/lib/jsdoc/util/doop.js index ba0fea2f..52b68e79 100644 --- a/lib/jsdoc/util/doop.js +++ b/lib/jsdoc/util/doop.js @@ -26,7 +26,8 @@ function hasItem(set, item) { } } -// TODO: should share code with jsdoc/util/dumper~ObjectWalker +// TODO: can we remove the circular-ref checking? pretty sure it's not needed anymore... +// if we need this here for some reason I'm forgetting, we should share code with jsdoc/util/dumper function doop(o, seen) { var clone; var descriptor; diff --git a/lib/jsdoc/util/dumper.js b/lib/jsdoc/util/dumper.js index 3e3f88de..96795cb6 100644 --- a/lib/jsdoc/util/dumper.js +++ b/lib/jsdoc/util/dumper.js @@ -8,42 +8,37 @@ 'use strict'; var util = require('util'); -var setDefined = typeof Set !== 'undefined'; + +var OBJECT_WALKER_KEY = 'hasBeenSeenByWalkerDumper'; +var SET_DEFINED = (typeof Set !== 'undefined'); function ObjectWalker() { - if (setDefined) { - this.seenItems = new Set(); - } else { - this.seenItems = []; - } + this.seenItems = SET_DEFINED ? new Set() : []; } ObjectWalker.prototype.seen = function(object) { var result; - if (setDefined) { + + if (SET_DEFINED) { result = this.seenItems.has(object); } else { - result = object.hasBeenSeenByWalkerDumper; + result = object[OBJECT_WALKER_KEY]; } return result; }; ObjectWalker.prototype.markAsSeen = function(object) { - if (setDefined) { + if (SET_DEFINED) { this.seenItems.add(object); } else { - object.hasBeenSeenByWalkerDumper = true; + object[OBJECT_WALKER_KEY] = true; this.seenItems.push(object); } }; -ObjectWalker.prototype.cleanSeenFlag = function() { - if (setDefined) { - this.seenItems = new Set(); - } else { - this.seenItems.forEach(function(object) { - delete object.hasBeenSeenByWalkerDumper; - }); +ObjectWalker.prototype.removeSeenFlag = function(obj) { + if (!SET_DEFINED) { + delete obj[OBJECT_WALKER_KEY]; } }; @@ -85,10 +80,13 @@ ObjectWalker.prototype.walk = function(o) { else if ( Array.isArray(o) ) { result = this.checkCircularRefs(o, function(arr) { var newArray = []; + arr.forEach(function(item) { newArray.push( self.walk(item) ); }); + self.removeSeenFlag(arr); + return newArray; }); } @@ -107,11 +105,14 @@ ObjectWalker.prototype.walk = function(o) { else if ( this.isObject(o) && o !== null ) { result = this.checkCircularRefs(o, function(obj) { var newObj = {}; + Object.keys(obj).forEach(function(key) { - if (!setDefined && key === 'hasBeenSeenByWalkerDumper') { return; } + if (!SET_DEFINED && key === OBJECT_WALKER_KEY) { return; } newObj[key] = self.walk(obj[key]); }); + self.removeSeenFlag(obj); + return newObj; }); } @@ -128,8 +129,6 @@ ObjectWalker.prototype.walk = function(o) { */ exports.dump = function(object) { var walker = new ObjectWalker(); - var result = JSON.stringify(walker.walk(object), null, 4); - walker.cleanSeenFlag(); - return result; + return JSON.stringify(walker.walk(object), null, 4); }; diff --git a/test/specs/jsdoc/util/dumper.js b/test/specs/jsdoc/util/dumper.js index 37fb11c0..67deabf3 100644 --- a/test/specs/jsdoc/util/dumper.js +++ b/test/specs/jsdoc/util/dumper.js @@ -140,5 +140,33 @@ describe('jsdoc/util/dumper', function() { expect(actual).toBe(expected); }); + + it('should not treat references between different objects as circular refs', function() { + var a = [ + { + b: { + c: 1 + } + } + ]; + a[1] = { d: a[0].b }; + + var actual = dumper.dump(a); + var expected = '' + + '[\n' + + ' {\n' + + ' "b": {\n' + + ' "c": 1\n' + + ' }\n' + + ' },\n' + + ' {\n' + + ' "d": {\n' + + ' "c": 1\n' + + ' }\n' + + ' }\n' + + ']'; + + expect(actual).toBe(expected); + }); }); });