diff --git a/extension/src/background.ts b/extension/src/background.ts index 40645536..29b0aace 100644 --- a/extension/src/background.ts +++ b/extension/src/background.ts @@ -3,7 +3,7 @@ import browser from "webextension-polyfill" import type {BrowserAction, Menus, PageAction, Runtime, Tabs, WebNavigation} from "webextension-polyfill" import type {Url, SearchPageParams} from './common' -import {Visit, Visits, Blacklisted, Methods, uuid} from './common' +import {Visit, Visits, Blacklisted, Methods, assert, uuid} from './common' import type {Options} from './options' import {Toggles, getOptions, setOption, THIS_BROWSER_TAG} from './options' @@ -666,7 +666,10 @@ export async function handleToggleSidebar() { function registerActions() { // NOTE: on mobile, this sets action for both icon (if it's displayed) and in the menu for (const action of actions()) { - action.onClicked.addListener(defensify(toggleSidebarOnTab, 'action.onClicked')) + action.onClicked.addListener(defensify( + (tab: Tabs.Tab) => toggleSidebarOnTab({url: tab.url!, id: tab.id!}), + 'action.onClicked', + )) } } @@ -689,12 +692,6 @@ const onCommandCallback = defensify(async cmd => { }, 'onCommand') -type MenuInfo = { - menuItemId: string, - linkUrl?: string, -} - - async function active(): Promise { return (await getActiveTab())! } @@ -844,7 +841,7 @@ ${surl} }, ) }, - onMenuClick: async function(info: MenuInfo, _tab: Tabs.Tab) { + onMenuClick: async function(info: Menus.OnClickData, _tab: Tabs.Tab) { const url = info.linkUrl! await AddToMarkVisitedExcludelist.add([url]) }, @@ -858,7 +855,7 @@ const DEFAULT_CONTEXTS: Array = ['page', 'browser_action'] type MenuEntry = { id: string, title: string, - callback: ((info: MenuInfo, tab: Tabs.Tab) => Promise) | null, + callback: ((info: Menus.OnClickData, tab: Tabs.Tab) => Promise) | null, contexts?: Array, // NOTE: not present interpreted as DEFAULT_CONTEXTS parentId?: string, } @@ -977,7 +974,8 @@ function initContextMenus(): void { }) // need to keep these callbacks here, since onInstalled above isn't called when background page resumes - const onMenuClickedCallback = defensify(async (info: MenuInfo, tab: Tabs.Tab) => { + const onMenuClickedCallback = defensify(async (info: Menus.OnClickData, tab: Tabs.Tab | undefined) => { + assert(tab != null) const mid = info.menuItemId for (const m of [...MENUS, ...TOGGLES]) { if (mid == m.id) { diff --git a/extension/src/common.ts b/extension/src/common.ts index d6220e9e..06de18d1 100644 --- a/extension/src/common.ts +++ b/extension/src/common.ts @@ -326,3 +326,11 @@ export function getOrDefault(obj: any, key: string, def: T): T { const res = obj[key]; return res === undefined ? def : res; } + + +// js doesn't have builtin assert :( +export function assert(condition: any, msg?: string): asserts condition { + if (!condition) { + throw new Error(`assertion failed ${msg}`) + } +} diff --git a/extension/src/notifications.ts b/extension/src/notifications.ts index 0036d6e7..8469f096 100644 --- a/extension/src/notifications.ts +++ b/extension/src/notifications.ts @@ -42,10 +42,12 @@ export function alertError(obj: any) { } -// TODO see if I can define a typescript tyoe.. -// @ts-expect-error -export function defensify(pf: (...any) => Promise, name: string): (...any) => Promise { - const fname = pf.name // hopefully it's always present? +type DefensifyArgs = readonly unknown[] +export function defensify( + pf: (...args: Args) => Promise, + name: string, +): (...args: Args) => Promise { + const fname = pf.name // hopefully it's always present? const error_handler = (err: Error) => { console.error('function "%s" %s failed: %o', fname, name, err) getOptions().then((opts: Options) => { @@ -56,17 +58,18 @@ export function defensify(pf: (...any) => Promise, name: string): (...any) } }) } - return (...args) => pf(...args).then(() => { + return (...args: Args) => pf(...args).then(() => { // suppress return values, since the defensive error handler 'erases; the type anyway' return }).catch(error_handler) } -// TODO return type should be void here too... -// @ts-expect-error -export function defensifyAlert(pf: (...any) => Promise): (any) => Promise { - return (...args) => pf(...args).catch(alertError); +type DefensifyAlertArgs = readonly unknown[] +export function defensifyAlert( + pf: (...args: Args) => Promise, +): (...args: Args) => Promise { + return (...args) => pf(...args).catch(alertError) } diff --git a/extension/tsconfig.json b/extension/tsconfig.json index 149d1033..da715852 100644 --- a/extension/tsconfig.json +++ b/extension/tsconfig.json @@ -10,6 +10,9 @@ "moduleResolution": "bundler", // esnext is necessary, otherwise bundler module resolution can't be used? "module": "esnext", + + // without it, emacs (LSP?) complains when editing files.. not sure if impacts actual code generation? + "lib": ["es6", "dom"], }, "include": [ "./src/**/*.ts"