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
JavaScript
;
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