UNPKG

@proofkit/fmodata

Version:

FileMaker OData API client

117 lines (97 loc) 3.43 kB
export const TTY_COLORS = { reset: "\x1b[0m", bright: "\x1b[1m", dim: "\x1b[2m", undim: "\x1b[22m", underscore: "\x1b[4m", blink: "\x1b[5m", reverse: "\x1b[7m", hidden: "\x1b[8m", fg: { black: "\x1b[30m", red: "\x1b[31m", green: "\x1b[32m", yellow: "\x1b[33m", blue: "\x1b[34m", magenta: "\x1b[35m", cyan: "\x1b[36m", white: "\x1b[37m", }, bg: { black: "\x1b[40m", red: "\x1b[41m", green: "\x1b[42m", yellow: "\x1b[43m", blue: "\x1b[44m", magenta: "\x1b[45m", cyan: "\x1b[46m", white: "\x1b[47m", }, } as const; export type LogLevel = "debug" | "info" | "success" | "warn" | "error"; export const levels = ["debug", "info", "success", "warn", "error"] as const; export function shouldPublishLog(currentLogLevel: LogLevel, logLevel: LogLevel): boolean { return levels.indexOf(logLevel) >= levels.indexOf(currentLogLevel); } export interface Logger { disabled?: boolean | undefined; disableColors?: boolean | undefined; level?: Exclude<LogLevel, "success"> | undefined; // biome-ignore lint/suspicious/noExplicitAny: Dynamic log arguments from user code log?: ((level: Exclude<LogLevel, "success">, message: string, ...args: any[]) => void) | undefined; } export type LogHandlerParams = Parameters<NonNullable<Logger["log"]>> extends [LogLevel, ...infer Rest] ? Rest : never; const levelColors: Record<LogLevel, string> = { info: TTY_COLORS.fg.blue, success: TTY_COLORS.fg.green, warn: TTY_COLORS.fg.yellow, error: TTY_COLORS.fg.red, debug: TTY_COLORS.fg.magenta, }; const formatMessage = (level: LogLevel, message: string, colorsEnabled: boolean): string => { const timestamp = new Date().toISOString(); if (colorsEnabled) { return `${TTY_COLORS.dim}${timestamp}${TTY_COLORS.reset} ${ levelColors[level] }${level.toUpperCase()}${TTY_COLORS.reset} ${TTY_COLORS.bright}[FMODATA]:${TTY_COLORS.reset} ${message}`; } return `${timestamp} ${level.toUpperCase()} [FMODATA]: ${message}`; }; export type InternalLogger = { [K in LogLevel]: (...params: LogHandlerParams) => void; } & { get level(): LogLevel; }; export const createLogger = (options?: Logger | undefined): InternalLogger => { const enabled = options?.disabled !== true; const logLevel = options?.level ?? "error"; const colorsEnabled = options?.disableColors !== true; // biome-ignore lint/suspicious/noExplicitAny: Dynamic log arguments from user code const LogFunc = (level: LogLevel, message: string, args: any[] = []): void => { if (!(enabled && shouldPublishLog(logLevel, level))) { return; } const formattedMessage = formatMessage(level, message, colorsEnabled); if (!options || typeof options.log !== "function") { if (level === "error") { console.error(formattedMessage, ...args); } else if (level === "warn") { console.warn(formattedMessage, ...args); } else { console.log(formattedMessage, ...args); } return; } options.log(level === "success" ? "info" : level, message, ...args); }; const logger = Object.fromEntries( levels.map((level) => [level, (...[message, ...args]: LogHandlerParams) => LogFunc(level, message, args)]), ) as Record<LogLevel, (...params: LogHandlerParams) => void>; return { ...logger, get level() { return logLevel; }, }; }; export const logger = createLogger();