index.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. /**
  2. * @type {Object.<string, number>}
  3. */
  4. export const LEVELS = {
  5. debug: 0,
  6. info: 1,
  7. warn: 2,
  8. error: 3,
  9. fatal: 4,
  10. };
  11. /* eslint-disable @typescript-eslint/no-empty-function */
  12. const logger = Object.assign(
  13. {
  14. debug: console?.log ? console.log.bind(console) : function noop() {},
  15. error: console?.log ? console.log.bind(console) : function noop() {},
  16. info: console?.log ? console.log.bind(console) : function noop() {},
  17. warn: console?.log ? console.log.bind(console) : function noop() {},
  18. },
  19. console
  20. );
  21. /* eslint-enable @typescript-eslint/no-empty-function */
  22. /**
  23. * Logs messages to the console.
  24. * Available loglevels are:
  25. * - 0: 'debug'
  26. * - 1: 'info'
  27. * - 2: 'warn',
  28. * - 3: 'error'
  29. * - 4: 'fatal'.
  30. * When using the 'error' or 'warn' loglevels, a full stacktrace will be logged as well.
  31. * @namespace log
  32. */
  33. const log = {
  34. /** @type {keyof LEVELS} The current log level */
  35. loglevel: "info",
  36. /**
  37. * Sets the current log level which determines which messages are logged
  38. * @param {keyof LEVELS} level - The log level to set
  39. * @throws {Error} If an invalid log level is provided
  40. */
  41. setLogLevel(level) {
  42. if (!["debug", "info", "warn", "error", "fatal"].includes(/** @type {string} */ (level))) {
  43. throw new Error(`Invalid loglevel: ${level}`);
  44. }
  45. this.loglevel = level;
  46. },
  47. /**
  48. * Logs a message at the specified level with optional CSS styling
  49. * @param {any} message - The message to log
  50. * @param {keyof LEVELS} level - The log level to use
  51. * @param {string} [style=""] - Optional CSS styles to apply to the log message
  52. */
  53. log(message, level, style = "") {
  54. if (LEVELS[level] < LEVELS[this.loglevel]) {
  55. return;
  56. }
  57. if (level === "error" || level === "fatal") {
  58. style = style || "color: maroon";
  59. } else if (level === "debug") {
  60. style = style || "color: green";
  61. }
  62. if (message instanceof Error) {
  63. message = message.stack;
  64. } else if (isElement(message)) {
  65. message = /** @type {Element} */ (message).outerHTML;
  66. }
  67. const prefix = style ? "%c" : "";
  68. if (level === "error") {
  69. logger.error(`${prefix} ERROR: ${message}`, style);
  70. } else if (level === "warn") {
  71. logger.warn(`${prefix} ${new Date().toISOString()} WARNING: ${message}`, style);
  72. } else if (level === "fatal") {
  73. logger.error(`${prefix} FATAL: ${message}`, style);
  74. } else if (level === "debug") {
  75. logger.debug(`${prefix} ${new Date().toISOString()} DEBUG: ${message}`, style);
  76. } else {
  77. logger.info(`${prefix} ${new Date().toISOString()} INFO: ${message}`, style);
  78. }
  79. },
  80. /**
  81. * @param {any} message - The message to log
  82. * @param {string} [style=""] - Optional CSS styles to apply to the log message
  83. */
  84. debug(message, style) {
  85. this.log(message, "debug", style);
  86. },
  87. /**
  88. * @param {any} message - The message to log
  89. * @param {string} [style=""] - Optional CSS styles to apply to the log message
  90. */
  91. error(message, style) {
  92. this.log(message, "error", style);
  93. },
  94. /**
  95. * @param {any} message - The message to log
  96. * @param {string} [style=""] - Optional CSS styles to apply to the log message
  97. */
  98. info(message, style) {
  99. this.log(message, "info", style);
  100. },
  101. /**
  102. * @param {any} message - The message to log
  103. * @param {string} [style=""] - Optional CSS styles to apply to the log message
  104. */
  105. warn(message, style) {
  106. this.log(message, "warn", style);
  107. },
  108. /**
  109. * @param {any} message - The message to log
  110. * @param {string} [style=""] - Optional CSS styles to apply to the log message
  111. */
  112. fatal(message, style) {
  113. this.log(message, "fatal", style);
  114. },
  115. };
  116. /**
  117. * @param {unknown} el - The value to check
  118. * @returns {boolean} True if the value is an Element or Document
  119. */
  120. export function isElement(el) {
  121. return el instanceof Element || el instanceof Document;
  122. }
  123. export default log;