UNPKG

spectra-log

Version:

SpectraLog enables you to apply various colors to your log messages, enhancing readability and making your logs visually dynamic.

580 lines (564 loc) 19.5 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // index.ts var index_exports = {}; __export(index_exports, { default: () => index_default }); module.exports = __toCommonJS(index_exports); // core/colorManager.ts var import_ansi_colors = __toESM(require("ansi-colors"), 1); var defineColor = (code) => { const colorFn = (text) => `\x1B[38;5;${code}m${text}\x1B[0m`; colorFn.colorCode = code; return colorFn; }; var customColors = { red: defineColor(196), green: defineColor(82), blue: defineColor(33), brightCyan: defineColor(116), cyan: defineColor(51), muteCyan: defineColor(67), white: defineColor(255), gray: defineColor(245), dim: defineColor(240), orange: defineColor(202), pink: defineColor(213), purple: defineColor(135), violet: defineColor(129), teal: defineColor(37), brightYellow: defineColor(226), brightGreen: defineColor(118), brightRed: defineColor(196), brightBlue: defineColor(75), brown: defineColor(130), gold: defineColor(220), lime: defineColor(154), silver: defineColor(250), maroon: defineColor(88) }; var extendedColors = Object.create(import_ansi_colors.default); Object.assign(extendedColors, customColors); var addStyleMethod = (colorFn, styleName, styleCode) => { colorFn[styleName] = (text) => { return `\x1B[38;5;${colorFn.colorCode}m${styleCode}${text}\x1B[0m`; }; }; Object.keys(customColors).forEach((color) => { const colorFn = extendedColors[color]; if (typeof colorFn === "function" && colorFn.colorCode !== void 0) { addStyleMethod(colorFn, "bold", "\x1B[1m"); addStyleMethod(colorFn, "dim", "\x1B[2m"); addStyleMethod(colorFn, "italic", "\x1B[3m"); addStyleMethod(colorFn, "underline", "\x1B[4m"); } }); var colorManager_default = extendedColors; // core/colorize.ts var colorizeString = (message) => { let processedMessage; if (typeof message === "object" && message !== null) { processedMessage = JSON.stringify(message, null, 2); } else if (message === null || message === void 0) { processedMessage = String(message); } else { processedMessage = String(message); } const regex = /\{\{\s*(?:(\w+)\s*:\s*)?(\w+)\s*:\s*([^\}]+?)\s*\}\}/g; return processedMessage.replace(regex, (match, style, color, text) => { style = style?.toLowerCase(); const trimmedText = text.replace(/^ /, "").replace(/ $/, ""); const colorFn = colorManager_default[color] || colorManager_default.dim; if (style && typeof colorFn[style] === "function") { return colorFn[style](trimmedText); } return colorFn(trimmedText); }); }; var colorize_default = colorizeString; // util/stripAnsi.ts var stripAnsi = (str) => str.replace(/\x1b\[[0-9;]*m/g, ""); var stripAnsi_default = stripAnsi; // util/sleep.ts var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); var sleep_default = sleep; // config/constants.ts var smoothPrint = false; var interval = 5; var processLevel = 2; var isProcessing = false; var displayStandby = false; var messageQueue = []; var DebugLevelOrder = { "MUTE": -1, "TRACE": 0, "DEBUG": 1, "INFO": 2, "ERROR": 3, "FATAL": 4, "NOTLVL": 5 }; var getIsProcessing = () => isProcessing; var setIsProcessing = (value) => { isProcessing = value; }; var getSmoothPrint = () => smoothPrint; var setSmoothPrint = (value) => { smoothPrint = value; }; var getProcessLevel = () => processLevel; var setProcessLevel = (value) => { processLevel = DebugLevelOrder[value]; }; var getPrintSpeed = () => interval; var setPrintSpeed = (value) => { interval = value; }; var getDisplayStandby = () => displayStandby; var setDisplayStandby = (value) => { displayStandby = value; }; // util/stringWidth.ts var fullWidthRegex = /[\u1100-\u115F\u2329\u232A\u2E80-\u303E\u3040-\uA4CF\uAC00-\uD7A3\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE6F\uFF01-\uFF60\uFFE0-\uFFE6]|[\u{1F300}-\u{1F64F}]|[\u{1F900}-\u{1F9FF}]/u; var stringWidth = (str) => { const clean = stripAnsi_default(str); let width = 0; for (const char of [...clean]) { width += fullWidthRegex.test(char) ? 2 : 1; } return width; }; var stringWidth_default = stringWidth; // core/printer.ts var parseAnsiAndText = (str) => { const parts = []; let i = 0; let textBuffer = ""; while (i < str.length) { const ansiMatch = str.slice(i).match(/^\u001b\[[0-9;]*m/); if (ansiMatch) { if (textBuffer) { parts.push({ type: "text", content: textBuffer }); textBuffer = ""; } parts.push({ type: "ansi", content: ansiMatch[0] }); i += ansiMatch[0].length; } else { textBuffer += str[i]; i++; } } if (textBuffer) { parts.push({ type: "text", content: textBuffer }); } return parts; }; var splitTextIntoChunks = (text, maxWidth) => { if (!text) return []; const parts = parseAnsiAndText(text); const chunks = []; let currentChunk = ""; let currentWidth = 0; let activeAnsiCodes = []; for (const part of parts) { if (part.type === "ansi") { currentChunk += part.content; if (part.content === "\x1B[0m") { activeAnsiCodes = []; } else { activeAnsiCodes.push(part.content); } } else { let remaining = part.content; while (remaining) { let fit = 0; let fitWidth = 0; for (let i = 0; i < remaining.length; i++) { const charWidth = stringWidth_default(remaining[i]); if (currentWidth + fitWidth + charWidth <= maxWidth) { fit++; fitWidth += charWidth; } else { break; } } if (fit === 0 && currentWidth > 0) { chunks.push(currentChunk); currentChunk = activeAnsiCodes.join(""); currentWidth = 0; } else { const textToAdd = remaining.slice(0, fit || 1); currentChunk += textToAdd; currentWidth += fitWidth || stringWidth_default(textToAdd); remaining = remaining.slice(fit || 1); if (remaining && currentWidth > 0) { chunks.push(currentChunk); currentChunk = activeAnsiCodes.join(""); currentWidth = 0; } } } } } if (currentChunk) { chunks.push(currentChunk); } return chunks; }; var printLineSmooth = async (line, currentPrefix, terminalWidth) => { const prefixWidth = stripAnsi_default(currentPrefix).length; const availWidth = terminalWidth - prefixWidth; const chunks = splitTextIntoChunks(line, availWidth); if (chunks.length === 0) { process.stdout.write(`\r${currentPrefix} `); return; } for (let chunkIndex = 0; chunkIndex < chunks.length; chunkIndex++) { const chunk = chunks[chunkIndex]; const prefix = chunkIndex === 0 ? currentPrefix : " ".repeat(36) + " | "; process.stdout.write(`\r${prefix}`); const parts = parseAnsiAndText(chunk); for (const part of parts) { if (part.type === "ansi") { process.stdout.write(part.content); } else { for (const char of part.content) { process.stdout.write(char); await sleep_default(getPrintSpeed()); } } } process.stdout.write("\n"); } }; var printSmooth = async (prefix, lines) => { const terminalWidth = Math.floor(process.stdout.columns * 0.9) || 80; for (let i = 0; i < lines.length; i++) { const linePrefix = i === 0 ? prefix : " ".repeat(36) + " | "; await printLineSmooth(lines[i], linePrefix, terminalWidth); } }; var printer_default = printSmooth; // config/levelTypes.ts var LEVEL_TYPES = { FATAL: { levelLabel: "FATAL", color: colorManager_default.red.bold }, ERROR: { levelLabel: "ERROR", color: colorManager_default.orange.bold }, INFO: { levelLabel: "INFO", color: colorManager_default.yellow.bold }, DEBUG: { levelLabel: "DEBUG", color: colorManager_default.brightCyan.bold }, TRACE: { levelLabel: "TRACE", color: colorManager_default.muteCyan.bold }, default: { levelLabel: "NOTLVL", color: colorManager_default.red.bold } }; var levelTypes_default = LEVEL_TYPES; // config/httpTypes.ts var HTTP_MESSAGE_TYPES = { 100: { httpLabel: "CONTINUE", color: colorManager_default.dim }, 101: { httpLabel: "SWITCHING", color: colorManager_default.dim }, 200: { httpLabel: "OK", color: colorManager_default.green }, 201: { httpLabel: "CREATED", color: colorManager_default.green }, 202: { httpLabel: "ACCEPTED", color: colorManager_default.cyan }, 204: { httpLabel: "NO-CONTENT", color: colorManager_default.gray }, 301: { httpLabel: "MOVED", color: colorManager_default.yellow }, 302: { httpLabel: "FOUND", color: colorManager_default.yellow }, 304: { httpLabel: "NOT-MODIFIED", color: colorManager_default.gray }, 400: { httpLabel: "BAD-REQUEST", color: colorManager_default.red }, 401: { httpLabel: "UNAUTHZED", color: colorManager_default.red }, 402: { httpLabel: "PAY-REQUEST", color: colorManager_default.red }, 403: { httpLabel: "FORBIDDEN", color: colorManager_default.red }, 404: { httpLabel: "NOT-FOUND", color: colorManager_default.red }, 405: { httpLabel: "NO-METHOD", color: colorManager_default.red }, 408: { httpLabel: "TIMEOUT", color: colorManager_default.red }, 409: { httpLabel: "CONFLICT", color: colorManager_default.red }, 410: { httpLabel: "GONE", color: colorManager_default.red }, 429: { httpLabel: "TOO-MANY", color: colorManager_default.red }, 500: { httpLabel: "SERVER-ERROR", color: colorManager_default.red }, 502: { httpLabel: "BAD-GATEWAY", color: colorManager_default.red }, 503: { httpLabel: "SERVER-NAVAL", color: colorManager_default.red }, 504: { httpLabel: "GW-TIMEOUT", color: colorManager_default.red }, 600: { httpLabel: "SERVER-START", color: colorManager_default.yellow }, default: { httpLabel: "UNKNOWN", color: colorManager_default.dim } }; var httpTypes_default = HTTP_MESSAGE_TYPES; // util/time.ts var getFormattedTime = (timestamp) => { const time = new Date(timestamp); return `${String(time.getHours()).padStart(2, "0")}:${String( time.getMinutes() ).padStart(2, "0")}:${String(time.getSeconds()).padStart(2, "0")}`; }; var time_default = getFormattedTime; // core/formatter.ts var getPrefix = (type, level, timestamp) => { const { levelLabel, color: levelColor } = levelTypes_default[level] || levelTypes_default.default; const { httpLabel, color: typeColor } = httpTypes_default[type] || httpTypes_default.default; const shortLabel = levelLabel.substring(0, 2); const fullLabel = shortLabel + levelLabel.substring(2); return `[ ${levelColor(fullLabel.padEnd(6))} | ${typeColor( httpLabel.padEnd(12) )} | ${time_default(timestamp)} ] | `; }; var formatMultiline = (lines, prefix, maxWidth = Math.floor(process.stdout.columns * 0.9) || 80) => { const visualPrefixLength = stripAnsi_default(prefix).length; const linePad = " ".repeat(36) + " | "; const formatted = []; lines.forEach((line, i) => { const availWidth = maxWidth - (i === 0 ? visualPrefixLength : stripAnsi_default(linePad).length); if (!line) { formatted.push(`${i === 0 ? prefix : linePad}`); return; } const ansiLength = line.length - stripAnsi_default(line).length; let chunks = splitIntoVisualChunks(line, availWidth + ansiLength); if (chunks.length === 0) { chunks = [line]; } chunks.forEach((chunk, chunkIndex) => { const linePrefix = i === 0 && chunkIndex === 0 ? prefix : linePad; formatted.push(`${linePrefix}${chunk}`); }); }); return formatted.join("\n"); }; var splitIntoVisualChunks = (text, maxWidth) => { if (!text) return []; const ansiCodesMap = /* @__PURE__ */ new Map(); const visibleText = stripAnsi_default(text); let originalIndex = 0; let strippedIndex = 0; let activeAnsiCodes = []; while (originalIndex < text.length) { const ansiMatch = text.slice(originalIndex).match(/^\x1B\[[0-9;]*m/); if (ansiMatch) { const ansiCode = ansiMatch[0]; if (!ansiCodesMap.has(strippedIndex)) { ansiCodesMap.set(strippedIndex, []); } ansiCodesMap.get(strippedIndex).push(ansiCode); if (ansiCode === "\x1B[0m") { activeAnsiCodes = []; } else { activeAnsiCodes.push(ansiCode); } originalIndex += ansiCode.length; } else { originalIndex++; strippedIndex++; } } const chunks = []; let start = 0; while (start < visibleText.length) { let visibleWidth = 0; let end = start; while (end < visibleText.length && visibleWidth < maxWidth) { const charWidth = stringWidth_default(visibleText[end]); if (visibleWidth + charWidth <= maxWidth) { visibleWidth += charWidth; end++; } else { break; } } if (end === start && start < visibleText.length) { end = start + 1; } let chunk = ""; let activeCodesForNextChunk = []; for (let i = start; i <= end; i++) { if (ansiCodesMap.has(i)) { const codes = ansiCodesMap.get(i); for (const code of codes) { chunk += code; if (code === "\x1B[0m") { activeCodesForNextChunk = []; } else { activeCodesForNextChunk.push(code); } } } if (i < end && i < visibleText.length) { chunk += visibleText[i]; } } chunks.push(chunk); start = end; activeAnsiCodes = [...activeCodesForNextChunk]; } if (chunks.length === 0 && text) { chunks.push(text); } return chunks; }; // core/queueProcessor.ts var isStandbyActive = false; var printMessage = async (message, type, level, timestamp) => { const prefix = getPrefix(type, level, timestamp); const str = typeof message === "object" ? JSON.stringify(message, null, 2) || "[Unserializable Object]" : String(message); const lines = str.split("\n"); if (getSmoothPrint() && lines.length > 0) { await printer_default(prefix, lines); } else { process.stdout.write(`\r${formatMultiline(lines, prefix)} `); } }; var processQueue = async () => { if (getIsProcessing() || messageQueue.length === 0) return; stopStandbyLog(); setIsProcessing(true); const item = messageQueue.shift(); if (!item || typeof item !== "object" || item === null) { setIsProcessing(false); if (messageQueue.length === 0) { startStandbyLog(); } else { processQueue(); } return; } const { message, type, level, timestamp } = item; await printMessage(message, type, level, timestamp); setIsProcessing(false); if (messageQueue.length === 0) { startStandbyLog(); } else { processQueue(); } }; var startStandbyLog = () => { if (!getDisplayStandby() || isStandbyActive) return; isStandbyActive = true; (async function standbyLoop() { while (isStandbyActive) { const prefix = getPrefix("default", "INFO", Date.now()).replace( /\[.*?\]/, `[ ${colorManager_default.yellow.bold("STBY")} | - | ${time_default( Date.now() )} ]` ); process.stdout.write(`\r${prefix}`); await sleep_default(1e3); } })(); }; var stopStandbyLog = () => { isStandbyActive = false; }; var queueProcessor_default = processQueue; // util/debugLevel.ts var getDebugLevel = (levelLabel) => { switch (levelLabel) { case "MUTE": return { level: -1, color: "dim" }; case "TRACE": return { level: 0, color: "muteCyan" }; case "DEBUG": return { level: 1, color: "brightCyan" }; case "INFO": return { level: 2, color: "yellow" }; case "ERROR": return { level: 3, color: "orange" }; case "FATAL": return { level: 4, color: "red" }; default: return { level: 5, color: "dim" }; } }; var debugLevel_default = getDebugLevel; // index.ts var log = (message, type = 200, level = "INFO", option = {}) => { const { urgent = false, force = false } = option; if (force === true || getProcessLevel() <= debugLevel_default(level).level) { message = colorize_default(message); if (urgent === true) messageQueue.unshift({ message, type, level, timestamp: Date.now() }); else messageQueue.push({ message, type, level, timestamp: Date.now() }); queueProcessor_default(); } }; log.setDebugLevel = (level, options = { silent: false }) => { const { silent } = options; const temp = debugLevel_default(level); setProcessLevel(level); silentHandler( silent, `{{ bold : yellow : Debug level }} has been changed to {{ bold : ${temp.color} : ${level} }}.` ); }; log.setPrintSpeed = (delay, option = {}) => { const { silent = false } = option; setPrintSpeed(delay); silentHandler( silent, `{{ bold : yellow : Smooth process level }} has been set to {{ bold : green : ${delay}ms Per Character }}.` ); }; log.setSmoothPrint = (value, options = {}) => { const { silent = false } = options; setSmoothPrint(value); silentHandler( silent, `{{ bold : yellow : Smooth print }} mode has been {{ bold : ${value ? "green : ACTIVATED" : "red : DEACTIVATED"} }}.` ); }; log.setDisplayStandby = (value, options = {}) => { setDisplayStandby(value); deprecationHandler( `{{ bold : yellow : Stand by }} mode has been {{ bold : ${value ? "green : ACTIVATED" : "red : DEACTIVATED"} }}`, "setDisplayStandby()", "setDisplayStandBy()" ); queueProcessor_default(); }; log.setDisplayStandBy = (value, options = {}) => { const { silent = false } = options; setDisplayStandby(value); silentHandler( silent, `{{ bold : yellow : Stand by }} mode has been {{ bold : ${value ? "green : ACTIVATED" : "red : DEACTIVATED"} }}.` ); }; var silentHandler = (silent = false, message) => { if (!silent) { log(message, 202, "INFO", { force: true }); queueProcessor_default(); } }; var deprecationHandler = (message, before, after) => { log( `${message} [{{ bold : red : DEPRECATION WARNING }}] {{ bold : yellow : ${before} }} is deprecated. Use {{ bold : green : ${after} }} instead. It will be removed at next Major update. ` ); }; var index_default = log; //# sourceMappingURL=index.cjs.map