UNPKG

@alwatr/logger

Version:

Fancy colorful console debugger with custom scope written in tiny TypeScript, ES module.

181 lines (153 loc) 5.56 kB
import {getGlobalThis} from '@alwatr/global-this'; import {platformInfo} from '@alwatr/platform-info'; import type {AlwatrLogger} from './type.js'; const console_ = getGlobalThis().console; /** * Default debug mode state, determined by environment variables or localStorage. */ const defaultDebugMode = (() => { if (platformInfo.development) { if (platformInfo.isCli) { return process.env.ALWATR_DEBUG !== '0'; } else { return typeof localStorage !== 'undefined' && localStorage.getItem('ALWATR_DEBUG') !== '0'; } } // else return platformInfo.isCli ? Boolean(process.env.DEBUG) : typeof localStorage !== 'undefined' && localStorage.getItem('ALWATR_DEBUG') === '1'; })(); /** * A list of aesthetically pleasing colors for console logging, adapted for CLI and browser environments. */ const colorList = (() => platformInfo.isCli ? ['0;36', '0;35', '0;34', '0;33', '0;32'] // CLI-safe colors : [ '#35b997', '#f05561', '#ee224a', '#91c13e', '#22af4b', '#f0e995', '#0fe995', '#0f89ca', '#08b9a5', '#fee851', '#ee573d', '#f9df30', '#1da2dc', '#f05123', '#ee2524', ])(); /** * Platform-specific styling templates for logger output. */ const style_ = (() => ({ scope: platformInfo.isCli ? '\x1b[{{color}}m' : 'color: {{color}};', reset: platformInfo.isCli ? '\x1b[0m' : 'color: inherit;', }))(); /** * Platform-specific format for displaying the logger's scope. */ const keySection_ = (() => (platformInfo.isCli ? '%s%s%s' : '%c%s%c'))(); // --- Utility Functions --- let colorIndex_ = 0; /** * Cycles through the `colorList` to provide a new color for each logger instance. */ function getNextColor_(): string { const color = colorList[colorIndex_]; colorIndex_ = (colorIndex_ + 1) % colorList.length; return color; } /** * Sanitizes and formats the logger name string by wrapping it in brackets if not already. */ function sanitizeName_(name: string): string { if (!/^[[{<]/.test(name)) { name = `{${name}}`; } return name; } // --- Core Factory --- /** * Create a logger function for fancy console debug with custom scope. * * - `color` is optional and automatically selected from an internal list. * - `debug` is optional and automatically detected from `ALWATR_DEBUG` in localStorage or `process.env.DEBUG`. * * @example * ```ts * import {createLogger} from '@alwatr/logger'; * const logger = createLogger('my-module'); * * logger.logMethodArgs?.('myMethod', {a: 1}); // This line is ignored if debugMode is false. * ``` */ export function createLogger(name: string, forceDebugMode = defaultDebugMode): AlwatrLogger { const color = getNextColor_(); const styleScope = style_.scope.replace('{{color}}', color); const sanitizedDomain = sanitizeName_(name); /** * Logger methods that are always available, regardless of debugMode. */ const requiredItems: AlwatrLogger = { name, banner: platformInfo.isCli ? console_.log.bind(console_, `\x1b[1;37;45m {{{ %s }}} ${style_.reset}`) : console_.log.bind( console_, '%c%s', 'font-size: 2rem; background-color: #5858e8; color: #fff; padding: 1rem 4rem; border-radius: 0.5rem;', ), accident: platformInfo.isCli ? console_.warn.bind( console_, `${styleScope}⚠️\n%s\x1b[33m.%s() Accident \`%s\`!${style_.reset}`, sanitizedDomain, ) : console_.warn.bind(console_, '%c%s%c.%s() Accident `%s`!', styleScope, sanitizedDomain, style_.reset), error: platformInfo.isCli ? console_.error.bind(console_, `${styleScope}❌\n%s\x1b[31m.%s() Error \`%s\`${style_.reset}\n`, sanitizedDomain) : console_.error.bind(console_, '%c%s%c.%s() Error `%s`\n', styleScope, sanitizedDomain, style_.reset), }; if (!forceDebugMode) { return requiredItems; } /** * Logger methods available only when debugMode is true. * Using `console.debug` which is often filtered by default in browsers unless "Verbose" logs are enabled. */ return { ...requiredItems, logProperty: console_.debug.bind(console_, keySection_ + '.%s = %o;', styleScope, sanitizedDomain, style_.reset), logMethod: console_.debug.bind(console_, keySection_ + '.%s();', styleScope, sanitizedDomain, style_.reset), logFileModule: console_.debug.bind(console_, keySection_ + '/%s.js;', styleScope, sanitizedDomain, style_.reset), logMethodArgs: console_.debug.bind(console_, keySection_ + '.%s(%o);', styleScope, sanitizedDomain, style_.reset), logMethodFull: console_.debug.bind( console_, keySection_ + '.%s(%o) => %o', styleScope, sanitizedDomain, style_.reset, ), logStep: console_.debug.bind(console_, keySection_ + '.%s() -> %s', styleScope, sanitizedDomain, style_.reset), logOther: console_.debug.bind(console_, keySection_, styleScope, sanitizedDomain, style_.reset), logTable: console_.table.bind(console_), incident: platformInfo.isCli ? console_.log.bind( console_, `${styleScope}🚸\n%s${style_.reset}.%s() Incident \`%s\`!${style_.reset}`, sanitizedDomain, ) : console_.log.bind(console_, '%c%s%c.%s() Incident `%s`!', styleScope, sanitizedDomain, 'color: orange;'), time: (label: string) => console_.time(sanitizedDomain + '.' + label), timeEnd: (label: string) => console_.timeEnd(sanitizedDomain + '.' + label), }; }