Source: index.js

// Copyright (c) 2014 Quildreen Motta
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation files
// (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

/**
 * Displays a human-readable representation of built-in and custom objects
 *
 * @module lib/index
 */

// -- Helpers ----------------------------------------------------------

/**
 * True if the value has a .toString method that returns a custom repr.
 *
 * @method
 * @private
 * @summary Any → Boolean
 */
function isCustom(a) {
  var repr = a && a.toString()
  return a && !Array.isArray(a) && repr !== '[object Object]';
}

/**
 * Returns the [[Class]] of an object.
 *
 * @method
 * @private
 * @summary Any → String
 */
function classOf(a) {
  return Object.prototype.toString.call(a).slice(8, -1)
}

/**
 * True if an object is a String
 * 
 * @method
 * @private
 * @summary Any → Boolean
 */
function isString(a) {
  return classOf(a) === 'String'
}

/**
 * Returns a list of key/value pairs.
 *
 * @method
 * @private
 * @summary { String → * } → [(String, *)]
 */
function pairs(object) {
  return Object.keys(object).map(function(key){
    return { key: key, value: object[key] }
  })
}

/**
 * Displays the representation of a number.
 *
 * @method
 * @private
 * @summary Number → String
 */
function showNumber(a) {
  return Number(a).toString();
}

/**
 * Displays the representation of a boolean.
 *
 * @method
 * @private
 * @summary Boolean → String
 */
function showBoolean(a) {
  return Boolean(a).toString();
}

/**
 * Displays the representation of a string.
 *
 * @method
 * @private
 * @summary String → String
 */
function showString(a) {
  return JSON.stringify(String(a));
}

/**
 * Displays the representation of an array.
 *
 * @method
 * @private
 * @summary Number → [α] → String
 */
function showArray(maxDepth, array) {
  return '['
        + array.map(function(a) {
            return show(maxDepth - 1, a)
          }).join(', ')
        + ']';
}

/**
 * Displays the representation of an object.
 *
 * @method
 * @private
 * @summary Number → { String → * } → String
 */
function showObject(maxDepth, object) {
  return '{'
       + pairs(object).map(function(pair){
           return showString(pair.key) + ': ' + show(maxDepth - 1, pair.value)
         }).join(', ')
       + '}'
}

// -- Public interface -------------------------------------------------

/**
 * Displays the representation of anything.
 *
 * @method
 * @static
 * @summary Number → Any → String
 */
function show(maxDepth, value) {
  return value === undefined?   'undefined'
  :      value === null?        'null'
  :      isString(value)?       showString(value)
  :      isCustom(value)?       value.toString()
  :      maxDepth <= 0?         '(...)'
  :      Array.isArray(value)?  showArray(maxDepth, value)
  :      /* otherwise */        showObject(maxDepth, value)
}


module.exports = exports = function(a){ return show(5, a) };
exports.show = show;