util.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  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. import process from 'process';
  22. var formatRegExp = /%[sdj%]/g;
  23. export 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. var i = 1;
  32. var args = arguments;
  33. var len = args.length;
  34. var str = String(f).replace(formatRegExp, function(x) {
  35. if (x === '%%') return '%';
  36. if (i >= len) return x;
  37. switch (x) {
  38. case '%s': return String(args[i++]);
  39. case '%d': return Number(args[i++]);
  40. case '%j':
  41. try {
  42. return JSON.stringify(args[i++]);
  43. } catch (_) {
  44. return '[Circular]';
  45. }
  46. default:
  47. return x;
  48. }
  49. });
  50. for (var x = args[i]; i < len; x = args[++i]) {
  51. if (isNull(x) || !isObject(x)) {
  52. str += ' ' + x;
  53. } else {
  54. str += ' ' + inspect(x);
  55. }
  56. }
  57. return str;
  58. };
  59. // Mark that a method should not be used.
  60. // Returns a modified function which warns once by default.
  61. // If --no-deprecation is set, then it is a no-op.
  62. export function deprecate(fn, msg) {
  63. // Allow for deprecating things in the process of starting up.
  64. if (isUndefined(global.process)) {
  65. return function() {
  66. return deprecate(fn, msg).apply(this, arguments);
  67. };
  68. }
  69. if (process.noDeprecation === true) {
  70. return fn;
  71. }
  72. var warned = false;
  73. function deprecated() {
  74. if (!warned) {
  75. if (process.throwDeprecation) {
  76. throw new Error(msg);
  77. } else if (process.traceDeprecation) {
  78. console.trace(msg);
  79. } else {
  80. console.error(msg);
  81. }
  82. warned = true;
  83. }
  84. return fn.apply(this, arguments);
  85. }
  86. return deprecated;
  87. };
  88. var debugs = {};
  89. var debugEnviron;
  90. export function debuglog(set) {
  91. if (isUndefined(debugEnviron))
  92. debugEnviron = process.env.NODE_DEBUG || '';
  93. set = set.toUpperCase();
  94. if (!debugs[set]) {
  95. if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) {
  96. var pid = 0;
  97. debugs[set] = function() {
  98. var msg = format.apply(null, arguments);
  99. console.error('%s %d: %s', set, pid, msg);
  100. };
  101. } else {
  102. debugs[set] = function() {};
  103. }
  104. }
  105. return debugs[set];
  106. };
  107. /**
  108. * Echos the value of a value. Trys to print the value out
  109. * in the best way possible given the different types.
  110. *
  111. * @param {Object} obj The object to print out.
  112. * @param {Object} opts Optional options object that alters the output.
  113. */
  114. /* legacy: obj, showHidden, depth, colors*/
  115. export function inspect(obj, opts) {
  116. // default options
  117. var ctx = {
  118. seen: [],
  119. stylize: stylizeNoColor
  120. };
  121. // legacy...
  122. if (arguments.length >= 3) ctx.depth = arguments[2];
  123. if (arguments.length >= 4) ctx.colors = arguments[3];
  124. if (isBoolean(opts)) {
  125. // legacy...
  126. ctx.showHidden = opts;
  127. } else if (opts) {
  128. // got an "options" object
  129. _extend(ctx, opts);
  130. }
  131. // set default options
  132. if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
  133. if (isUndefined(ctx.depth)) ctx.depth = 2;
  134. if (isUndefined(ctx.colors)) ctx.colors = false;
  135. if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
  136. if (ctx.colors) ctx.stylize = stylizeWithColor;
  137. return formatValue(ctx, obj, ctx.depth);
  138. }
  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 !== 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. export function isArray(ar) {
  394. return Array.isArray(ar);
  395. }
  396. export function isBoolean(arg) {
  397. return typeof arg === 'boolean';
  398. }
  399. export function isNull(arg) {
  400. return arg === null;
  401. }
  402. export function isNullOrUndefined(arg) {
  403. return arg == null;
  404. }
  405. export function isNumber(arg) {
  406. return typeof arg === 'number';
  407. }
  408. export function isString(arg) {
  409. return typeof arg === 'string';
  410. }
  411. export function isSymbol(arg) {
  412. return typeof arg === 'symbol';
  413. }
  414. export function isUndefined(arg) {
  415. return arg === void 0;
  416. }
  417. export function isRegExp(re) {
  418. return isObject(re) && objectToString(re) === '[object RegExp]';
  419. }
  420. export function isObject(arg) {
  421. return typeof arg === 'object' && arg !== null;
  422. }
  423. export function isDate(d) {
  424. return isObject(d) && objectToString(d) === '[object Date]';
  425. }
  426. export function isError(e) {
  427. return isObject(e) &&
  428. (objectToString(e) === '[object Error]' || e instanceof Error);
  429. }
  430. export function isFunction(arg) {
  431. return typeof arg === 'function';
  432. }
  433. export function isPrimitive(arg) {
  434. return arg === null ||
  435. typeof arg === 'boolean' ||
  436. typeof arg === 'number' ||
  437. typeof arg === 'string' ||
  438. typeof arg === 'symbol' || // ES6 symbol
  439. typeof arg === 'undefined';
  440. }
  441. export function isBuffer(maybeBuf) {
  442. return Buffer.isBuffer(maybeBuf);
  443. }
  444. function objectToString(o) {
  445. return Object.prototype.toString.call(o);
  446. }
  447. function pad(n) {
  448. return n < 10 ? '0' + n.toString(10) : n.toString(10);
  449. }
  450. var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
  451. 'Oct', 'Nov', 'Dec'];
  452. // 26 Feb 16:19:34
  453. function timestamp() {
  454. var d = new Date();
  455. var time = [pad(d.getHours()),
  456. pad(d.getMinutes()),
  457. pad(d.getSeconds())].join(':');
  458. return [d.getDate(), months[d.getMonth()], time].join(' ');
  459. }
  460. // log is just a thin wrapper to console.log that prepends a timestamp
  461. export function log() {
  462. console.log('%s - %s', timestamp(), format.apply(null, arguments));
  463. }
  464. /**
  465. * Inherit the prototype methods from one constructor into another.
  466. *
  467. * The Function.prototype.inherits from lang.js rewritten as a standalone
  468. * function (not on Function.prototype). NOTE: If this file is to be loaded
  469. * during bootstrapping this function needs to be rewritten using some native
  470. * functions as prototype setup using normal JavaScript does not work as
  471. * expected during bootstrapping (see mirror.js in r114903).
  472. *
  473. * @param {function} ctor Constructor function which needs to inherit the
  474. * prototype.
  475. * @param {function} superCtor Constructor function to inherit prototype from.
  476. */
  477. import inherits from './inherits';
  478. export {inherits}
  479. export function _extend(origin, add) {
  480. // Don't do anything if add isn't an object
  481. if (!add || !isObject(add)) return origin;
  482. var keys = Object.keys(add);
  483. var i = keys.length;
  484. while (i--) {
  485. origin[keys[i]] = add[keys[i]];
  486. }
  487. return origin;
  488. };
  489. function hasOwnProperty(obj, prop) {
  490. return Object.prototype.hasOwnProperty.call(obj, prop);
  491. }
  492. export default {
  493. inherits: inherits,
  494. _extend: _extend,
  495. log: log,
  496. isBuffer: isBuffer,
  497. isPrimitive: isPrimitive,
  498. isFunction: isFunction,
  499. isError: isError,
  500. isDate: isDate,
  501. isObject: isObject,
  502. isRegExp: isRegExp,
  503. isUndefined: isUndefined,
  504. isSymbol: isSymbol,
  505. isString: isString,
  506. isNumber: isNumber,
  507. isNullOrUndefined: isNullOrUndefined,
  508. isNull: isNull,
  509. isBoolean: isBoolean,
  510. isArray: isArray,
  511. inspect: inspect,
  512. deprecate: deprecate,
  513. format: format,
  514. debuglog: debuglog
  515. }