diff --git a/src/consola.ts b/src/consola.ts index baefd8fb..ca9aa35f 100644 --- a/src/consola.ts +++ b/src/consola.ts @@ -82,6 +82,10 @@ export class Consola { // Track of last log this._lastLog = {}; + + // Prevent infinite loop on logging + // Issue: https://github.com/unjs/consola/issues/298 + this._logFn = _preventLoop(this._logFn).bind(this); } /** @@ -474,6 +478,24 @@ function _normalizeLogLevel( return defaultLevel; } +function _preventLoop any>(fn: T): T { + let doing = false; + return function (...args) { + if (doing) { + return false; + } + doing = true; + try { + const result = fn.apply(this, args); + doing = false; + return result; + } catch (error) { + doing = false; + throw error; + } + } as T; +} + export interface LogFn { (message: InputLogObject | any, ...args: any[]): void; raw: (...args: any[]) => void; diff --git a/test/consola.test.ts b/test/consola.test.ts index ae9e177f..32c5be17 100644 --- a/test/consola.test.ts +++ b/test/consola.test.ts @@ -56,6 +56,30 @@ describe("consola", () => { expect(logs.at(-1)!.args).toEqual(["SPAM", "(repeated 4 times)"]); }); + + test("should avoid infinite loop", () => { + const logs: LogObject[] = []; + const TestReporter: ConsolaReporter = { + log(logObj) { + logs.push(logObj); + }, + }; + const consola = createConsola({ + reporters: [TestReporter], + }); + + consola.wrapConsole(); + const obj = { + get value() { + console.warn(obj); + return "anything"; + }, + }; + consola.warn(obj); + consola.restoreConsole(); + + expect(logs.length).toBe(1); + }); }); function wait(delay) {