/*global Set */ /** * Recursively print out all names and values in a data structure. * @module jsdoc/util/dumper * @author Michael Mathews * @license Apache License 2.0 - See file 'LICENSE.md' in this project. */ 'use strict'; var util = require('util'); var setDefined = typeof Set !== 'undefined'; function ObjectWalker() { if (setDefined) { this.seenItems = new Set(); } else { this.seenItems = []; } } ObjectWalker.prototype.seen = function(object) { var result; if (setDefined) { result = this.seenItems.has(object); } else { result = object.hasBeenSeenByWalkerDumper; } return result; }; ObjectWalker.prototype.markAsSeen = function(object) { if (setDefined) { this.seenItems.add(object); } else { object.hasBeenSeenByWalkerDumper = true; this.seenItems.push(object); } }; ObjectWalker.prototype.cleanSeenFlag = function() { if (setDefined) { this.seenItems = new Set(); } else { this.seenItems.forEach(function(object) { delete object.hasBeenSeenByWalkerDumper; }); } }; // some objects are unwalkable, like Java native objects ObjectWalker.prototype.isUnwalkable = function(o) { return (o && typeof o === 'object' && typeof o.constructor === 'undefined'); }; ObjectWalker.prototype.isFunction = function(o) { return (o && typeof o === 'function' || o instanceof Function); }; ObjectWalker.prototype.isObject = function(o) { return o && o instanceof Object || (o && typeof o.constructor !== 'undefined' && o.constructor.name === 'Object'); }; ObjectWalker.prototype.checkCircularRefs = function(o, func) { if ( this.seen(o) ) { return ''; } else { this.markAsSeen(o); return func(o); } }; ObjectWalker.prototype.walk = function(o) { var result; var self = this; if ( this.isUnwalkable(o) ) { result = ''; } else if ( o === undefined ) { result = null; } else if ( Array.isArray(o) ) { result = this.checkCircularRefs(o, function(arr) { var newArray = []; arr.forEach(function(item) { newArray.push( self.walk(item) ); }); return newArray; }); } else if ( util.isRegExp(o) ) { result = ''; } else if ( util.isDate(o) ) { result = ''; } else if ( util.isError(o) ) { result = { message: o.message }; } else if ( this.isFunction(o) ) { result = ''; } 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; } newObj[key] = self.walk(obj[key]); }); return newObj; }); } // should be safe to JSON.stringify() everything else else { result = o; } return result; }; /** * @param {*} object */ exports.dump = function(object) { var walker = new ObjectWalker(); var result = JSON.stringify(walker.walk(object), null, 4); walker.cleanSeenFlag(); return result; };