From 8c65d81e232bc13275d80a28a53cdaeaace4c630 Mon Sep 17 00:00:00 2001 From: Jeff Williams Date: Thu, 18 Apr 2013 23:16:47 -0700 Subject: [PATCH] match Node.js' console.log/error/info/warn/trace; speed up -X option (#298) --- jsdoc.js | 2 +- lib/jsdoc/util/dumper.js | 189 +++++++++++--------------------- rhino/rhino-shim.js | 47 ++++---- templates/haruki/publish.js | 2 +- test/specs/jsdoc/util/dumper.js | 16 +-- 5 files changed, 99 insertions(+), 157 deletions(-) diff --git a/jsdoc.js b/jsdoc.js index 21e3dd94..d7ff21f9 100644 --- a/jsdoc.js +++ b/jsdoc.js @@ -231,7 +231,7 @@ function main() { borrow.resolveBorrows(docs); if (env.opts.explain) { - console.log(docs); + dump(docs); process.exit(0); } diff --git a/lib/jsdoc/util/dumper.js b/lib/jsdoc/util/dumper.js index 247b42af..e22279dc 100644 --- a/lib/jsdoc/util/dumper.js +++ b/lib/jsdoc/util/dumper.js @@ -1,155 +1,94 @@ /** - 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. + * 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. */ -const INDENTATION = ' '; // 4 spaces -var indentBy, - output; +var util = require('util'); -function pad(depth) { - var padding = ''; - while (depth--) { - padding += INDENTATION; +var seenItems = []; +function seen(object) { + if (seenItems.indexOf(object) !== -1) { + return true; } - return padding; -} -/** - @param {string} openingBrace - The opening brace to add, like "{". - @private - @inner - @memberof module:jsdoc/util/dumper - */ -function indent(openingBrace) { - indentBy++; - if (openingBrace) { output += openingBrace + '\n'; } -} - -/** - @param {string|boolean} closingBrace - The closing brace to add, like "}" or if boolean - `false` no closing brace or trailing newline. - @private - @inner - @memberof module:jsdoc/util/dumper - */ -function outdent(closingBrace) { - indentBy--; - output = output.replace(/,\n$/, '\n'); // trim trailing comma - if (closingBrace === false) { output = output.replace(/\n$/, ''); } - else if (closingBrace) { output += pad(indentBy) + closingBrace + ',\n'; } -} - -var seen = []; -seen.has = function(object) { - for (var i = 0, l = seen.length; i < l; i++) { - if (seen[i] === object) { return true; } - } return false; -}; - -function stringify(o) { - return JSON.stringify(o); } -function getValue(o) { // see: https://developer.mozilla.org/en/JavaScript/Reference/Operators/Special/typeof - if (o === null) { return 'null'; } - if ( /^(string|boolean|number|undefined)$/.test(typeof o) ) { - return ''+stringify(o); - } -} - -function isUnwalkable(o) { // some objects are unwalkable, like Java native objects - return (typeof o === 'object' && typeof o.constructor === 'undefined'); -} - -function isArray(o) { - return o && (o instanceof Array) || o.constructor === Array; -} - -function isRegExp(o) { - return (o instanceof RegExp) || - (typeof o.constructor !== 'undefined' && o.constructor.name === 'RegExp'); -} - -function isDate(o) { - return o && (o instanceof Date) || - (typeof o.constructor !== 'undefined' && o.constructor.name === 'Date'); +// some objects are unwalkable, like Java native objects +function isUnwalkable(o) { + return (o && typeof o === 'object' && typeof o.constructor === 'undefined'); } function isFunction(o) { - return o && (typeof o === 'function' || o instanceof Function);// || - //(typeof o.constructor !== 'undefined' && (o.constructor||{}).name === 'Function'); + return (o && typeof o === 'function' || o instanceof Function); } function isObject(o) { - return o && o instanceof Object || - (typeof o.constructor !== 'undefined' && o.constructor.name === 'Object'); + return o && o instanceof Object || + (o && typeof o.constructor !== 'undefined' && o.constructor.name === 'Object'); } -function walk(object) { - var value = getValue(object); - if (value) { - output += value + ',\n'; +function checkCircularRefs(o, func) { + if ( seen(o) ) { + return ''; } - else if ( isUnwalkable(object) ) { - output += ',\n'; + else { + seenItems.push(o); + return func.call(this, o); } - else if ( isRegExp(object) ) { - output += ',\n'; +} + +function walk(o) { + var result; + + if ( isUnwalkable(o) ) { + result = ''; } - else if ( isDate(object) ) { - output += ',\n'; + else if ( o === undefined ) { + result = 'undefined'; } - else if ( isFunction(object) ) { - output += ',\n'; + else if ( Array.isArray(o) ) { + result = checkCircularRefs(o, function(arr) { + var newArray = []; + arr.forEach(function(item) { + newArray.push( walk(item) ); + }); + + return newArray; + }); } - else if ( isArray(object) ) { - if ( seen.has(object) ) { - output += ',\n'; - return; - } - else { - seen.push(object); - } - - indent('['); - for (var i = 0, leni = object.length; i < leni; i++) { - output += pad(indentBy); // + i + ': '; - walk( object[i] ); - } - outdent(']'); + else if ( util.isRegExp(o) ) { + result = ''; } - else if ( isObject(object) ) { - if ( seen.has(object) ) { - output += ',\n'; - return; - } - else { - seen.push(object); - } - - indent('{'); - for (var p in object) { - if ( object.hasOwnProperty(p) ) { - output += pad(indentBy) + stringify(p) + ': '; - walk( object[p] ); - } - } - outdent('}'); + else if ( util.isDate(o) ) { + result = ''; } + else if ( isFunction(o) ) { + result = ''; + } + else if ( isObject(o) && o !== null ) { + result = checkCircularRefs(o, function(obj) { + var newObj = {}; + Object.keys(obj).forEach(function(key) { + newObj[key] = walk(obj[key]); + }); + + return newObj; + }); + } + // should be safe to JSON.stringify() everything else + else { + result = o; + } + + return result; } /** - @param {any} object + * @param {*} object */ exports.dump = function(object) { - indentBy = 0; - output = ''; - - walk(object); - outdent(false); - return output; + return JSON.stringify(walk(object), null, 4); }; diff --git a/rhino/rhino-shim.js b/rhino/rhino-shim.js index fde081ee..16c126f6 100644 --- a/rhino/rhino-shim.js +++ b/rhino/rhino-shim.js @@ -55,30 +55,31 @@ clearInterval = null; * Emulate Node.js console functions. * @see http://nodejs.org/api/stdio.html */ -console = { - debug: function() { - // TODO - }, - error: function() { - // TODO - }, - log: function(/*...*/) { - // TODO: make this consistent with Node.js - var args = Array.prototype.slice.call(arguments, 0), - dumper = dumper || require('jsdoc/util/dumper'); - - for (var i = 0, len = args.length; i < len; i++) { - if (typeof args[i] !== 'string') { - args[i] = dumper.dump(args[i]); - } - } - - java.lang.System.out.println( args.join(' ') ); - }, - trace: function() { - // TODO +console = (function() { + function println(stream, args) { + java.lang.System[stream].println( require('util').format.apply(this, args) ); } -}; + + return { + error: function() { + println('err', arguments); + }, + info: function() { + println('out', arguments); + }, + log: function() { + println('out', arguments); + }, + trace: function(label) { + // this puts some extra junk at the top of the stack trace, but it's close enough + var e = new java.lang.Exception(label || 'Trace'); + e.printStackTrace(); + }, + warn: function() { + println('err', arguments); + } + }; +})(); /** * Emulate Node.js process functions. diff --git a/templates/haruki/publish.js b/templates/haruki/publish.js index d05db1c6..45c79876 100644 --- a/templates/haruki/publish.js +++ b/templates/haruki/publish.js @@ -210,7 +210,7 @@ exports.publish = function(data, opts) { console.log( xml('jsdoc', root) ); } else { - console.log(root); + dump(root); } } else { diff --git a/test/specs/jsdoc/util/dumper.js b/test/specs/jsdoc/util/dumper.js index ab9843eb..25e48141 100644 --- a/test/specs/jsdoc/util/dumper.js +++ b/test/specs/jsdoc/util/dumper.js @@ -1,3 +1,4 @@ +/*global describe: true, expect: true, it: true */ describe("common/dumper", function() { var common = {dumper: require('jsdoc/util/dumper')}; @@ -38,20 +39,21 @@ describe("common/dumper", function() { }); it("can dump undefined values", function() { - expect(common.dumper.dump(undefined)).toEqual('undefined'); + expect(common.dumper.dump(undefined)).toEqual('"undefined"'); }); it("can dump regex values", function() { - expect(common.dumper.dump(/^[Ff]oo$/gi)).toEqual(''); + expect(common.dumper.dump(/^[Ff]oo$/gi)).toEqual('""'); }); it("can dump date values", function() { - expect(common.dumper.dump(new Date('January 1, 1901 GMT'))).toEqual(''); + expect(common.dumper.dump(new Date('January 1, 1901 GMT'))) + .toEqual('""'); }); it("can dump function values", function() { - expect(common.dumper.dump(function myFunc(){})).toEqual(''); - expect(common.dumper.dump(function(){})).toEqual(''); + expect(common.dumper.dump(function myFunc(){})).toEqual('""'); + expect(common.dumper.dump(function(){})).toEqual('""'); }); it("can dump array values", function() { @@ -84,7 +86,7 @@ describe("common/dumper", function() { var actual = common.dumper.dump( [undefined, null, new Foo(), 1, true, 'hello\n"world', new Error('oops'), /foo/gi, new Date('December 26, 2010 GMT'), {f: function myFunc(){}, o: {a:1}}] ), - expected = '[\n undefined,\n null,\n {\n },\n 1,\n true,\n "hello\\n\\"world",\n {\n "message": "oops"\n },\n ,\n ,\n {\n "f": ,\n "o": {\n "a": 1\n }\n }\n]'; + expected = '[\n "undefined",\n null,\n {},\n 1,\n true,\n "hello\\n\\"world",\n {\n "message": "oops"\n },\n "",\n "",\n {\n "f": "",\n "o": {\n "a": 1\n }\n }\n]'; expect(actual).toEqual(expected); }); @@ -94,7 +96,7 @@ describe("common/dumper", function() { a.b = a; var actual = common.dumper.dump(a), - expected = '{\n "b": \n}'; + expected = '{\n "b": ""\n}'; expect(actual).toEqual(expected); });