debug.js 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. /*
  2. * MIT License http://opensource.org/licenses/MIT
  3. * Author: Ben Holloway @bholloway
  4. */
  5. 'use strict';
  6. const path = require('path');
  7. const PACKAGE_NAME = require('../../package.json').name;
  8. /**
  9. * Paths are formatted to have posix style path separators and those within the CWD are made relative to CWD.
  10. *
  11. * @param {string} absolutePath An absolute path to format
  12. * @returns {string} the formatted path
  13. */
  14. const pathToString = (absolutePath) => {
  15. if (absolutePath === '') {
  16. return '-empty-';
  17. } else {
  18. const relative = path.relative(process.cwd(), absolutePath).split(path.sep);
  19. const segments =
  20. (relative[0] !== '..') ? ['.'].concat(relative).filter(Boolean) :
  21. (relative.lastIndexOf('..') < 2) ? relative :
  22. absolutePath.replace(/^[A-Z]\:/, '').split(path.sep);
  23. return segments.join('/');
  24. }
  25. };
  26. exports.pathToString = pathToString;
  27. /**
  28. * Format a debug message.
  29. *
  30. * @param {string} filename The file being processed by webpack
  31. * @param {string} uri A uri path, relative or absolute
  32. * @param {Array<{base:string,joined:string,isSuccess:boolean}>} attempts An array of attempts, possibly empty
  33. * @return {string} Formatted message
  34. */
  35. const formatJoinMessage = (filename, uri, attempts) => {
  36. const attemptToCells = (_, i, array) => {
  37. const { base: prev } = (i === 0) ? {} : array[i-1];
  38. const { base: curr, joined } = array[i];
  39. return [(curr === prev) ? '' : pathToString(curr), pathToString(joined)];
  40. };
  41. const formatCells = (lines) => {
  42. const maxWidth = lines.reduce((max, [cellA]) => Math.max(max, cellA.length), 0);
  43. return lines.map(([cellA, cellB]) => [cellA.padEnd(maxWidth), cellB]).map((cells) => cells.join(' --> '));
  44. };
  45. return [PACKAGE_NAME + ': ' + pathToString(filename) + ': ' + uri]
  46. .concat(attempts.length === 0 ? '-empty-' : formatCells(attempts.map(attemptToCells)))
  47. .concat(attempts.some(({ isSuccess }) => isSuccess) ? 'FOUND' : 'NOT FOUND')
  48. .join('\n ');
  49. };
  50. exports.formatJoinMessage = formatJoinMessage;
  51. /**
  52. * A factory for a log function predicated on the given debug parameter.
  53. *
  54. * The logging function created accepts a function that formats a message and parameters that the function utilises.
  55. * Presuming the message function may be expensive we only call it if logging is enabled.
  56. *
  57. * The log messages are de-duplicated based on the parameters, so it is assumed they are simple types that stringify
  58. * well.
  59. *
  60. * @param {function|boolean} debug A boolean or debug function
  61. * @return {function(function, array):void} A logging function possibly degenerate
  62. */
  63. const createDebugLogger = (debug) => {
  64. const log = !!debug && ((typeof debug === 'function') ? debug : console.log);
  65. const cache = {};
  66. return log ?
  67. ((msgFn, params) => {
  68. const key = Function.prototype.toString.call(msgFn) + JSON.stringify(params);
  69. if (!cache[key]) {
  70. cache[key] = true;
  71. log(msgFn.apply(null, params));
  72. }
  73. }) :
  74. (() => undefined);
  75. };
  76. exports.createDebugLogger = createDebugLogger;