util.js 15 KB

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