diff --git a/src/semantic/router.ts b/src/semantic/router.ts index cfb317d..0dafae4 100644 --- a/src/semantic/router.ts +++ b/src/semantic/router.ts @@ -286,8 +286,7 @@ export class SemanticRouter implements RouterContext { // Add timeout to prevent hanging when no file is active try { const timeoutPromise = new Promise((_, reject) => - // eslint-disable-next-line obsidianmd/prefer-window-timers - setTimeout(() => reject(new Error('Timeout: No active file in Obsidian. Please open a file first.')), 5000) + window.setTimeout(() => reject(new Error('Timeout: No active file in Obsidian. Please open a file first.')), 5000) ); const activeResult = await Promise.race([ this.api.getActiveFile(), diff --git a/src/utils/debug.ts b/src/utils/debug.ts index 12787a0..898c8bf 100644 --- a/src/utils/debug.ts +++ b/src/utils/debug.ts @@ -10,11 +10,10 @@ export interface DebugLogger { info(message: string, ...args: unknown[]): void; } -// Indirect console reference — this is a debug utility that legitimately needs -// console access. Picking the host at runtime keeps this safe in both the -// Obsidian renderer (window) and the Jest/Node test environment (globalThis). -// eslint-disable-next-line obsidianmd/no-global-this -const _console: Console = (typeof window !== 'undefined' ? window : globalThis).console; +// Indirect console reference — this debug utility legitimately needs console +// access. Obsidian's renderer provides window; the Jest node env aliases +// window to globalThis in tests/setup.ts, so window.console resolves in both. +const _console: Console = window.console; export class Debug { private static debugEnabled = false; diff --git a/src/utils/obsidian-api.ts b/src/utils/obsidian-api.ts index 2bafd7d..090bfb9 100644 --- a/src/utils/obsidian-api.ts +++ b/src/utils/obsidian-api.ts @@ -960,9 +960,8 @@ export class ObsidianAPI { // Exponential backoff: allow time for sync processes to stabilize const delay = Math.pow(2, attempt) * baseDelayMs; Debug.log(`${operationType} failed (attempt ${attempt + 1}/${maxRetries}), retrying in ${delay}ms... Error: ${errorMessage}`); - // Backoff delay; must also work in the Jest Node test env. - // eslint-disable-next-line obsidianmd/prefer-window-timers - await new Promise(resolve => setTimeout(resolve, delay)); + // Backoff delay; window is aliased to globalThis in the Jest node env. + await new Promise(resolve => window.setTimeout(resolve, delay)); continue; } diff --git a/src/utils/session-manager.ts b/src/utils/session-manager.ts index 33524a5..52402fe 100644 --- a/src/utils/session-manager.ts +++ b/src/utils/session-manager.ts @@ -22,7 +22,7 @@ export class SessionManager extends EventEmitter { private sessions: Map = new Map(); private sessionOrder: string[] = []; // Track session order for LRU eviction private options: SessionManagerOptions; - private cleanupInterval?: ReturnType; + private cleanupInterval?: number; constructor(options: Partial = {}) { super(); @@ -37,10 +37,9 @@ export class SessionManager extends EventEmitter { * Start the session manager */ start(): void { - // Background cleanup; not tied to any popout window, and must also work - // in the Jest Node test env where `window` is undefined. - // eslint-disable-next-line obsidianmd/prefer-window-timers - this.cleanupInterval = setInterval(() => { + // Background cleanup; not tied to any popout window. The Jest node env + // aliases window to globalThis (tests/setup.ts) so window.setInterval works. + this.cleanupInterval = window.setInterval(() => { this.cleanupExpiredSessions(); }, this.options.checkInterval); @@ -52,8 +51,7 @@ export class SessionManager extends EventEmitter { */ stop(): void { if (this.cleanupInterval) { - // eslint-disable-next-line obsidianmd/prefer-window-timers - clearInterval(this.cleanupInterval); + window.clearInterval(this.cleanupInterval); this.cleanupInterval = undefined; } this.sessions.clear(); diff --git a/tests/setup.ts b/tests/setup.ts index 5f0dbaf..42ea2b8 100644 --- a/tests/setup.ts +++ b/tests/setup.ts @@ -1,5 +1,13 @@ // Jest setup file for Obsidian plugin testing +// Source code uses window.* timers and window.console (per obsidianmd's +// prefer-window-timers / no-global-this rules — Obsidian always provides +// window at runtime). The node test env has no window, so alias it to +// globalThis, which supplies setTimeout/setInterval/clearInterval/console. +if (typeof (globalThis as { window?: unknown }).window === 'undefined') { + (globalThis as { window?: unknown }).window = globalThis; +} + // Mock performance API if not available if (!global.performance) { global.performance = {