l0bsterssg

node.js static responsive blog post generator
Log | Files | Refs | README

util.js (15563B)


      1 // Copyright Joyent, Inc. and other Node contributors.
      2 //
      3 // Permission is hereby granted, free of charge, to any person obtaining a
      4 // copy of this software and associated documentation files (the
      5 // "Software"), to deal in the Software without restriction, including
      6 // without limitation the rights to use, copy, modify, merge, publish,
      7 // distribute, sublicense, and/or sell copies of the Software, and to permit
      8 // persons to whom the Software is furnished to do so, subject to the
      9 // following conditions:
     10 //
     11 // The above copyright notice and this permission notice shall be included
     12 // in all copies or substantial portions of the Software.
     13 //
     14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
     17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
     18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
     19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
     20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
     21 
     22 var formatRegExp = /%[sdj%]/g;
     23 exports.format = function(f) {
     24   if (!isString(f)) {
     25     var objects = [];
     26     for (var i = 0; i < arguments.length; i++) {
     27       objects.push(inspect(arguments[i]));
     28     }
     29     return objects.join(' ');
     30   }
     31 
     32   var i = 1;
     33   var args = arguments;
     34   var len = args.length;
     35   var str = String(f).replace(formatRegExp, function(x) {
     36     if (x === '%%') return '%';
     37     if (i >= len) return x;
     38     switch (x) {
     39       case '%s': return String(args[i++]);
     40       case '%d': return Number(args[i++]);
     41       case '%j':
     42         try {
     43           return JSON.stringify(args[i++]);
     44         } catch (_) {
     45           return '[Circular]';
     46         }
     47       default:
     48         return x;
     49     }
     50   });
     51   for (var x = args[i]; i < len; x = args[++i]) {
     52     if (isNull(x) || !isObject(x)) {
     53       str += ' ' + x;
     54     } else {
     55       str += ' ' + inspect(x);
     56     }
     57   }
     58   return str;
     59 };
     60 
     61 
     62 // Mark that a method should not be used.
     63 // Returns a modified function which warns once by default.
     64 // If --no-deprecation is set, then it is a no-op.
     65 exports.deprecate = function(fn, msg) {
     66   // Allow for deprecating things in the process of starting up.
     67   if (isUndefined(global.process)) {
     68     return function() {
     69       return exports.deprecate(fn, msg).apply(this, arguments);
     70     };
     71   }
     72 
     73   if (process.noDeprecation === true) {
     74     return fn;
     75   }
     76 
     77   var warned = false;
     78   function deprecated() {
     79     if (!warned) {
     80       if (process.throwDeprecation) {
     81         throw new Error(msg);
     82       } else if (process.traceDeprecation) {
     83         console.trace(msg);
     84       } else {
     85         console.error(msg);
     86       }
     87       warned = true;
     88     }
     89     return fn.apply(this, arguments);
     90   }
     91 
     92   return deprecated;
     93 };
     94 
     95 
     96 var debugs = {};
     97 var debugEnviron;
     98 exports.debuglog = function(set) {
     99   if (isUndefined(debugEnviron))
    100     debugEnviron = process.env.NODE_DEBUG || '';
    101   set = set.toUpperCase();
    102   if (!debugs[set]) {
    103     if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) {
    104       var pid = process.pid;
    105       debugs[set] = function() {
    106         var msg = exports.format.apply(exports, arguments);
    107         console.error('%s %d: %s', set, pid, msg);
    108       };
    109     } else {
    110       debugs[set] = function() {};
    111     }
    112   }
    113   return debugs[set];
    114 };
    115 
    116 
    117 /**
    118  * Echos the value of a value. Trys to print the value out
    119  * in the best way possible given the different types.
    120  *
    121  * @param {Object} obj The object to print out.
    122  * @param {Object} opts Optional options object that alters the output.
    123  */
    124 /* legacy: obj, showHidden, depth, colors*/
    125 function inspect(obj, opts) {
    126   // default options
    127   var ctx = {
    128     seen: [],
    129     stylize: stylizeNoColor
    130   };
    131   // legacy...
    132   if (arguments.length >= 3) ctx.depth = arguments[2];
    133   if (arguments.length >= 4) ctx.colors = arguments[3];
    134   if (isBoolean(opts)) {
    135     // legacy...
    136     ctx.showHidden = opts;
    137   } else if (opts) {
    138     // got an "options" object
    139     exports._extend(ctx, opts);
    140   }
    141   // set default options
    142   if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
    143   if (isUndefined(ctx.depth)) ctx.depth = 2;
    144   if (isUndefined(ctx.colors)) ctx.colors = false;
    145   if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
    146   if (ctx.colors) ctx.stylize = stylizeWithColor;
    147   return formatValue(ctx, obj, ctx.depth);
    148 }
    149 exports.inspect = inspect;
    150 
    151 
    152 // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
    153 inspect.colors = {
    154   'bold' : [1, 22],
    155   'italic' : [3, 23],
    156   'underline' : [4, 24],
    157   'inverse' : [7, 27],
    158   'white' : [37, 39],
    159   'grey' : [90, 39],
    160   'black' : [30, 39],
    161   'blue' : [34, 39],
    162   'cyan' : [36, 39],
    163   'green' : [32, 39],
    164   'magenta' : [35, 39],
    165   'red' : [31, 39],
    166   'yellow' : [33, 39]
    167 };
    168 
    169 // Don't use 'blue' not visible on cmd.exe
    170 inspect.styles = {
    171   'special': 'cyan',
    172   'number': 'yellow',
    173   'boolean': 'yellow',
    174   'undefined': 'grey',
    175   'null': 'bold',
    176   'string': 'green',
    177   'date': 'magenta',
    178   // "name": intentionally not styling
    179   'regexp': 'red'
    180 };
    181 
    182 
    183 function stylizeWithColor(str, styleType) {
    184   var style = inspect.styles[styleType];
    185 
    186   if (style) {
    187     return '\u001b[' + inspect.colors[style][0] + 'm' + str +
    188            '\u001b[' + inspect.colors[style][1] + 'm';
    189   } else {
    190     return str;
    191   }
    192 }
    193 
    194 
    195 function stylizeNoColor(str, styleType) {
    196   return str;
    197 }
    198 
    199 
    200 function arrayToHash(array) {
    201   var hash = {};
    202 
    203   array.forEach(function(val, idx) {
    204     hash[val] = true;
    205   });
    206 
    207   return hash;
    208 }
    209 
    210 
    211 function formatValue(ctx, value, recurseTimes) {
    212   // Provide a hook for user-specified inspect functions.
    213   // Check that value is an object with an inspect function on it
    214   if (ctx.customInspect &&
    215       value &&
    216       isFunction(value.inspect) &&
    217       // Filter out the util module, it's inspect function is special
    218       value.inspect !== exports.inspect &&
    219       // Also filter out any prototype objects using the circular check.
    220       !(value.constructor && value.constructor.prototype === value)) {
    221     var ret = value.inspect(recurseTimes, ctx);
    222     if (!isString(ret)) {
    223       ret = formatValue(ctx, ret, recurseTimes);
    224     }
    225     return ret;
    226   }
    227 
    228   // Primitive types cannot have properties
    229   var primitive = formatPrimitive(ctx, value);
    230   if (primitive) {
    231     return primitive;
    232   }
    233 
    234   // Look up the keys of the object.
    235   var keys = Object.keys(value);
    236   var visibleKeys = arrayToHash(keys);
    237 
    238   if (ctx.showHidden) {
    239     keys = Object.getOwnPropertyNames(value);
    240   }
    241 
    242   // IE doesn't make error fields non-enumerable
    243   // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx
    244   if (isError(value)
    245       && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) {
    246     return formatError(value);
    247   }
    248 
    249   // Some type of object without properties can be shortcutted.
    250   if (keys.length === 0) {
    251     if (isFunction(value)) {
    252       var name = value.name ? ': ' + value.name : '';
    253       return ctx.stylize('[Function' + name + ']', 'special');
    254     }
    255     if (isRegExp(value)) {
    256       return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
    257     }
    258     if (isDate(value)) {
    259       return ctx.stylize(Date.prototype.toString.call(value), 'date');
    260     }
    261     if (isError(value)) {
    262       return formatError(value);
    263     }
    264   }
    265 
    266   var base = '', array = false, braces = ['{', '}'];
    267 
    268   // Make Array say that they are Array
    269   if (isArray(value)) {
    270     array = true;
    271     braces = ['[', ']'];
    272   }
    273 
    274   // Make functions say that they are functions
    275   if (isFunction(value)) {
    276     var n = value.name ? ': ' + value.name : '';
    277     base = ' [Function' + n + ']';
    278   }
    279 
    280   // Make RegExps say that they are RegExps
    281   if (isRegExp(value)) {
    282     base = ' ' + RegExp.prototype.toString.call(value);
    283   }
    284 
    285   // Make dates with properties first say the date
    286   if (isDate(value)) {
    287     base = ' ' + Date.prototype.toUTCString.call(value);
    288   }
    289 
    290   // Make error with message first say the error
    291   if (isError(value)) {
    292     base = ' ' + formatError(value);
    293   }
    294 
    295   if (keys.length === 0 && (!array || value.length == 0)) {
    296     return braces[0] + base + braces[1];
    297   }
    298 
    299   if (recurseTimes < 0) {
    300     if (isRegExp(value)) {
    301       return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
    302     } else {
    303       return ctx.stylize('[Object]', 'special');
    304     }
    305   }
    306 
    307   ctx.seen.push(value);
    308 
    309   var output;
    310   if (array) {
    311     output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
    312   } else {
    313     output = keys.map(function(key) {
    314       return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
    315     });
    316   }
    317 
    318   ctx.seen.pop();
    319 
    320   return reduceToSingleString(output, base, braces);
    321 }
    322 
    323 
    324 function formatPrimitive(ctx, value) {
    325   if (isUndefined(value))
    326     return ctx.stylize('undefined', 'undefined');
    327   if (isString(value)) {
    328     var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
    329                                              .replace(/'/g, "\\'")
    330                                              .replace(/\\"/g, '"') + '\'';
    331     return ctx.stylize(simple, 'string');
    332   }
    333   if (isNumber(value))
    334     return ctx.stylize('' + value, 'number');
    335   if (isBoolean(value))
    336     return ctx.stylize('' + value, 'boolean');
    337   // For some reason typeof null is "object", so special case here.
    338   if (isNull(value))
    339     return ctx.stylize('null', 'null');
    340 }
    341 
    342 
    343 function formatError(value) {
    344   return '[' + Error.prototype.toString.call(value) + ']';
    345 }
    346 
    347 
    348 function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
    349   var output = [];
    350   for (var i = 0, l = value.length; i < l; ++i) {
    351     if (hasOwnProperty(value, String(i))) {
    352       output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
    353           String(i), true));
    354     } else {
    355       output.push('');
    356     }
    357   }
    358   keys.forEach(function(key) {
    359     if (!key.match(/^\d+$/)) {
    360       output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
    361           key, true));
    362     }
    363   });
    364   return output;
    365 }
    366 
    367 
    368 function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
    369   var name, str, desc;
    370   desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };
    371   if (desc.get) {
    372     if (desc.set) {
    373       str = ctx.stylize('[Getter/Setter]', 'special');
    374     } else {
    375       str = ctx.stylize('[Getter]', 'special');
    376     }
    377   } else {
    378     if (desc.set) {
    379       str = ctx.stylize('[Setter]', 'special');
    380     }
    381   }
    382   if (!hasOwnProperty(visibleKeys, key)) {
    383     name = '[' + key + ']';
    384   }
    385   if (!str) {
    386     if (ctx.seen.indexOf(desc.value) < 0) {
    387       if (isNull(recurseTimes)) {
    388         str = formatValue(ctx, desc.value, null);
    389       } else {
    390         str = formatValue(ctx, desc.value, recurseTimes - 1);
    391       }
    392       if (str.indexOf('\n') > -1) {
    393         if (array) {
    394           str = str.split('\n').map(function(line) {
    395             return '  ' + line;
    396           }).join('\n').substr(2);
    397         } else {
    398           str = '\n' + str.split('\n').map(function(line) {
    399             return '   ' + line;
    400           }).join('\n');
    401         }
    402       }
    403     } else {
    404       str = ctx.stylize('[Circular]', 'special');
    405     }
    406   }
    407   if (isUndefined(name)) {
    408     if (array && key.match(/^\d+$/)) {
    409       return str;
    410     }
    411     name = JSON.stringify('' + key);
    412     if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
    413       name = name.substr(1, name.length - 2);
    414       name = ctx.stylize(name, 'name');
    415     } else {
    416       name = name.replace(/'/g, "\\'")
    417                  .replace(/\\"/g, '"')
    418                  .replace(/(^"|"$)/g, "'");
    419       name = ctx.stylize(name, 'string');
    420     }
    421   }
    422 
    423   return name + ': ' + str;
    424 }
    425 
    426 
    427 function reduceToSingleString(output, base, braces) {
    428   var numLinesEst = 0;
    429   var length = output.reduce(function(prev, cur) {
    430     numLinesEst++;
    431     if (cur.indexOf('\n') >= 0) numLinesEst++;
    432     return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
    433   }, 0);
    434 
    435   if (length > 60) {
    436     return braces[0] +
    437            (base === '' ? '' : base + '\n ') +
    438            ' ' +
    439            output.join(',\n  ') +
    440            ' ' +
    441            braces[1];
    442   }
    443 
    444   return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
    445 }
    446 
    447 
    448 // NOTE: These type checking functions intentionally don't use `instanceof`
    449 // because it is fragile and can be easily faked with `Object.create()`.
    450 function isArray(ar) {
    451   return Array.isArray(ar);
    452 }
    453 exports.isArray = isArray;
    454 
    455 function isBoolean(arg) {
    456   return typeof arg === 'boolean';
    457 }
    458 exports.isBoolean = isBoolean;
    459 
    460 function isNull(arg) {
    461   return arg === null;
    462 }
    463 exports.isNull = isNull;
    464 
    465 function isNullOrUndefined(arg) {
    466   return arg == null;
    467 }
    468 exports.isNullOrUndefined = isNullOrUndefined;
    469 
    470 function isNumber(arg) {
    471   return typeof arg === 'number';
    472 }
    473 exports.isNumber = isNumber;
    474 
    475 function isString(arg) {
    476   return typeof arg === 'string';
    477 }
    478 exports.isString = isString;
    479 
    480 function isSymbol(arg) {
    481   return typeof arg === 'symbol';
    482 }
    483 exports.isSymbol = isSymbol;
    484 
    485 function isUndefined(arg) {
    486   return arg === void 0;
    487 }
    488 exports.isUndefined = isUndefined;
    489 
    490 function isRegExp(re) {
    491   return isObject(re) && objectToString(re) === '[object RegExp]';
    492 }
    493 exports.isRegExp = isRegExp;
    494 
    495 function isObject(arg) {
    496   return typeof arg === 'object' && arg !== null;
    497 }
    498 exports.isObject = isObject;
    499 
    500 function isDate(d) {
    501   return isObject(d) && objectToString(d) === '[object Date]';
    502 }
    503 exports.isDate = isDate;
    504 
    505 function isError(e) {
    506   return isObject(e) &&
    507       (objectToString(e) === '[object Error]' || e instanceof Error);
    508 }
    509 exports.isError = isError;
    510 
    511 function isFunction(arg) {
    512   return typeof arg === 'function';
    513 }
    514 exports.isFunction = isFunction;
    515 
    516 function isPrimitive(arg) {
    517   return arg === null ||
    518          typeof arg === 'boolean' ||
    519          typeof arg === 'number' ||
    520          typeof arg === 'string' ||
    521          typeof arg === 'symbol' ||  // ES6 symbol
    522          typeof arg === 'undefined';
    523 }
    524 exports.isPrimitive = isPrimitive;
    525 
    526 exports.isBuffer = require('./support/isBuffer');
    527 
    528 function objectToString(o) {
    529   return Object.prototype.toString.call(o);
    530 }
    531 
    532 
    533 function pad(n) {
    534   return n < 10 ? '0' + n.toString(10) : n.toString(10);
    535 }
    536 
    537 
    538 var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
    539               'Oct', 'Nov', 'Dec'];
    540 
    541 // 26 Feb 16:19:34
    542 function timestamp() {
    543   var d = new Date();
    544   var time = [pad(d.getHours()),
    545               pad(d.getMinutes()),
    546               pad(d.getSeconds())].join(':');
    547   return [d.getDate(), months[d.getMonth()], time].join(' ');
    548 }
    549 
    550 
    551 // log is just a thin wrapper to console.log that prepends a timestamp
    552 exports.log = function() {
    553   console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments));
    554 };
    555 
    556 
    557 /**
    558  * Inherit the prototype methods from one constructor into another.
    559  *
    560  * The Function.prototype.inherits from lang.js rewritten as a standalone
    561  * function (not on Function.prototype). NOTE: If this file is to be loaded
    562  * during bootstrapping this function needs to be rewritten using some native
    563  * functions as prototype setup using normal JavaScript does not work as
    564  * expected during bootstrapping (see mirror.js in r114903).
    565  *
    566  * @param {function} ctor Constructor function which needs to inherit the
    567  *     prototype.
    568  * @param {function} superCtor Constructor function to inherit prototype from.
    569  */
    570 exports.inherits = require('inherits');
    571 
    572 exports._extend = function(origin, add) {
    573   // Don't do anything if add isn't an object
    574   if (!add || !isObject(add)) return origin;
    575 
    576   var keys = Object.keys(add);
    577   var i = keys.length;
    578   while (i--) {
    579     origin[keys[i]] = add[keys[i]];
    580   }
    581   return origin;
    582 };
    583 
    584 function hasOwnProperty(obj, prop) {
    585   return Object.prototype.hasOwnProperty.call(obj, prop);
    586 }