From e1448d8ea2b275d5d3c52f5d7bd36f13447187d2 Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Fri, 11 Sep 2026 15:08:05 -0400 Subject: [PATCH] Document intentional empty catches, fix one real gap, allow == null in eqeqeq (#44) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ESLint flagged ~20 empty catch blocks and 4 loose-equality comparisons in assets/js/. Auditing each: all ~19 remaining empty catches are localStorage/sessionStorage access (persisted tab/theme/column- visibility state, recent command-palette entries) or the terminal beep's AudioContext calls — genuinely intentional best-effort UX affordances that must silently no-op if storage is disabled/full or audio is blocked, not oversights. One (a viewport-change listener callback) was a real gap: swallowing an arbitrary caller-supplied callback's exception could hide a genuine bug, so that one now logs via console.error instead. Documented the storage/audio convention once in a file-level comment rather than repeating the same explanation on ~19 near-identical one-line try/catches. All 4 flagged loose-equality comparisons turned out to be `== null`/`!= null` checks — the one loose-equality idiom that's deliberately safe (catches both null and undefined in one comparison; ESLint's own eqeqeq rule has a "smart" mode specifically for this). Converting them to strict equality would have been a behavior change (no longer catching undefined), not a fix, so switched .eslintrc.json's eqeqeq rule to "smart" instead — flags every other loose comparison as before, correctly stops flagging this one safe idiom. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01Lhz7pGMaoTfL5sdYS5XiKv --- .eslintrc.json | 2 +- assets/js/base.js | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 3f36631..bf1e71d 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -20,6 +20,6 @@ "no-useless-escape": "warn", "no-regex-spaces": "warn", "semi": ["error", "always"], - "eqeqeq": "warn" + "eqeqeq": ["warn", "smart"] } } diff --git a/assets/js/base.js b/assets/js/base.js index 397c58f..9778205 100644 --- a/assets/js/base.js +++ b/assets/js/base.js @@ -41,6 +41,16 @@ * 32. Drag & Drop Upload * 33. Intersection Observer * 34. Full Initialisation + * + * NOTE ON EMPTY CATCH BLOCKS: throughout this file, `try { ... } catch (_) {}` + * around localStorage/sessionStorage access (persisted tab/theme/column- + * visibility state, recent command-palette entries, etc.) and the terminal + * beep's AudioContext calls is intentional, not an oversight — these are + * best-effort UX affordances that must silently no-op rather than break the + * surrounding feature if storage is disabled/full (private browsing, quota) + * or audio is blocked (autoplay policy). Swallowing errors from arbitrary + * caller-supplied callbacks (e.g. viewport-change listeners) is handled + * separately with real logging, since those can hide genuine bugs. */ (function (global) { @@ -1398,7 +1408,7 @@ _vpCurrent = bp; if (bp !== prev) { const evt = { bp, w, h, prev }; - _vpListeners.forEach(cb => { try { cb(evt); } catch (_) {} }); + _vpListeners.forEach(cb => { try { cb(evt); } catch (e) { console.error('[lt.viewport] listener threw:', e); } }); bus.emit('viewport:change', evt); } }