@nanocollective/nanocoder
Version:
A local-first CLI coding agent that brings the power of agentic coding tools like Claude Code and Gemini CLI to local models or controlled APIs like OpenRouter
172 lines • 7.57 kB
JavaScript
/**
* Shared factory function for creating log methods with specific levels
* Used across different logger implementations to reduce code duplication
*/
// Type guard to check if a logger has a specific level method
// biome-ignore lint/suspicious/noExplicitAny: Generic logger type
function hasLevelMethod(logger, level) {
return logger && typeof logger[level] === 'function';
}
/**
* Factory function to create log method with specific level
* Returns overloaded function matching Logger interface
*
* @param logger - The underlying logger instance (Pino, console, etc.)
* @param level - The log level ('info', 'error', 'warn', etc.)
* @param options - Optional configuration for the log method
* @returns An overloaded log method that accepts both string-first and object-first signatures
*/
// biome-ignore lint/suspicious/noExplicitAny: Generic logger type parameter
export function createLogMethod(logger, level, options) {
const { contextPrefix, consolePrefix, consoleMethod, transformArgs, transformResult, } = options || {};
// Create overloaded function
const logMethod = (msgOrObj, ...args) => {
try {
// Handle console prefix fallback case
if (consolePrefix && consoleMethod && logger === console) {
// This is for fallback logger with console prefixes
if (typeof msgOrObj === 'object' && msgOrObj !== null) {
// Object first: (obj: object, msg?: string) => void
const obj = msgOrObj;
const msg = args[0];
// biome-ignore lint/suspicious/noExplicitAny: Dynamic console method access
console[consoleMethod](`[${consolePrefix}]`, msg || '', obj);
}
else {
// String first: (msg: string, ...args: unknown[]) => void
const msg = msgOrObj;
const restArgs = args.slice(1);
// biome-ignore lint/suspicious/noExplicitAny: Dynamic console method access
console[consoleMethod](`[${consolePrefix}]`, msg, ...restArgs);
}
return;
}
// Transform arguments if needed
const transformedArgs = transformArgs
? transformArgs(args, typeof msgOrObj === 'string' ? msgOrObj : undefined)
: args;
if (typeof msgOrObj === 'object' && msgOrObj !== null) {
// Object first: (obj: object, msg?: string) => void
const obj = msgOrObj;
const msg = transformedArgs[0];
// Call the logger with object and optional message
if (hasLevelMethod(logger, level)) {
// biome-ignore lint/suspicious/noExplicitAny: Dynamic logger method access
const result = logger[level](msg || '', obj);
if (transformResult) {
transformResult(result);
}
}
}
else {
// String first: (msg: string, ...args: unknown[]) => void
const msg = msgOrObj;
// Add context prefix if specified
const finalMsg = contextPrefix ? `[${contextPrefix}] ${msg}` : msg;
// Call the logger with message and additional args
if (hasLevelMethod(logger, level)) {
// biome-ignore lint/suspicious/noExplicitAny: Dynamic logger method access
const result = logger[level](finalMsg, ...transformedArgs);
if (transformResult) {
transformResult(result);
}
}
}
}
catch (error) {
// Fallback to console if logger method fails
const fallbackLevel = level === 'trace' ? 'log' : level;
const consoleMethod = console[fallbackLevel];
if (typeof consoleMethod === 'function') {
consoleMethod('Logger method failed:', {
level,
error: error instanceof Error ? error.message : String(error),
message: msgOrObj,
args,
});
}
}
};
// Return the method with both overloads
return logMethod;
}
/**
* Create a set of log methods for all standard levels
*
* @param logger - The underlying logger instance
* @param options - Optional configuration for all log methods
* @returns An object containing log methods for all standard levels
*/
// biome-ignore lint/suspicious/noExplicitAny: Generic logger type parameter
export function createLogMethods(logger, options) {
const { contextPrefix, transformArgs, transformResult, consolePrefix, consoleMethod, } = options || {};
// Level-specific argument transformers if needed
const createTransformer = (level) => {
return (args, msg) => {
if (transformArgs) {
return transformArgs(args, level, msg);
}
return args;
};
};
const createResultTransformer = (level) => {
// biome-ignore lint/suspicious/noExplicitAny: Generic result type
return (result) => {
if (transformResult) {
transformResult(result, level);
}
};
};
return {
fatal: createLogMethod(logger, 'fatal', {
contextPrefix: contextPrefix ? 'FATAL' : undefined,
consolePrefix,
consoleMethod,
transformArgs: createTransformer('fatal'),
transformResult: createResultTransformer('fatal'),
}),
error: createLogMethod(logger, 'error', {
contextPrefix: contextPrefix ? 'ERROR' : undefined,
consolePrefix,
consoleMethod,
transformArgs: createTransformer('error'),
transformResult: createResultTransformer('error'),
}),
warn: createLogMethod(logger, 'warn', {
contextPrefix: contextPrefix ? 'WARN' : undefined,
consolePrefix,
consoleMethod,
transformArgs: createTransformer('warn'),
transformResult: createResultTransformer('warn'),
}),
info: createLogMethod(logger, 'info', {
contextPrefix: contextPrefix ? 'INFO' : undefined,
consolePrefix,
consoleMethod,
transformArgs: createTransformer('info'),
transformResult: createResultTransformer('info'),
}),
http: createLogMethod(logger, 'http', {
contextPrefix: contextPrefix ? 'HTTP' : undefined,
consolePrefix,
consoleMethod,
transformArgs: createTransformer('http'),
transformResult: createResultTransformer('http'),
}),
debug: createLogMethod(logger, 'debug', {
contextPrefix: contextPrefix ? 'DEBUG' : undefined,
consolePrefix,
consoleMethod,
transformArgs: createTransformer('debug'),
transformResult: createResultTransformer('debug'),
}),
trace: createLogMethod(logger, 'trace', {
contextPrefix: contextPrefix ? 'TRACE' : undefined,
consolePrefix,
consoleMethod,
transformArgs: createTransformer('trace'),
transformResult: createResultTransformer('trace'),
}),
};
}
//# sourceMappingURL=log-method-factory.js.map