UNPKG

@reliverse/relinka

Version:

@reliverse/relinka is a modern and lightweight logging library.

195 lines (194 loc) 5.48 kB
import { re } from "@reliverse/relico"; const textEncoder = new TextEncoder(); const LOG_COLORS = { log: re.white, error: re.red, fatal: re.red, warn: re.yellow, info: re.blue, success: re.green, debug: re.gray, box: re.white }; const LOG_SYMBOLS = { log: "\u2502 ", error: "\u2716 ", fatal: "\u2620 ", warn: "\u26A0 ", info: "\u25A0 ", success: "\u2713 ", debug: "\u2731 ", box: "" }; let writeLock = Promise.resolve(); const formatMessage = (...args) => { const len = args.length; if (len === 0) { return ""; } if (len === 1) { return String(args[0]); } return args.map(String).join(" "); }; const createPrefixedMessage = (level, message) => { const symbol = LOG_SYMBOLS[level]; if (symbol === "") { return message; } return symbol + message; }; const formatBox = (message) => { const lines = message.split("\n"); const lineCount = lines.length; if (lineCount === 0) { return "\u250C\u2500\u2500\u2510\n\u2502 \u2502\n\u2514\u2500\u2500\u2518\n"; } let maxWidth = 0; for (let i = 0; i < lineCount; i++) { const line = lines[i]; if (line === void 0) { continue; } const len = line.length; if (len > maxWidth) { maxWidth = len; } } const padding = 2; const width = maxWidth + padding * 2; const horizontal = "\u2500".repeat(width); const top = `\u250C${horizontal}\u2510 `; const bottom = `\u2514${horizontal}\u2518 `; const leftPadding = " ".repeat(padding); const rightPadding = " ".repeat(padding); if (maxWidth === 0) { return `${top}\u2502${" ".repeat(width)}\u2502 ${bottom}`; } let content = ""; for (let i = 0; i < lineCount; i++) { const line = lines[i]; if (line === void 0) { continue; } const padded = line.padEnd(maxWidth); content += `\u2502${leftPadding}${padded}${rightPadding}\u2502 `; } return `${top}${content}${bottom}`; }; const writeAsync = async (text, isError = false) => { const encoded = textEncoder.encode(`${text} `); const stream = isError ? Bun.stderr : Bun.stdout; writeLock = writeLock.then(async () => { await Bun.write(stream, encoded); }); }; const writeSync = (text, isError = false) => { const encoded = textEncoder.encode(`${text} `); (isError ? process.stderr : process.stdout).write(encoded); }; const writeColoredAsync = (text, color, isError = false) => { const coloredText = color(text); return writeAsync(coloredText, isError); }; const writeColoredSync = (text, color, isError = false) => { const coloredText = color(text); writeSync(coloredText, isError); }; function createLogMethod(level, isAsync, isError = false) { const color = LOG_COLORS[level]; const isBox = level === "box"; if (isAsync) { return (...args) => { const message = formatMessage(...args); const formattedMessage = isBox ? formatBox(message) : createPrefixedMessage(level, message); return writeColoredAsync(formattedMessage, color, isError); }; } return (...args) => { const message = formatMessage(...args); const formattedMessage = isBox ? formatBox(message) : createPrefixedMessage(level, message); writeColoredSync(formattedMessage, color, isError); }; } function createRawMethod(isAsync) { if (isAsync) { return (...args) => { const message = formatMessage(...args); return writeAsync(message); }; } return (...args) => { const message = formatMessage(...args); writeSync(message); }; } const createCallableLogger = (methods) => { const callable = ((level, ...args) => { const method = methods[level]; if (method) { method(...args); return; } methods.log(...args); }); callable.log = methods.log; callable.error = methods.error; callable.fatal = methods.fatal; callable.warn = methods.warn; callable.info = methods.info; callable.success = methods.success; callable.debug = methods.debug; callable.box = methods.box; callable.raw = methods.raw; return callable; }; const createCallableLoggerAsync = (methods) => { const callable = ((level, ...args) => { const method = methods[level]; if (method) { return method(...args); } return methods.log(...args); }); callable.log = methods.log; callable.error = methods.error; callable.fatal = methods.fatal; callable.warn = methods.warn; callable.info = methods.info; callable.success = methods.success; callable.debug = methods.debug; callable.box = methods.box; callable.raw = methods.raw; return callable; }; const loggerMethods = { log: createLogMethod("log", false), error: createLogMethod("error", false, true), fatal: createLogMethod("fatal", false, true), warn: createLogMethod("warn", false), info: createLogMethod("info", false), success: createLogMethod("success", false), debug: createLogMethod("debug", false), box: createLogMethod("box", false), raw: createRawMethod(false) }; const relinkaMethods = { log: createLogMethod("log", true), error: createLogMethod("error", true, true), fatal: createLogMethod("fatal", true, true), warn: createLogMethod("warn", true), info: createLogMethod("info", true), success: createLogMethod("success", true), debug: createLogMethod("debug", true), box: createLogMethod("box", true), raw: createRawMethod(true) }; export const logger = createCallableLogger(loggerMethods); export const relinka = createCallableLoggerAsync(relinkaMethods);