| // Protocol Buffers - Google's data interchange format | 
 | // Copyright 2008 Google Inc.  All rights reserved. | 
 | // https://developers.google.com/protocol-buffers/ | 
 | // | 
 | // Redistribution and use in source and binary forms, with or without | 
 | // modification, are permitted provided that the following conditions are | 
 | // met: | 
 | // | 
 | //     * Redistributions of source code must retain the above copyright | 
 | // notice, this list of conditions and the following disclaimer. | 
 | //     * Redistributions in binary form must reproduce the above | 
 | // copyright notice, this list of conditions and the following disclaimer | 
 | // in the documentation and/or other materials provided with the | 
 | // distribution. | 
 | //     * Neither the name of Google Inc. nor the names of its | 
 | // contributors may be used to endorse or promote products derived from | 
 | // this software without specific prior written permission. | 
 | // | 
 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
 |  | 
 | /** | 
 |  * @fileoverview Utilities to debug JSPB based proto objects. | 
 |  */ | 
 |  | 
 | goog.provide('jspb.debug'); | 
 |  | 
 | goog.require('goog.array'); | 
 | goog.require('goog.asserts'); | 
 | goog.require('goog.object'); | 
 | goog.require('jspb.Message'); | 
 |  | 
 |  | 
 | /** | 
 |  * Turns a proto into a human readable object that can i.e. be written to the | 
 |  * console: {@code console.log(jspb.debug.dump(myProto))}. | 
 |  * This function makes a best effort and may not work in all cases. It will not | 
 |  * work in obfuscated and or optimized code. | 
 |  * Use this in environments where {@see jspb.Message.prototype.toObject} is | 
 |  * not available for code size reasons. | 
 |  * @param {jspb.Message} message A jspb.Message. | 
 |  * @return {Object} | 
 |  */ | 
 | jspb.debug.dump = function(message) { | 
 |   if (!goog.DEBUG) { | 
 |     return null; | 
 |   } | 
 |   goog.asserts.assert(message instanceof jspb.Message, | 
 |       'jspb.Message instance expected'); | 
 |   /** @type {Object} */ | 
 |   var object = message; | 
 |   goog.asserts.assert(object['getExtension'], | 
 |       'Only unobfuscated and unoptimized compilation modes supported.'); | 
 |   return /** @type {Object} */ (jspb.debug.dump_(message)); | 
 | }; | 
 |  | 
 |  | 
 | /** | 
 |  * Recursively introspects a message and the values its getters return to | 
 |  * make a best effort in creating a human readable representation of the | 
 |  * message. | 
 |  * @param {?} thing A jspb.Message, Array or primitive type to dump. | 
 |  * @return {*} | 
 |  * @private | 
 |  */ | 
 | jspb.debug.dump_ = function(thing) { | 
 |   var type = goog.typeOf(thing); | 
 |   if (type == 'number' || type == 'string' || type == 'boolean' || | 
 |       type == 'null' || type == 'undefined') { | 
 |     return thing; | 
 |   } | 
 |   if (type == 'array') { | 
 |     goog.asserts.assertArray(thing); | 
 |     return goog.array.map(thing, jspb.debug.dump_); | 
 |   } | 
 |   var message = thing;  // Copy because we don't want type inference on thing. | 
 |   goog.asserts.assert(message instanceof jspb.Message, | 
 |       'Only messages expected: ' + thing); | 
 |   var ctor = message.constructor; | 
 |   var messageName = ctor.name || ctor.displayName; | 
 |   var object = { | 
 |     '$name': messageName | 
 |   }; | 
 |   for (var name in ctor.prototype) { | 
 |     var match = /^get([A-Z]\w*)/.exec(name); | 
 |     if (match && name != 'getExtension' && | 
 |         name != 'getJsPbMessageId') { | 
 |       var has = 'has' + match[1]; | 
 |       if (!thing[has] || thing[has]()) { | 
 |         var val = thing[name](); | 
 |         object[jspb.debug.formatFieldName_(match[1])] = jspb.debug.dump_(val); | 
 |       } | 
 |     } | 
 |   } | 
 |   if (COMPILED && thing['extensionObject_']) { | 
 |     object['$extensions'] = 'Recursive dumping of extensions not supported ' + | 
 |         'in compiled code. Switch to uncompiled or dump extension object ' + | 
 |         'directly'; | 
 |     return object; | 
 |   } | 
 |   var extensionsObject; | 
 |   for (var id in ctor['extensions']) { | 
 |     if (/^\d+$/.test(id)) { | 
 |       var ext = ctor['extensions'][id]; | 
 |       var extVal = thing.getExtension(ext); | 
 |       var fieldName = goog.object.getKeys(ext.fieldName)[0]; | 
 |       if (extVal != null) { | 
 |         if (!extensionsObject) { | 
 |           extensionsObject = object['$extensions'] = {}; | 
 |         } | 
 |         extensionsObject[jspb.debug.formatFieldName_(fieldName)] = | 
 |             jspb.debug.dump_(extVal); | 
 |       } | 
 |     } | 
 |   } | 
 |   return object; | 
 | }; | 
 |  | 
 |  | 
 | /** | 
 |  * Formats a field name for output as camelCase. | 
 |  * | 
 |  * @param {string} name Name of the field. | 
 |  * @return {string} | 
 |  * @private | 
 |  */ | 
 | jspb.debug.formatFieldName_ = function(name) { | 
 |   // Name may be in TitleCase. | 
 |   return name.replace(/^[A-Z]/, function(c) { | 
 |     return c.toLowerCase(); | 
 |   }); | 
 | }; |