UNPKG

15.7 kBJavaScriptView Raw
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.
21import process from 'process';
22var formatRegExp = /%[sdj%]/g;
23export function format(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.
65export function deprecate(fn, msg) {
66 // Allow for deprecating things in the process of starting up.
67 if (isUndefined(global.process)) {
68 return function() {
69 return 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
96var debugs = {};
97var debugEnviron;
98export function debuglog(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 = 0;
105 debugs[set] = function() {
106 var msg = format.apply(null, 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*/
125export 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 _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
150// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
151inspect.colors = {
152 'bold' : [1, 22],
153 'italic' : [3, 23],
154 'underline' : [4, 24],
155 'inverse' : [7, 27],
156 'white' : [37, 39],
157 'grey' : [90, 39],
158 'black' : [30, 39],
159 'blue' : [34, 39],
160 'cyan' : [36, 39],
161 'green' : [32, 39],
162 'magenta' : [35, 39],
163 'red' : [31, 39],
164 'yellow' : [33, 39]
165};
166
167// Don't use 'blue' not visible on cmd.exe
168inspect.styles = {
169 'special': 'cyan',
170 'number': 'yellow',
171 'boolean': 'yellow',
172 'undefined': 'grey',
173 'null': 'bold',
174 'string': 'green',
175 'date': 'magenta',
176 // "name": intentionally not styling
177 'regexp': 'red'
178};
179
180
181function stylizeWithColor(str, styleType) {
182 var style = inspect.styles[styleType];
183
184 if (style) {
185 return '\u001b[' + inspect.colors[style][0] + 'm' + str +
186 '\u001b[' + inspect.colors[style][1] + 'm';
187 } else {
188 return str;
189 }
190}
191
192
193function stylizeNoColor(str, styleType) {
194 return str;
195}
196
197
198function arrayToHash(array) {
199 var hash = {};
200
201 array.forEach(function(val, idx) {
202 hash[val] = true;
203 });
204
205 return hash;
206}
207
208
209function formatValue(ctx, value, recurseTimes) {
210 // Provide a hook for user-specified inspect functions.
211 // Check that value is an object with an inspect function on it
212 if (ctx.customInspect &&
213 value &&
214 isFunction(value.inspect) &&
215 // Filter out the util module, it's inspect function is special
216 value.inspect !== inspect &&
217 // Also filter out any prototype objects using the circular check.
218 !(value.constructor && value.constructor.prototype === value)) {
219 var ret = value.inspect(recurseTimes, ctx);
220 if (!isString(ret)) {
221 ret = formatValue(ctx, ret, recurseTimes);
222 }
223 return ret;
224 }
225
226 // Primitive types cannot have properties
227 var primitive = formatPrimitive(ctx, value);
228 if (primitive) {
229 return primitive;
230 }
231
232 // Look up the keys of the object.
233 var keys = Object.keys(value);
234 var visibleKeys = arrayToHash(keys);
235
236 if (ctx.showHidden) {
237 keys = Object.getOwnPropertyNames(value);
238 }
239
240 // IE doesn't make error fields non-enumerable
241 // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx
242 if (isError(value)
243 && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) {
244 return formatError(value);
245 }
246
247 // Some type of object without properties can be shortcutted.
248 if (keys.length === 0) {
249 if (isFunction(value)) {
250 var name = value.name ? ': ' + value.name : '';
251 return ctx.stylize('[Function' + name + ']', 'special');
252 }
253 if (isRegExp(value)) {
254 return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
255 }
256 if (isDate(value)) {
257 return ctx.stylize(Date.prototype.toString.call(value), 'date');
258 }
259 if (isError(value)) {
260 return formatError(value);
261 }
262 }
263
264 var base = '', array = false, braces = ['{', '}'];
265
266 // Make Array say that they are Array
267 if (isArray(value)) {
268 array = true;
269 braces = ['[', ']'];
270 }
271
272 // Make functions say that they are functions
273 if (isFunction(value)) {
274 var n = value.name ? ': ' + value.name : '';
275 base = ' [Function' + n + ']';
276 }
277
278 // Make RegExps say that they are RegExps
279 if (isRegExp(value)) {
280 base = ' ' + RegExp.prototype.toString.call(value);
281 }
282
283 // Make dates with properties first say the date
284 if (isDate(value)) {
285 base = ' ' + Date.prototype.toUTCString.call(value);
286 }
287
288 // Make error with message first say the error
289 if (isError(value)) {
290 base = ' ' + formatError(value);
291 }
292
293 if (keys.length === 0 && (!array || value.length == 0)) {
294 return braces[0] + base + braces[1];
295 }
296
297 if (recurseTimes < 0) {
298 if (isRegExp(value)) {
299 return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
300 } else {
301 return ctx.stylize('[Object]', 'special');
302 }
303 }
304
305 ctx.seen.push(value);
306
307 var output;
308 if (array) {
309 output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
310 } else {
311 output = keys.map(function(key) {
312 return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
313 });
314 }
315
316 ctx.seen.pop();
317
318 return reduceToSingleString(output, base, braces);
319}
320
321
322function formatPrimitive(ctx, value) {
323 if (isUndefined(value))
324 return ctx.stylize('undefined', 'undefined');
325 if (isString(value)) {
326 var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
327 .replace(/'/g, "\\'")
328 .replace(/\\"/g, '"') + '\'';
329 return ctx.stylize(simple, 'string');
330 }
331 if (isNumber(value))
332 return ctx.stylize('' + value, 'number');
333 if (isBoolean(value))
334 return ctx.stylize('' + value, 'boolean');
335 // For some reason typeof null is "object", so special case here.
336 if (isNull(value))
337 return ctx.stylize('null', 'null');
338}
339
340
341function formatError(value) {
342 return '[' + Error.prototype.toString.call(value) + ']';
343}
344
345
346function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
347 var output = [];
348 for (var i = 0, l = value.length; i < l; ++i) {
349 if (hasOwnProperty(value, String(i))) {
350 output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
351 String(i), true));
352 } else {
353 output.push('');
354 }
355 }
356 keys.forEach(function(key) {
357 if (!key.match(/^\d+$/)) {
358 output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
359 key, true));
360 }
361 });
362 return output;
363}
364
365
366function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
367 var name, str, desc;
368 desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };
369 if (desc.get) {
370 if (desc.set) {
371 str = ctx.stylize('[Getter/Setter]', 'special');
372 } else {
373 str = ctx.stylize('[Getter]', 'special');
374 }
375 } else {
376 if (desc.set) {
377 str = ctx.stylize('[Setter]', 'special');
378 }
379 }
380 if (!hasOwnProperty(visibleKeys, key)) {
381 name = '[' + key + ']';
382 }
383 if (!str) {
384 if (ctx.seen.indexOf(desc.value) < 0) {
385 if (isNull(recurseTimes)) {
386 str = formatValue(ctx, desc.value, null);
387 } else {
388 str = formatValue(ctx, desc.value, recurseTimes - 1);
389 }
390 if (str.indexOf('\n') > -1) {
391 if (array) {
392 str = str.split('\n').map(function(line) {
393 return ' ' + line;
394 }).join('\n').substr(2);
395 } else {
396 str = '\n' + str.split('\n').map(function(line) {
397 return ' ' + line;
398 }).join('\n');
399 }
400 }
401 } else {
402 str = ctx.stylize('[Circular]', 'special');
403 }
404 }
405 if (isUndefined(name)) {
406 if (array && key.match(/^\d+$/)) {
407 return str;
408 }
409 name = JSON.stringify('' + key);
410 if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
411 name = name.substr(1, name.length - 2);
412 name = ctx.stylize(name, 'name');
413 } else {
414 name = name.replace(/'/g, "\\'")
415 .replace(/\\"/g, '"')
416 .replace(/(^"|"$)/g, "'");
417 name = ctx.stylize(name, 'string');
418 }
419 }
420
421 return name + ': ' + str;
422}
423
424
425function reduceToSingleString(output, base, braces) {
426 var numLinesEst = 0;
427 var length = output.reduce(function(prev, cur) {
428 numLinesEst++;
429 if (cur.indexOf('\n') >= 0) numLinesEst++;
430 return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
431 }, 0);
432
433 if (length > 60) {
434 return braces[0] +
435 (base === '' ? '' : base + '\n ') +
436 ' ' +
437 output.join(',\n ') +
438 ' ' +
439 braces[1];
440 }
441
442 return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
443}
444
445
446// NOTE: These type checking functions intentionally don't use `instanceof`
447// because it is fragile and can be easily faked with `Object.create()`.
448export function isArray(ar) {
449 return Array.isArray(ar);
450}
451
452export function isBoolean(arg) {
453 return typeof arg === 'boolean';
454}
455
456export function isNull(arg) {
457 return arg === null;
458}
459
460export function isNullOrUndefined(arg) {
461 return arg == null;
462}
463
464export function isNumber(arg) {
465 return typeof arg === 'number';
466}
467
468export function isString(arg) {
469 return typeof arg === 'string';
470}
471
472export function isSymbol(arg) {
473 return typeof arg === 'symbol';
474}
475
476export function isUndefined(arg) {
477 return arg === void 0;
478}
479
480export function isRegExp(re) {
481 return isObject(re) && objectToString(re) === '[object RegExp]';
482}
483
484export function isObject(arg) {
485 return typeof arg === 'object' && arg !== null;
486}
487
488export function isDate(d) {
489 return isObject(d) && objectToString(d) === '[object Date]';
490}
491
492export function isError(e) {
493 return isObject(e) &&
494 (objectToString(e) === '[object Error]' || e instanceof Error);
495}
496
497export function isFunction(arg) {
498 return typeof arg === 'function';
499}
500
501export function isPrimitive(arg) {
502 return arg === null ||
503 typeof arg === 'boolean' ||
504 typeof arg === 'number' ||
505 typeof arg === 'string' ||
506 typeof arg === 'symbol' || // ES6 symbol
507 typeof arg === 'undefined';
508}
509
510export function isBuffer(maybeBuf) {
511 return Buffer.isBuffer(maybeBuf);
512}
513
514function objectToString(o) {
515 return Object.prototype.toString.call(o);
516}
517
518
519function pad(n) {
520 return n < 10 ? '0' + n.toString(10) : n.toString(10);
521}
522
523
524var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
525 'Oct', 'Nov', 'Dec'];
526
527// 26 Feb 16:19:34
528function timestamp() {
529 var d = new Date();
530 var time = [pad(d.getHours()),
531 pad(d.getMinutes()),
532 pad(d.getSeconds())].join(':');
533 return [d.getDate(), months[d.getMonth()], time].join(' ');
534}
535
536
537// log is just a thin wrapper to console.log that prepends a timestamp
538export function log() {
539 console.log('%s - %s', timestamp(), format.apply(null, arguments));
540}
541
542
543/**
544 * Inherit the prototype methods from one constructor into another.
545 *
546 * The Function.prototype.inherits from lang.js rewritten as a standalone
547 * function (not on Function.prototype). NOTE: If this file is to be loaded
548 * during bootstrapping this function needs to be rewritten using some native
549 * functions as prototype setup using normal JavaScript does not work as
550 * expected during bootstrapping (see mirror.js in r114903).
551 *
552 * @param {function} ctor Constructor function which needs to inherit the
553 * prototype.
554 * @param {function} superCtor Constructor function to inherit prototype from.
555 */
556import inherits from './inherits';
557export {inherits}
558
559export function _extend(origin, add) {
560 // Don't do anything if add isn't an object
561 if (!add || !isObject(add)) return origin;
562
563 var keys = Object.keys(add);
564 var i = keys.length;
565 while (i--) {
566 origin[keys[i]] = add[keys[i]];
567 }
568 return origin;
569};
570
571function hasOwnProperty(obj, prop) {
572 return Object.prototype.hasOwnProperty.call(obj, prop);
573}
574
575export default {
576 inherits: inherits,
577 _extend: _extend,
578 log: log,
579 isBuffer: isBuffer,
580 isPrimitive: isPrimitive,
581 isFunction: isFunction,
582 isError: isError,
583 isDate: isDate,
584 isObject: isObject,
585 isRegExp: isRegExp,
586 isUndefined: isUndefined,
587 isSymbol: isSymbol,
588 isString: isString,
589 isNumber: isNumber,
590 isNullOrUndefined: isNullOrUndefined,
591 isNull: isNull,
592 isBoolean: isBoolean,
593 isArray: isArray,
594 inspect: inspect,
595 deprecate: deprecate,
596 format: format,
597 debuglog: debuglog
598}