pad-levels.js 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. /* eslint no-unused-vars: 0 */
  2. 'use strict';
  3. const { configs, LEVEL, MESSAGE } = require('triple-beam');
  4. class Padder {
  5. constructor(opts = { levels: configs.npm.levels }) {
  6. this.paddings = Padder.paddingForLevels(opts.levels, opts.filler);
  7. this.options = opts;
  8. }
  9. /**
  10. * Returns the maximum length of keys in the specified `levels` Object.
  11. * @param {Object} levels Set of all levels to calculate longest level against.
  12. * @returns {Number} Maximum length of the longest level string.
  13. */
  14. static getLongestLevel(levels) {
  15. const lvls = Object.keys(levels).map(level => level.length);
  16. return Math.max(...lvls);
  17. }
  18. /**
  19. * Returns the padding for the specified `level` assuming that the
  20. * maximum length of all levels it's associated with is `maxLength`.
  21. * @param {String} level Level to calculate padding for.
  22. * @param {String} filler Repeatable text to use for padding.
  23. * @param {Number} maxLength Length of the longest level
  24. * @returns {String} Padding string for the `level`
  25. */
  26. static paddingForLevel(level, filler, maxLength) {
  27. const targetLen = maxLength + 1 - level.length;
  28. const rep = Math.floor(targetLen / filler.length);
  29. const padding = `${filler}${filler.repeat(rep)}`;
  30. return padding.slice(0, targetLen);
  31. }
  32. /**
  33. * Returns an object with the string paddings for the given `levels`
  34. * using the specified `filler`.
  35. * @param {Object} levels Set of all levels to calculate padding for.
  36. * @param {String} filler Repeatable text to use for padding.
  37. * @returns {Object} Mapping of level to desired padding.
  38. */
  39. static paddingForLevels(levels, filler = ' ') {
  40. const maxLength = Padder.getLongestLevel(levels);
  41. return Object.keys(levels).reduce((acc, level) => {
  42. acc[level] = Padder.paddingForLevel(level, filler, maxLength);
  43. return acc;
  44. }, {});
  45. }
  46. /**
  47. * Prepends the padding onto the `message` based on the `LEVEL` of
  48. * the `info`. This is based on the behavior of `winston@2` which also
  49. * prepended the level onto the message.
  50. *
  51. * See: https://github.com/winstonjs/winston/blob/2.x/lib/winston/logger.js#L198-L201
  52. *
  53. * @param {Info} info Logform info object
  54. * @param {Object} opts Options passed along to this instance.
  55. * @returns {Info} Modified logform info object.
  56. */
  57. transform(info, opts) {
  58. info.message = `${this.paddings[info[LEVEL]]}${info.message}`;
  59. if (info[MESSAGE]) {
  60. info[MESSAGE] = `${this.paddings[info[LEVEL]]}${info[MESSAGE]}`;
  61. }
  62. return info;
  63. }
  64. }
  65. /*
  66. * function padLevels (info)
  67. * Returns a new instance of the padLevels Format which pads
  68. * levels to be the same length. This was previously exposed as
  69. * { padLevels: true } to transports in `winston < 3.0.0`.
  70. */
  71. module.exports = opts => new Padder(opts);
  72. module.exports.Padder
  73. = module.exports.Format
  74. = Padder;