From f174f1f2382cb9c96307acbbfaff989b41c779b7 Mon Sep 17 00:00:00 2001 From: Graham Langford Date: Wed, 1 May 2024 12:51:27 -0500 Subject: [PATCH] moves rest of exported backgroudn contextMenu functions to separate files --- src/background/background.ts | 2 +- .../initContextMenus.test.ts} | 2 +- .../initContextMenus.ts} | 70 +------------------ .../contextMenus/preloadContextMenus.ts | 61 ++++++++++++++++ .../contextMenus/uninstallContextMenu.ts | 45 ++++++++++++ src/background/messenger/api.ts | 5 -- src/background/messenger/registration.ts | 7 +- src/background/messenger/strict/api.ts | 4 ++ .../messenger/strict/registration.ts | 3 + src/background/modUpdater.test.ts | 2 +- src/background/modUpdater.ts | 2 +- src/background/removeExtensionForEveryTab.ts | 2 +- src/contentScript/contentScriptPlatform.ts | 2 +- .../contextMenu/contextMenu.test.ts | 6 +- src/tsconfig.strictNullChecks.json | 1 + 15 files changed, 127 insertions(+), 87 deletions(-) rename src/background/{contextMenus.test.ts => contextMenus/initContextMenus.test.ts} (97%) rename src/background/{contextMenus.ts => contextMenus/initContextMenus.ts} (59%) create mode 100644 src/background/contextMenus/preloadContextMenus.ts create mode 100644 src/background/contextMenus/uninstallContextMenu.ts diff --git a/src/background/background.ts b/src/background/background.ts index 0a05f3ab4b..1c0b710bdc 100644 --- a/src/background/background.ts +++ b/src/background/background.ts @@ -30,7 +30,7 @@ import registerMessenger from "@/background/messenger/registration"; import registerMessengerStrict from "@/background/messenger/strict/registration"; import registerExternalMessenger from "@/background/messenger/external/registration"; import initLocator from "@/background/locator"; -import initContextMenus from "@/background/contextMenus"; +import initContextMenus from "@/background/contextMenus/initContextMenus"; import initBrowserAction from "@/background/browserAction"; import initInstaller from "@/background/installer"; import initNavigation from "@/background/navigation"; diff --git a/src/background/contextMenus.test.ts b/src/background/contextMenus/initContextMenus.test.ts similarity index 97% rename from src/background/contextMenus.test.ts rename to src/background/contextMenus/initContextMenus.test.ts index d2a6b30aa5..561221ea4a 100644 --- a/src/background/contextMenus.test.ts +++ b/src/background/contextMenus/initContextMenus.test.ts @@ -15,7 +15,6 @@ * along with this program. If not, see . */ -import { preloadContextMenus } from "@/background/contextMenus"; import extensionPointRegistry from "@/starterBricks/registry"; import { fromJS } from "@/starterBricks/contextMenu/contextMenu"; import * as backgroundApi from "@/background/messenger/strict/api"; @@ -31,6 +30,7 @@ import { type ContextMenuConfig, } from "@/starterBricks/contextMenu/types"; import { ensureContextMenu } from "@/background/contextMenus/ensureContextMenu"; +import { preloadContextMenus } from "@/background/contextMenus/preloadContextMenus"; TEST_setContext("background"); diff --git a/src/background/contextMenus.ts b/src/background/contextMenus/initContextMenus.ts similarity index 59% rename from src/background/contextMenus.ts rename to src/background/contextMenus/initContextMenus.ts index 7de0878174..3e2a5c9766 100644 --- a/src/background/contextMenus.ts +++ b/src/background/contextMenus/initContextMenus.ts @@ -20,20 +20,12 @@ import { type Menus, type Tabs } from "webextension-polyfill"; import { handleMenuAction, notify } from "@/contentScript/messenger/strict/api"; import { waitForContentScript } from "@/background/contentScript"; import { expectContext } from "@/utils/expectContext"; -import extensionPointRegistry from "@/starterBricks/registry"; -import { ContextMenuStarterBrickABC } from "@/starterBricks/contextMenu/contextMenu"; import { getModComponentState } from "@/store/extensionsStorage"; import { resolveExtensionInnerDefinitions } from "@/registry/internal"; import { type UUID } from "@/types/stringTypes"; -import { - type ModComponentBase, - type ResolvedModComponent, -} from "@/types/modComponentTypes"; import { allSettled } from "@/utils/promiseUtils"; -import { ContextError } from "@/errors/genericErrors"; -import { selectEventData } from "@/telemetry/deployments"; -import { type ContextMenuConfig } from "@/starterBricks/contextMenu/types"; -import { MENU_PREFIX, makeMenuId } from "@/background/contextMenus/makeMenuId"; +import { MENU_PREFIX } from "@/background/contextMenus/makeMenuId"; +import { preloadContextMenus } from "@/background/contextMenus/preloadContextMenus"; // This constant must be high enough to give Chrome time to inject the content script. waitForContentScript can take // >= 1 seconds because it also waits for the content script to be ready @@ -89,64 +81,6 @@ function menuListener(info: Menus.OnClickData, tab: Tabs.Tab) { } } -/** - * Uninstall the contextMenu UI for `extensionId` from browser context menu on all tabs. - * - * Safe to call on non-context menu extension ids. - * - * @returns true if the contextMenu was removed, or false if the contextMenu was not found. - */ -export async function uninstallContextMenu({ - extensionId, -}: { - extensionId: UUID; -}): Promise { - try { - await browser.contextMenus.remove(makeMenuId(extensionId)); - console.debug(`Uninstalled context menu ${extensionId}`); - return true; - } catch (error) { - // Will throw if extensionId doesn't refer to a context menu. The callers don't have an easy way to check the type - // without having to resolve the extensionPointId. So instead we'll just expect some of the calls to fail. - console.debug("Could not uninstall context menu %s", extensionId, { - error, - }); - return false; - } -} - -/** - * Add context menu items to the Chrome context menu on all tabs, in anticipation that on Page Load, the content - * script will register a handler for the item. - * @param extensions the ModComponent to preload. - */ -export async function preloadContextMenus( - extensions: ModComponentBase[], -): Promise { - expectContext("background"); - const promises = extensions.map(async (definition) => { - const resolved = await resolveExtensionInnerDefinitions(definition); - - const extensionPoint = await extensionPointRegistry.lookup( - resolved.extensionPointId, - ); - if (extensionPoint instanceof ContextMenuStarterBrickABC) { - await extensionPoint.registerMenuItem( - definition as unknown as ResolvedModComponent, - () => { - throw new ContextError( - "Context menu was preloaded, but no handler was registered", - { - context: selectEventData(resolved), - }, - ); - }, - ); - } - }); - await allSettled(promises, { catch: "ignore" }); -} - async function preloadAllContextMenus(): Promise { const { extensions } = await getModComponentState(); const { fulfilled } = await allSettled( diff --git a/src/background/contextMenus/preloadContextMenus.ts b/src/background/contextMenus/preloadContextMenus.ts new file mode 100644 index 0000000000..41e563950d --- /dev/null +++ b/src/background/contextMenus/preloadContextMenus.ts @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2024 PixieBrix, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { ContextError } from "@/errors/genericErrors"; +import { resolveExtensionInnerDefinitions } from "@/registry/internal"; +import { ContextMenuStarterBrickABC } from "@/starterBricks/contextMenu/contextMenu"; +import { type ContextMenuConfig } from "@/starterBricks/contextMenu/types"; +import { selectEventData } from "@/telemetry/deployments"; +import { + type ModComponentBase, + type ResolvedModComponent, +} from "@/types/modComponentTypes"; +import { expectContext } from "@/utils/expectContext"; +import { allSettled } from "@/utils/promiseUtils"; +import extensionPointRegistry from "@/starterBricks/registry"; + +/** + * Add context menu items to the Chrome context menu on all tabs, in anticipation that on Page Load, the content + * script will register a handler for the item. + * @param extensions the ModComponent to preload. + */ +export async function preloadContextMenus( + extensions: ModComponentBase[], +): Promise { + expectContext("background"); + const promises = extensions.map(async (definition) => { + const resolved = await resolveExtensionInnerDefinitions(definition); + + const extensionPoint = await extensionPointRegistry.lookup( + resolved.extensionPointId, + ); + if (extensionPoint instanceof ContextMenuStarterBrickABC) { + await extensionPoint.registerMenuItem( + definition as unknown as ResolvedModComponent, + () => { + throw new ContextError( + "Context menu was preloaded, but no handler was registered", + { + context: selectEventData(resolved), + }, + ); + }, + ); + } + }); + await allSettled(promises, { catch: "ignore" }); +} diff --git a/src/background/contextMenus/uninstallContextMenu.ts b/src/background/contextMenus/uninstallContextMenu.ts new file mode 100644 index 0000000000..9329ff29cf --- /dev/null +++ b/src/background/contextMenus/uninstallContextMenu.ts @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2024 PixieBrix, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { makeMenuId } from "@/background/contextMenus/makeMenuId"; +import { type UUID } from "@/types/stringTypes"; + +/** + * Uninstall the contextMenu UI for `extensionId` from browser context menu on all tabs. + * + * Safe to call on non-context menu extension ids. + * + * @returns true if the contextMenu was removed, or false if the contextMenu was not found. + */ +export async function uninstallContextMenu({ + extensionId, +}: { + extensionId: UUID; +}): Promise { + try { + await browser.contextMenus.remove(makeMenuId(extensionId)); + console.debug(`Uninstalled context menu ${extensionId}`); + return true; + } catch (error) { + // Will throw if extensionId doesn't refer to a context menu. The callers don't have an easy way to check the type + // without having to resolve the extensionPointId. So instead we'll just expect some of the calls to fail. + console.debug("Could not uninstall context menu %s", extensionId, { + error, + }); + return false; + } +} diff --git a/src/background/messenger/api.ts b/src/background/messenger/api.ts index 1d156fefe4..eb76fc9796 100644 --- a/src/background/messenger/api.ts +++ b/src/background/messenger/api.ts @@ -34,11 +34,6 @@ export const removeExtensionForEveryTab = getNotifier( export const clearServiceCache = getMethod("CLEAR_SERVICE_CACHE", bg); -/** - * Uninstall context menu and return whether the context menu was uninstalled. - */ -export const uninstallContextMenu = getMethod("UNINSTALL_CONTEXT_MENU", bg); - export const requestRun = { inOpener: getMethod("REQUEST_RUN_IN_OPENER", bg), inTarget: getMethod("REQUEST_RUN_IN_TARGET", bg), diff --git a/src/background/messenger/registration.ts b/src/background/messenger/registration.ts index 5e0dbe0109..6d001c1bf4 100644 --- a/src/background/messenger/registration.ts +++ b/src/background/messenger/registration.ts @@ -24,10 +24,6 @@ import { registerMethods } from "webext-messenger"; import { expectContext } from "@/utils/expectContext"; -import { - preloadContextMenus, - uninstallContextMenu, -} from "@/background/contextMenus"; // 201 strictNullCheck errors import { requestRunInAllFrames, requestRunInOtherTabs, @@ -39,13 +35,13 @@ import { removeExtensionForEveryTab } from "@/background/removeExtensionForEvery import { debouncedActivateStarterMods as installStarterBlueprints } from "@/background/starterMods"; // 209 strictNullCheck errors import { setCopilotProcessData } from "@/background/partnerHandlers"; // Depends on contentScript/messenger to pass strictNullCheck +import { preloadContextMenus } from "@/background/contextMenus/preloadContextMenus"; // 197 strictNullCheck errors expectContext("background"); declare global { interface MessengerMethods { PRELOAD_CONTEXT_MENUS: typeof preloadContextMenus; - UNINSTALL_CONTEXT_MENU: typeof uninstallContextMenu; SET_PARTNER_COPILOT_DATA: typeof setCopilotProcessData; @@ -68,7 +64,6 @@ export default function registerMessenger(): void { INSTALL_STARTER_BLUEPRINTS: installStarterBlueprints, PRELOAD_CONTEXT_MENUS: preloadContextMenus, - UNINSTALL_CONTEXT_MENU: uninstallContextMenu, REMOVE_EXTENSION_EVERY_TAB: removeExtensionForEveryTab, diff --git a/src/background/messenger/strict/api.ts b/src/background/messenger/strict/api.ts index a01040d581..00804515ae 100644 --- a/src/background/messenger/strict/api.ts +++ b/src/background/messenger/strict/api.ts @@ -125,3 +125,7 @@ export const initTelemetry = getNotifier("INIT_TELEMETRY", bg); export const sendDeploymentAlert = getNotifier("SEND_DEPLOYMENT_ALERT", bg); export const ensureContextMenu = getMethod("ENSURE_CONTEXT_MENU", bg); +/** + * Uninstall context menu and return whether the context menu was uninstalled. + */ +export const uninstallContextMenu = getMethod("UNINSTALL_CONTEXT_MENU", bg); diff --git a/src/background/messenger/strict/registration.ts b/src/background/messenger/strict/registration.ts index d6c163173f..b13a18fe10 100644 --- a/src/background/messenger/strict/registration.ts +++ b/src/background/messenger/strict/registration.ts @@ -65,6 +65,7 @@ import { sendDeploymentAlert, } from "@/background/telemetry"; import { ensureContextMenu } from "@/background/contextMenus/ensureContextMenu"; +import { uninstallContextMenu } from "@/background/contextMenus/uninstallContextMenu"; expectContext("background"); @@ -126,6 +127,7 @@ declare global { SEND_DEPLOYMENT_ALERT: typeof sendDeploymentAlert; ENSURE_CONTEXT_MENU: typeof ensureContextMenu; + UNINSTALL_CONTEXT_MENU: typeof uninstallContextMenu; } } @@ -187,5 +189,6 @@ export default function registerMessenger(): void { SEND_DEPLOYMENT_ALERT: sendDeploymentAlert, ENSURE_CONTEXT_MENU: ensureContextMenu, + UNINSTALL_CONTEXT_MENU: uninstallContextMenu, }); } diff --git a/src/background/modUpdater.test.ts b/src/background/modUpdater.test.ts index 9984cd2fd2..f26ca220c7 100644 --- a/src/background/modUpdater.test.ts +++ b/src/background/modUpdater.test.ts @@ -42,7 +42,7 @@ import extensionsSlice from "@/store/extensionsSlice"; import { sharingDefinitionFactory } from "@/testUtils/factories/registryFactories"; import type { ModDefinition } from "@/types/modDefinitionTypes"; import type { ActivatedModComponent } from "@/types/modComponentTypes"; -import { uninstallContextMenu } from "@/background/contextMenus"; +import { uninstallContextMenu } from "@/background/contextMenus/uninstallContextMenu"; import { TEST_deleteFeatureFlagsCache } from "@/auth/featureFlagStorage"; const axiosMock = new MockAdapter(axios); diff --git a/src/background/modUpdater.ts b/src/background/modUpdater.ts index a751660b09..a4c8c61ffd 100644 --- a/src/background/modUpdater.ts +++ b/src/background/modUpdater.ts @@ -38,7 +38,7 @@ import type { } from "@/types/modComponentTypes"; import { collectModOptions } from "@/store/extensionsUtils"; import type { ModComponentState } from "@/store/extensionsTypes"; -import { uninstallContextMenu } from "@/background/contextMenus"; +import { uninstallContextMenu } from "@/background/contextMenus/uninstallContextMenu"; import collectExistingConfiguredDependenciesForMod from "@/integrations/util/collectExistingConfiguredDependenciesForMod"; import { flagOn } from "@/auth/featureFlagStorage"; diff --git a/src/background/removeExtensionForEveryTab.ts b/src/background/removeExtensionForEveryTab.ts index 9067b5f522..2b69e7dc44 100644 --- a/src/background/removeExtensionForEveryTab.ts +++ b/src/background/removeExtensionForEveryTab.ts @@ -5,7 +5,7 @@ import { import { removeSidebars } from "@/contentScript/messenger/strict/api"; import { forEachTab } from "@/utils/extensionUtils"; import { type UUID } from "@/types/stringTypes"; -import { uninstallContextMenu } from "./contextMenus"; +import { uninstallContextMenu } from "./contextMenus/uninstallContextMenu"; import { clearExtensionTraces } from "@/telemetry/trace"; import { clearLog } from "@/telemetry/logging"; diff --git a/src/contentScript/contentScriptPlatform.ts b/src/contentScript/contentScriptPlatform.ts index 82579788f9..2fc9917aad 100644 --- a/src/contentScript/contentScriptPlatform.ts +++ b/src/contentScript/contentScriptPlatform.ts @@ -24,13 +24,13 @@ import { openTab, performConfiguredRequestInBackground, ensureContextMenu, + uninstallContextMenu, } from "@/background/messenger/strict/api"; import { getState, setState } from "@/platform/state/stateController"; import quickBarRegistry from "@/components/quickBar/quickBarRegistry"; import { expectContext } from "@/utils/expectContext"; import type { PlatformCapability } from "@/platform/capabilities"; import { getReferenceForElement } from "@/contentScript/elementReference"; -import { uninstallContextMenu } from "@/background/messenger/api"; import { ephemeralForm } from "@/contentScript/ephemeralForm"; import { ephemeralPanel } from "@/contentScript/ephemeralPanel"; import type { ElementReference } from "@/types/runtimeTypes"; diff --git a/src/starterBricks/contextMenu/contextMenu.test.ts b/src/starterBricks/contextMenu/contextMenu.test.ts index 5fe0a77775..38a563990c 100644 --- a/src/starterBricks/contextMenu/contextMenu.test.ts +++ b/src/starterBricks/contextMenu/contextMenu.test.ts @@ -26,13 +26,15 @@ import { fromJS } from "@/starterBricks/contextMenu/contextMenu"; import { type ResolvedModComponent } from "@/types/modComponentTypes"; import { uuidSequence } from "@/testUtils/factories/stringFactories"; import { RunReason } from "@/types/runtimeTypes"; -import { uninstallContextMenu } from "@/background/messenger/api"; +import { + uninstallContextMenu, + ensureContextMenu, +} from "@/background/messenger/strict/api"; import { getPlatform } from "@/platform/platformContext"; import { type ContextMenuDefinition, type ContextMenuConfig, } from "@/starterBricks/contextMenu/types"; -import { ensureContextMenu } from "@/background/messenger/strict/api"; const uninstallContextMenuMock = jest.mocked(uninstallContextMenu); const ensureContextMenuMock = jest.mocked(ensureContextMenu); diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index d5846f8225..ad6c3e8c16 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -76,6 +76,7 @@ "./background/contentScript.ts", "./background/contextMenus/ensureContextMenu.ts", "./background/contextMenus/makeMenuId.ts", + "./background/contextMenus/uninstallContextMenu.ts", "./background/dataStore.ts", "./background/externalProtocol.ts", "./background/initTheme.ts",