a04c19c7353fdf3459c89369d726c00d2c7a1fe4
[platform/upstream/nodejs.git] / lib / util.js
1 'use strict';
2
3 const uv = process.binding('uv');
4
5 const formatRegExp = /%[sdj%]/g;
6 exports.format = function(f) {
7   if (typeof f !== 'string') {
8     var objects = [];
9     for (var i = 0; i < arguments.length; i++) {
10       objects.push(inspect(arguments[i]));
11     }
12     return objects.join(' ');
13   }
14
15   var i = 1;
16   var args = arguments;
17   var len = args.length;
18   var str = String(f).replace(formatRegExp, function(x) {
19     if (x === '%%') return '%';
20     if (i >= len) return x;
21     switch (x) {
22       case '%s': return String(args[i++]);
23       case '%d': return Number(args[i++]);
24       case '%j':
25         try {
26           return JSON.stringify(args[i++]);
27         } catch (_) {
28           return '[Circular]';
29         }
30       default:
31         return x;
32     }
33   });
34   for (var x = args[i]; i < len; x = args[++i]) {
35     if (x === null || (typeof x !== 'object' && typeof x !== 'symbol')) {
36       str += ' ' + x;
37     } else {
38       str += ' ' + inspect(x);
39     }
40   }
41   return str;
42 };
43
44
45 // Mark that a method should not be used.
46 // Returns a modified function which warns once by default.
47 // If --no-deprecation is set, then it is a no-op.
48 exports.deprecate = function(fn, msg) {
49   // Allow for deprecating things in the process of starting up.
50   if (global.process === undefined) {
51     return function() {
52       return exports.deprecate(fn, msg).apply(this, arguments);
53     };
54   }
55
56   if (process.noDeprecation === true) {
57     return fn;
58   }
59
60   var warned = false;
61   function deprecated() {
62     if (!warned) {
63       if (process.throwDeprecation) {
64         throw new Error(msg);
65       } else if (process.traceDeprecation) {
66         console.trace(msg);
67       } else {
68         console.error(msg);
69       }
70       warned = true;
71     }
72     return fn.apply(this, arguments);
73   }
74
75   return deprecated;
76 };
77
78
79 var debugs = {};
80 var debugEnviron;
81 exports.debuglog = function(set) {
82   if (debugEnviron === undefined)
83     debugEnviron = process.env.NODE_DEBUG || '';
84   set = set.toUpperCase();
85   if (!debugs[set]) {
86     if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) {
87       var pid = process.pid;
88       debugs[set] = function() {
89         var msg = exports.format.apply(exports, arguments);
90         console.error('%s %d: %s', set, pid, msg);
91       };
92     } else {
93       debugs[set] = function() {};
94     }
95   }
96   return debugs[set];
97 };
98
99
100 /**
101  * Echos the value of a value. Trys to print the value out
102  * in the best way possible given the different types.
103  *
104  * @param {Object} obj The object to print out.
105  * @param {Object} opts Optional options object that alters the output.
106  */
107 /* legacy: obj, showHidden, depth, colors*/
108 function inspect(obj, opts) {
109   // default options
110   var ctx = {
111     seen: [],
112     stylize: stylizeNoColor
113   };
114   // legacy...
115   if (arguments.length >= 3) ctx.depth = arguments[2];
116   if (arguments.length >= 4) ctx.colors = arguments[3];
117   if (typeof opts === 'boolean') {
118     // legacy...
119     ctx.showHidden = opts;
120   } else if (opts) {
121     // got an "options" object
122     exports._extend(ctx, opts);
123   }
124   // set default options
125   if (ctx.showHidden === undefined) ctx.showHidden = false;
126   if (ctx.depth === undefined) ctx.depth = 2;
127   if (ctx.colors === undefined) ctx.colors = false;
128   if (ctx.customInspect === undefined) ctx.customInspect = true;
129   if (ctx.colors) ctx.stylize = stylizeWithColor;
130   return formatValue(ctx, obj, ctx.depth);
131 }
132 exports.inspect = inspect;
133
134
135 // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
136 inspect.colors = {
137   'bold' : [1, 22],
138   'italic' : [3, 23],
139   'underline' : [4, 24],
140   'inverse' : [7, 27],
141   'white' : [37, 39],
142   'grey' : [90, 39],
143   'black' : [30, 39],
144   'blue' : [34, 39],
145   'cyan' : [36, 39],
146   'green' : [32, 39],
147   'magenta' : [35, 39],
148   'red' : [31, 39],
149   'yellow' : [33, 39]
150 };
151
152 // Don't use 'blue' not visible on cmd.exe
153 inspect.styles = {
154   'special': 'cyan',
155   'number': 'yellow',
156   'boolean': 'yellow',
157   'undefined': 'grey',
158   'null': 'bold',
159   'string': 'green',
160   'symbol': 'green',
161   'date': 'magenta',
162   // "name": intentionally not styling
163   'regexp': 'red'
164 };
165
166
167 function stylizeWithColor(str, styleType) {
168   var style = inspect.styles[styleType];
169
170   if (style) {
171     return '\u001b[' + inspect.colors[style][0] + 'm' + str +
172            '\u001b[' + inspect.colors[style][1] + 'm';
173   } else {
174     return str;
175   }
176 }
177
178
179 function stylizeNoColor(str, styleType) {
180   return str;
181 }
182
183
184 function arrayToHash(array) {
185   var hash = {};
186
187   array.forEach(function(val, idx) {
188     hash[val] = true;
189   });
190
191   return hash;
192 }
193
194
195 function formatValue(ctx, value, recurseTimes) {
196   // Provide a hook for user-specified inspect functions.
197   // Check that value is an object with an inspect function on it
198   if (ctx.customInspect &&
199       value &&
200       typeof value.inspect === 'function' &&
201       // Filter out the util module, it's inspect function is special
202       value.inspect !== exports.inspect &&
203       // Also filter out any prototype objects using the circular check.
204       !(value.constructor && value.constructor.prototype === value)) {
205     var ret = value.inspect(recurseTimes, ctx);
206     if (typeof ret !== 'string') {
207       ret = formatValue(ctx, ret, recurseTimes);
208     }
209     return ret;
210   }
211
212   // Primitive types cannot have properties
213   var primitive = formatPrimitive(ctx, value);
214   if (primitive) {
215     return primitive;
216   }
217
218   // Look up the keys of the object.
219   var keys = Object.keys(value);
220   var visibleKeys = arrayToHash(keys);
221
222   if (ctx.showHidden) {
223     keys = Object.getOwnPropertyNames(value);
224     keys = keys.concat(Object.getOwnPropertySymbols(value));
225   }
226
227   // This could be a boxed primitive (new String(), etc.), check valueOf()
228   // NOTE: Avoid calling `valueOf` on `Date` instance because it will return
229   // a number which, when object has some additional user-stored `keys`,
230   // will be printed out.
231   var formatted;
232   var raw = value;
233   try {
234     // the .valueOf() call can fail for a multitude of reasons
235     if (!isDate(value))
236       raw = value.valueOf();
237   } catch (e) {
238     // ignore...
239   }
240
241   if (typeof raw === 'string') {
242     // for boxed Strings, we have to remove the 0-n indexed entries,
243     // since they just noisey up the output and are redundant
244     keys = keys.filter(function(key) {
245       return !(key >= 0 && key < raw.length);
246     });
247   }
248
249   // Some type of object without properties can be shortcutted.
250   if (keys.length === 0) {
251     if (typeof value === 'function') {
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     // now check the `raw` value to handle boxed primitives
265     if (typeof raw === 'string') {
266       formatted = formatPrimitiveNoColor(ctx, raw);
267       return ctx.stylize('[String: ' + formatted + ']', 'string');
268     }
269     if (typeof raw === 'number') {
270       formatted = formatPrimitiveNoColor(ctx, raw);
271       return ctx.stylize('[Number: ' + formatted + ']', 'number');
272     }
273     if (typeof raw === 'boolean') {
274       formatted = formatPrimitiveNoColor(ctx, raw);
275       return ctx.stylize('[Boolean: ' + formatted + ']', 'boolean');
276     }
277   }
278
279   var base = '', array = false, braces = ['{', '}'];
280
281   // Make Array say that they are Array
282   if (Array.isArray(value)) {
283     array = true;
284     braces = ['[', ']'];
285   }
286
287   // Make functions say that they are functions
288   if (typeof value === 'function') {
289     var n = value.name ? ': ' + value.name : '';
290     base = ' [Function' + n + ']';
291   }
292
293   // Make RegExps say that they are RegExps
294   if (isRegExp(value)) {
295     base = ' ' + RegExp.prototype.toString.call(value);
296   }
297
298   // Make dates with properties first say the date
299   if (isDate(value)) {
300     base = ' ' + Date.prototype.toUTCString.call(value);
301   }
302
303   // Make error with message first say the error
304   if (isError(value)) {
305     base = ' ' + formatError(value);
306   }
307
308   // Make boxed primitive Strings look like such
309   if (typeof raw === 'string') {
310     formatted = formatPrimitiveNoColor(ctx, raw);
311     base = ' ' + '[String: ' + formatted + ']';
312   }
313
314   // Make boxed primitive Numbers look like such
315   if (typeof raw === 'number') {
316     formatted = formatPrimitiveNoColor(ctx, raw);
317     base = ' ' + '[Number: ' + formatted + ']';
318   }
319
320   // Make boxed primitive Booleans look like such
321   if (typeof raw === 'boolean') {
322     formatted = formatPrimitiveNoColor(ctx, raw);
323     base = ' ' + '[Boolean: ' + formatted + ']';
324   }
325
326   if (keys.length === 0 && (!array || value.length === 0)) {
327     return braces[0] + base + braces[1];
328   }
329
330   if (recurseTimes < 0) {
331     if (isRegExp(value)) {
332       return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
333     } else {
334       return ctx.stylize('[Object]', 'special');
335     }
336   }
337
338   ctx.seen.push(value);
339
340   var output;
341   if (array) {
342     output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
343   } else {
344     output = keys.map(function(key) {
345       return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
346     });
347   }
348
349   ctx.seen.pop();
350
351   return reduceToSingleString(output, base, braces);
352 }
353
354
355 function formatPrimitive(ctx, value) {
356   if (value === undefined)
357     return ctx.stylize('undefined', 'undefined');
358
359   // For some reason typeof null is "object", so special case here.
360   if (value === null)
361     return ctx.stylize('null', 'null');
362
363   var type = typeof value;
364
365   if (type === 'string') {
366     var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
367         .replace(/'/g, "\\'")
368         .replace(/\\"/g, '"') + '\'';
369     return ctx.stylize(simple, 'string');
370   }
371   if (type === 'number') {
372     // Format -0 as '-0'. Strict equality won't distinguish 0 from -0,
373     // so instead we use the fact that 1 / -0 < 0 whereas 1 / 0 > 0 .
374     if (value === 0 && 1 / value < 0)
375       return ctx.stylize('-0', 'number');
376     return ctx.stylize('' + value, 'number');
377   }
378   if (type === 'boolean')
379     return ctx.stylize('' + value, 'boolean');
380   // es6 symbol primitive
381   if (type === 'symbol')
382     return ctx.stylize(value.toString(), 'symbol');
383 }
384
385
386 function formatPrimitiveNoColor(ctx, value) {
387   var stylize = ctx.stylize;
388   ctx.stylize = stylizeNoColor;
389   var str = formatPrimitive(ctx, value);
390   ctx.stylize = stylize;
391   return str;
392 }
393
394
395 function formatError(value) {
396   return '[' + Error.prototype.toString.call(value) + ']';
397 }
398
399
400 function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
401   var output = [];
402   for (var i = 0, l = value.length; i < l; ++i) {
403     if (hasOwnProperty(value, String(i))) {
404       output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
405           String(i), true));
406     } else {
407       output.push('');
408     }
409   }
410   keys.forEach(function(key) {
411     if (typeof key === 'symbol' || !key.match(/^\d+$/)) {
412       output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
413           key, true));
414     }
415   });
416   return output;
417 }
418
419
420 function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
421   var name, str, desc;
422   desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };
423   if (desc.get) {
424     if (desc.set) {
425       str = ctx.stylize('[Getter/Setter]', 'special');
426     } else {
427       str = ctx.stylize('[Getter]', 'special');
428     }
429   } else {
430     if (desc.set) {
431       str = ctx.stylize('[Setter]', 'special');
432     }
433   }
434   if (!hasOwnProperty(visibleKeys, key)) {
435     if (typeof key === 'symbol') {
436       name = '[' + ctx.stylize(key.toString(), 'symbol') + ']';
437     } else {
438       name = '[' + key + ']';
439     }
440   }
441   if (!str) {
442     if (ctx.seen.indexOf(desc.value) < 0) {
443       if (recurseTimes === null) {
444         str = formatValue(ctx, desc.value, null);
445       } else {
446         str = formatValue(ctx, desc.value, recurseTimes - 1);
447       }
448       if (str.indexOf('\n') > -1) {
449         if (array) {
450           str = str.split('\n').map(function(line) {
451             return '  ' + line;
452           }).join('\n').substr(2);
453         } else {
454           str = '\n' + str.split('\n').map(function(line) {
455             return '   ' + line;
456           }).join('\n');
457         }
458       }
459     } else {
460       str = ctx.stylize('[Circular]', 'special');
461     }
462   }
463   if (name === undefined) {
464     if (array && key.match(/^\d+$/)) {
465       return str;
466     }
467     name = JSON.stringify('' + key);
468     if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
469       name = name.substr(1, name.length - 2);
470       name = ctx.stylize(name, 'name');
471     } else {
472       name = name.replace(/'/g, "\\'")
473                  .replace(/\\"/g, '"')
474                  .replace(/(^"|"$)/g, "'")
475                  .replace(/\\\\/g, '\\');
476       name = ctx.stylize(name, 'string');
477     }
478   }
479
480   return name + ': ' + str;
481 }
482
483
484 function reduceToSingleString(output, base, braces) {
485   var length = output.reduce(function(prev, cur) {
486     return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
487   }, 0);
488
489   if (length > 60) {
490     return braces[0] +
491            (base === '' ? '' : base + '\n ') +
492            ' ' +
493            output.join(',\n  ') +
494            ' ' +
495            braces[1];
496   }
497
498   return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
499 }
500
501
502 // NOTE: These type checking functions intentionally don't use `instanceof`
503 // because it is fragile and can be easily faked with `Object.create()`.
504 exports.isArray = Array.isArray;
505
506 function isBoolean(arg) {
507   return typeof arg === 'boolean';
508 }
509 exports.isBoolean = isBoolean;
510
511 function isNull(arg) {
512   return arg === null;
513 }
514 exports.isNull = isNull;
515
516 function isNullOrUndefined(arg) {
517   return arg === null || arg === undefined;
518 }
519 exports.isNullOrUndefined = isNullOrUndefined;
520
521 function isNumber(arg) {
522   return typeof arg === 'number';
523 }
524 exports.isNumber = isNumber;
525
526 function isString(arg) {
527   return typeof arg === 'string';
528 }
529 exports.isString = isString;
530
531 function isSymbol(arg) {
532   return typeof arg === 'symbol';
533 }
534 exports.isSymbol = isSymbol;
535
536 function isUndefined(arg) {
537   return arg === undefined;
538 }
539 exports.isUndefined = isUndefined;
540
541 function isRegExp(re) {
542   return re !== null && typeof re === 'object' &&
543          objectToString(re) === '[object RegExp]';
544 }
545 exports.isRegExp = isRegExp;
546
547 function isObject(arg) {
548   return arg !== null && typeof arg === 'object';
549 }
550 exports.isObject = isObject;
551
552 function isDate(d) {
553   return d !== null && typeof d === 'object' &&
554          objectToString(d) === '[object Date]';
555 }
556 exports.isDate = isDate;
557
558 function isError(e) {
559   return e !== null && typeof e === 'object' &&
560       (objectToString(e) === '[object Error]' || e instanceof Error);
561 }
562 exports.isError = isError;
563
564 function isFunction(arg) {
565   return typeof arg === 'function';
566 }
567 exports.isFunction = isFunction;
568
569 function isPrimitive(arg) {
570   return arg === null ||
571          typeof arg !== 'object' && typeof arg !== 'function';
572 }
573 exports.isPrimitive = isPrimitive;
574
575 function isBuffer(arg) {
576   return arg instanceof Buffer;
577 }
578 exports.isBuffer = isBuffer;
579
580 function objectToString(o) {
581   return Object.prototype.toString.call(o);
582 }
583
584
585 function pad(n) {
586   return n < 10 ? '0' + n.toString(10) : n.toString(10);
587 }
588
589
590 const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
591                 'Oct', 'Nov', 'Dec'];
592
593 // 26 Feb 16:19:34
594 function timestamp() {
595   var d = new Date();
596   var time = [pad(d.getHours()),
597               pad(d.getMinutes()),
598               pad(d.getSeconds())].join(':');
599   return [d.getDate(), months[d.getMonth()], time].join(' ');
600 }
601
602
603 // log is just a thin wrapper to console.log that prepends a timestamp
604 exports.log = function() {
605   console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments));
606 };
607
608
609 /**
610  * Inherit the prototype methods from one constructor into another.
611  *
612  * The Function.prototype.inherits from lang.js rewritten as a standalone
613  * function (not on Function.prototype). NOTE: If this file is to be loaded
614  * during bootstrapping this function needs to be rewritten using some native
615  * functions as prototype setup using normal JavaScript does not work as
616  * expected during bootstrapping (see mirror.js in r114903).
617  *
618  * @param {function} ctor Constructor function which needs to inherit the
619  *     prototype.
620  * @param {function} superCtor Constructor function to inherit prototype from.
621  * @throws {TypeError} Will error if either constructor is null, or if
622  *     the super constructor lacks a prototype.
623  */
624 exports.inherits = function(ctor, superCtor) {
625
626   if (ctor === undefined || ctor === null)
627     throw new TypeError('The constructor to `inherits` must not be ' +
628                         'null or undefined.');
629
630   if (superCtor === undefined || superCtor === null)
631     throw new TypeError('The super constructor to `inherits` must not ' +
632                         'be null or undefined.');
633
634   if (superCtor.prototype === undefined)
635     throw new TypeError('The super constructor to `inherits` must ' +
636                         'have a prototype.');
637
638   ctor.super_ = superCtor;
639   ctor.prototype = Object.create(superCtor.prototype, {
640     constructor: {
641       value: ctor,
642       enumerable: false,
643       writable: true,
644       configurable: true
645     }
646   });
647 };
648
649 exports._extend = function(origin, add) {
650   // Don't do anything if add isn't an object
651   if (add === null || typeof add !== 'object') return origin;
652
653   var keys = Object.keys(add);
654   var i = keys.length;
655   while (i--) {
656     origin[keys[i]] = add[keys[i]];
657   }
658   return origin;
659 };
660
661 function hasOwnProperty(obj, prop) {
662   return Object.prototype.hasOwnProperty.call(obj, prop);
663 }
664
665
666 // Deprecated old stuff.
667
668 exports.p = exports.deprecate(function() {
669   for (var i = 0, len = arguments.length; i < len; ++i) {
670     console.error(exports.inspect(arguments[i]));
671   }
672 }, 'util.p: Use console.error() instead');
673
674
675 exports.exec = exports.deprecate(function() {
676   return require('child_process').exec.apply(this, arguments);
677 }, 'util.exec is now called `child_process.exec`.');
678
679
680 exports.print = exports.deprecate(function() {
681   for (var i = 0, len = arguments.length; i < len; ++i) {
682     process.stdout.write(String(arguments[i]));
683   }
684 }, 'util.print: Use console.log instead');
685
686
687 exports.puts = exports.deprecate(function() {
688   for (var i = 0, len = arguments.length; i < len; ++i) {
689     process.stdout.write(arguments[i] + '\n');
690   }
691 }, 'util.puts: Use console.log instead');
692
693
694 exports.debug = exports.deprecate(function(x) {
695   process.stderr.write('DEBUG: ' + x + '\n');
696 }, 'util.debug: Use console.error instead');
697
698
699 exports.error = exports.deprecate(function(x) {
700   for (var i = 0, len = arguments.length; i < len; ++i) {
701     process.stderr.write(arguments[i] + '\n');
702   }
703 }, 'util.error: Use console.error instead');
704
705
706 exports.pump = exports.deprecate(function(readStream, writeStream, callback) {
707   var callbackCalled = false;
708
709   function call(a, b, c) {
710     if (callback && !callbackCalled) {
711       callback(a, b, c);
712       callbackCalled = true;
713     }
714   }
715
716   readStream.addListener('data', function(chunk) {
717     if (writeStream.write(chunk) === false) readStream.pause();
718   });
719
720   writeStream.addListener('drain', function() {
721     readStream.resume();
722   });
723
724   readStream.addListener('end', function() {
725     writeStream.end();
726   });
727
728   readStream.addListener('close', function() {
729     call();
730   });
731
732   readStream.addListener('error', function(err) {
733     writeStream.end();
734     call(err);
735   });
736
737   writeStream.addListener('error', function(err) {
738     readStream.destroy();
739     call(err);
740   });
741 }, 'util.pump(): Use readableStream.pipe() instead');
742
743
744 exports._errnoException = function(err, syscall, original) {
745   var errname = uv.errname(err);
746   var message = syscall + ' ' + errname;
747   if (original)
748     message += ' ' + original;
749   var e = new Error(message);
750   e.code = errname;
751   e.errno = errname;
752   e.syscall = syscall;
753   return e;
754 };
755
756
757 exports._exceptionWithHostPort = function(err,
758                                           syscall,
759                                           address,
760                                           port,
761                                           additional) {
762   var details;
763   if (port && port > 0) {
764     details = address + ':' + port;
765   } else {
766     details = address;
767   }
768
769   if (additional) {
770     details += ' - Local (' + additional + ')';
771   }
772   var ex = exports._errnoException(err, syscall, details);
773   ex.address = address;
774   if (port) {
775     ex.port = port;
776   }
777   return ex;
778 };