version 1.3!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

This commit is contained in:
2025-06-25 02:42:05 -04:00
parent df15f608ed
commit 5175d66eb5
5 changed files with 279 additions and 28 deletions

196
mod.ts
View File

@@ -1,14 +1,25 @@
import chalk from "chalk";
import { setImmediate } from "node:timers";
type ChalkFunction = (...msgs: unknown[]) => string;
type PrimitiveItems = unknown[];
interface UnknownConversion<T> {
condition: (arg: unknown) => boolean;
converter: (arg: T) => string;
}
/**
* A source for pretty and cool and fun logging
*/
class Logging {
/** Can I be seen by the console? */
/** Can I be seen by the console and listeners? */
visible: boolean
/** What is my name? */
source: string
/** Should I use bright colors over dull ones? */
bright: boolean = true;
/**
* Create a logging source
@@ -21,10 +32,90 @@ class Logging {
* @param silent Set to false to log a message when the logger instantiates. Useful for debugging.
* @returns A source for logging messages to the console. Functions for info, warnings, errors, debug statements, and network events are provided and have shorthands.
*/
constructor(source: string, silent?: boolean) {
constructor(source: string, silent?: boolean, bright?: boolean) {
this.visible = true;
this.source = source;
if (typeof silent == 'boolean' && !silent) this.info(`Instantiated module logging`);
if (typeof bright == 'boolean') this.bright = bright;
if (typeof silent == 'boolean' && !silent) this.info(`Instantiated logging for ${this.source}`);
}
#log(type: MessageType, chalkColor: ChalkFunction, ...msgs: PrimitiveItems) {
if (!this.visible) return;
const func = () => {
let typestr: string;
switch (type) {
case MessageType.Info:
typestr = '[INFO]';
break;
case MessageType.Warn:
typestr = '[WARN]';
break;
case MessageType.Error:
typestr = '[ERROR]';
break;
case MessageType.Debug:
typestr = '[DEBUG]';
break;
case MessageType.Network:
typestr = '[NETWORK]';
break;
default:
typestr = '[UNKNOWN]';
break;
}
const time = new Date();
let timeFormatted;
switch (LoggingConfiguration.timeFormat) {
case TimeFormat.Unix:
timeFormatted = time.getTime();
break;
case TimeFormat.Local:
timeFormatted = performance.now();
break;
default:
timeFormatted = time.toISOString();
}
const conversions = [
{
condition: arg => arg instanceof Error,
converter: arg => arg.stack || arg.message
} as UnknownConversion<Error>,
{
condition: arg => arg == null,
converter: arg => JSON.stringify(arg)
} as UnknownConversion<null>,
{
condition: arg => typeof arg == 'object',
converter: arg => JSON.stringify(arg)
} as UnknownConversion<object>,
];
function convertToString(arg: unknown) {
for (const conversion of conversions)
if (conversion.condition(arg))
return (conversion.converter as (arg: unknown) => string)(arg);
// gpt-4o idea cuz my brain has the `stupid` type
return String(arg); // fallback
}
const str = msgs.map(val => convertToString(val)).join(' ');
const msg = chalk.gray(`${timeFormatted} `) + chalkColor(chalk.inverse(`${this.source} ${typestr}`) + ` ${str}`);
console.log(msg);
try {
LoggingListeners.emit('basic', msg);
LoggingListeners.emit('type', str, type, this.source, time);
} catch (err) {
console.error(`(FALLBACK ERROR) Callback failed! Stack: ${(err as Error).stack}`);
}
}
if (LoggingConfiguration.logTiming == LogTiming.Sync) func();
else setImmediate(func);
}
/**
@@ -32,7 +123,7 @@ class Logging {
* @param type The kind of message to log
* @param msgs Your message(s)
*/
log(type: MessageType, ...msgs: string[]) {
log(type: MessageType, ...msgs: PrimitiveItems) {
if (type == MessageType.Info) this.i(...msgs);
if (type == MessageType.Warn) this.w(...msgs);
if (type == MessageType.Error) this.e(...msgs);
@@ -41,48 +132,43 @@ class Logging {
}
/** Logging Function */
i(...msgs: string[]) {this.info(...msgs);}
i(...msgs: PrimitiveItems) {this.info(...msgs);}
/** Logging Function */
info(...msgs: string[]) {
info(...msgs: PrimitiveItems) {
if (!MessageTypeVisibility.Info) return;
if (this.visible !== true) return;
console.log(chalk.gray(`${new Date().toISOString()} `) + chalk.bgWhite.black(`${this.source} [INFO]`) + chalk.whiteBright(' ' + msgs.join(' ')));
this.#log(MessageType.Info, chalk.whiteBright, ...msgs);
}
/** Logging Function */
w(...msgs: string[]) {this.warn(...msgs);}
w(...msgs: PrimitiveItems) {this.warn(...msgs);}
/** Logging Function */
warn(...msgs: string[]) {
warn(...msgs: PrimitiveItems) {
if (!MessageTypeVisibility.Warn) return;
if (this.visible !== true) return;
console.warn(chalk.gray(`${new Date().toISOString()} `) + chalk.bgYellow.black(`${this.source} [WARN]`) + chalk.yellowBright(' ' + msgs.join(' ')));
this.#log(MessageType.Warn, chalk.yellowBright, ...msgs);
}
/** Logging Function */
e(...msgs: string[]) {this.error(...msgs);}
e(...msgs: PrimitiveItems) {this.error(...msgs);}
/** Logging Function */
error(...msgs: string[]) {
error(...msgs: PrimitiveItems) {
if (!MessageTypeVisibility.Error) return;
if (this.visible !== true) return;
console.error(chalk.gray(`${new Date().toISOString()} `) + chalk.bgRed.black(`${this.source} [ERROR]`) + chalk.redBright(' ' + msgs.join(' ')));
this.#log(MessageType.Error, chalk.redBright, ...msgs);
}
/** Logging Function */
d(...msgs: string[]) {this.debug(...msgs);}
d(...msgs: PrimitiveItems) {this.debug(...msgs);}
/** Logging Function */
debug(...msgs: string[]) {
debug(...msgs: PrimitiveItems) {
if (!MessageTypeVisibility.Debug) return;
if (this.visible !== true) return;
console.debug(chalk.gray(`${new Date().toISOString()} `) + chalk.bgGreen.black(`${this.source} [DEBUG]`) + chalk.greenBright(' ' + msgs.join(' ')));
this.#log(MessageType.Debug, chalk.greenBright, ...msgs);
}
/** Logging Function */
n(...msgs: string[]) {this.network(...msgs);}
n(...msgs: PrimitiveItems) {this.network(...msgs);}
/** Logging Function */
network(...msgs: string[]) {
network(...msgs: PrimitiveItems) {
if (!MessageTypeVisibility.Network) return;
if (this.visible !== true) return;
console.log(chalk.gray(`${new Date().toISOString()} `) + chalk.bgCyan.black(`${this.source} [NETWORK]`) + chalk.cyanBright(' ' + msgs.join(' ')));
this.#log(MessageType.Network, chalk.cyanBright, ...msgs);
}
}
@@ -105,5 +191,65 @@ const MessageTypeVisibility = {
Network: true
}
export { MessageType, MessageTypeVisibility };
// 'On Message' event listeners
type BasicListener = (msg: string) => unknown;
type TypeListener = (msg: string, type: MessageType, source: string, time: Date) => unknown;
type Listener = BasicListener | TypeListener;
type ListenerType = 'basic' | 'type';
const basicListeners = new Set<Listener>();
const typeListeners = new Set<Listener>();
class ListenersBase {
onmsg(type: 'basic', cb: BasicListener): void
onmsg(type: 'type', cb: TypeListener): void
onmsg(type: ListenerType, cb: Listener) {
if (type == 'basic') basicListeners.add(cb);
else if (type == 'type') typeListeners.add(cb);
}
offmsg(type: 'basic', cb: BasicListener): void
offmsg(type: 'type', cb: TypeListener): void
offmsg(type: ListenerType, cb: Listener) {
if (type == 'basic') basicListeners.delete(cb);
else if (type == 'type') typeListeners.delete(cb);
}
emit(type: 'basic', msg: string, msgtype?: MessageType, source?: string, time?: Date): void
emit(type: 'type', msg: string, msgtype: MessageType, source: string, time: Date): void
emit(type: ListenerType, msg: string, msgtype: MessageType, source: string, time: Date) {
if (type == 'basic')
for (const cb of basicListeners) (cb as BasicListener)(msg);
if (type == 'type')
for (const cb of typeListeners) (cb as TypeListener)(msg, msgtype, source, time);
}
}
const LoggingListeners = new ListenersBase();
enum LogTiming {
Sync,
Deferred
}
enum TimeFormat {
Utc,
Unix,
Local
}
class LoggingConfigurationBase {
#timing: LogTiming = LogTiming.Sync;
#timeType: TimeFormat = TimeFormat.Utc;
get timeFormat() { return this.#timeType }
set timeFormat(data) { this.#timeType = data }
get logTiming() { return this.#timing; }
set logTiming(data) { this.#timing = data }
}
const LoggingConfiguration = new LoggingConfigurationBase();
export { MessageType, TimeFormat, LogTiming, MessageTypeVisibility, LoggingListeners, LoggingConfiguration };
export default Logging;