UNPKG

@reyalp/debug-utils

Version:

ts transformers for debug

129 lines (98 loc) 4.82 kB
import strftime from 'strftime' import { inspect } from 'util' import { _not_transformed } from './prelude' export enum LogLevel { ERROR, WARN, INFO, VERBOSE, DEBUG, SILLY } export interface LogCallChain1 { error (...messages: unknown[]): LogCallChain2 warn (...messages: unknown[]): LogCallChain2 info (...messages: unknown[]): LogCallChain2 verbose (...messages: unknown[]): LogCallChain2 debug (...messages: unknown[]): LogCallChain2 silly (...messages: unknown[]): LogCallChain2 } export interface LogCallChain2 { trace (enabled: boolean): void msg (...messages: unknown[]): LogCallChain2 dump (...exprs: unknown[]): LogCallChain2 } export class Logger implements LogCallChain1 { readonly rt: LogRuntime private constructor(readonly tags: string[], impls: Partial<LogImpls>) { this.rt = { LogLevel, ...LoggerDefaults, ...impls } } tag (...tags: string[]): LogCallChain1 { void tags; return _not_transformed() } dump (...exprs: unknown[]): LogCallChain2 { void exprs; return _not_transformed() } error (...messages: unknown[]): LogCallChain2 { void messages; return _not_transformed() } warn (...messages: unknown[]): LogCallChain2 { void messages; return _not_transformed() } info (...messages: unknown[]): LogCallChain2 { void messages; return _not_transformed() } verbose (...messages: unknown[]): LogCallChain2 { void messages; return _not_transformed() } debug (...messages: unknown[]): LogCallChain2 { void messages; return _not_transformed() } silly (...messages: unknown[]): LogCallChain2 { void messages; return _not_transformed() } extend(...args: [...tags: string[], impls: Partial<LogImpls>] | string[]) { const [tags, impls] = args.length === 0 ? [[], {}] : typeof args.at(-1) === 'string' ? [args as string[], {}] : [args.slice(0, -1) as string[], args.at(-1) as Partial<LogImpls>] return new Logger([...new Set(this.tags.concat(tags))], { ...this.rt, ...impls }) } static create(...args: [...tags: string[], impls: Partial<LogImpls>] | string[]) { const [tags, impls] = args.length === 0 ? [[], {}] : typeof args.at(-1) === 'string' ? [args as string[], {}] : [args.slice(0, -1) as string[], args.at(-1) as Partial<LogImpls>] return new Logger([...new Set(tags)], impls) } } type Location = [file: string, line: number, name: string] type LogArgs = [ll: LogLevel, tags: string[], runtime: LogRuntime, ...Location] export type LogFilter = (ll: LogLevel, tags: string[], runtime: LogRuntime) => boolean export type LogPrinter = (obj: unknown, hint: string | undefined, runtime: LogRuntime) => string export type LogWriter = (lines: string[], ...args: LogArgs) => void export type LogFormatter = (messages: string[], ...args: LogArgs) => string[] export const DefaultLogFormatter: LogFormatter = (messages, ll, tags, _rt, file, line, name) => { const where = file ? ` ${file}:${line} ${name}` : '' const label = `${strftime('%m-%d %T.%L')} ${'EWIVDS'[ll]}${tags.length ? (' (' + tags.join('|') + ')') : ''}${where}` const lines = messages.join(' ').split('\n').map(s => s.trimEnd()) if (lines.length === 0) return [label + ':'] if (lines.length === 1) return [label + ': ' + lines[0]] const indent = ' '.repeat(label.length) return lines.map((s, i) => (i ? indent : label) + (i ? '| ' : ': ') + s) } export const DefaultLogWriter: LogWriter = lines => { for (const line of lines) console.log(line) } export const DefaultLogFilterConfigs = { level: LogLevel.DEBUG, masks: {} as Record<string, boolean> } const min = LogLevel.ERROR const max = LogLevel.SILLY export function parseLogLevel(l: number | string): LogLevel | undefined { if (typeof l === 'number') { return l >= min && l <= max ? l : undefined } else { const name = l.toUpperCase() return (LogLevel as unknown as Record<string, LogLevel>)[name] } } export const DefaultLogFilter: LogFilter = (ll, tags) => { if (ll > DefaultLogFilterConfigs.level) return false if (tags.length === 0) return true for (const t of tags) { if (DefaultLogFilterConfigs.masks[t]) { return false } } return true } const _inspect = (obj: any) => inspect(obj, false, null, false) export const DefaultLogPrinter: LogPrinter = (obj, hint) => hint ? _inspect(obj) : (inspect(obj) + ` ::${hint}`) export type LogImpls = typeof LoggerDefaults export const LoggerDefaults = { filter: DefaultLogFilter, format: DefaultLogFormatter, inspect: DefaultLogPrinter, write: DefaultLogWriter, } export type LogRuntime = typeof runtime const runtime = { LogLevel, ...LoggerDefaults }