@reliverse/relinka
Version:
@reliverse/relinka is a modern and lightweight logging library.
195 lines (194 loc) • 5.48 kB
JavaScript
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);