/** The kind of an entrypoint in an extension manifest. */ enum ManifestEntrypointKind { /** Javascript run as part of a content script */ CONTENT_SCRIPT_JS, /** CSS applied as part of a content script */ CONTENT_SCRIPT_CSS, /** Javascript run in the background page of an MV2 extension */ BACKGROUND_SCRIPT, /** Javascript run the service worker of an MV3 extension */ BACKGROUND_SERVICE_WORKER, /** Image file loaded as the extension's icon at a particular size */ ICON, /** Path listed in the `web_accessible_resources` of an MV2 extension */ WEB_ACCESSIBLE_RESOURCE_V2, /** Path listed in the `web_accessible_resources` of an MV3 extension */ WEB_ACCESSIBLE_RESOURCE_V3, } /** * A handle to a single entrypoint from a manifest, which allows for rewriting * the path of the asset in the manifest. */ interface ManifestEntrypoint { type: ManifestEntrypointKind; /** The full path to the entrypoint file. */ path: string; /** * Replaces this entry path with the given new path. This is an in-place * operation and directly affects the original manifest object. */ replacePath: (path: string) => void; } /** * Gets all script entrypoints from a manifest, returning them as * {@link ManifestEntrypoint} objects which allow for rewriting the path of each * individual entrypoint in place. * @param manifest Parsed `manifest.json` data. */ export const getScriptEntrypoints = (manifest: chrome.runtime.Manifest): ManifestEntrypoint[] => [ ...(manifest.content_scripts ?? []).flatMap(script => (script.js ?? []).map((path, i) => ({ type: ManifestEntrypointKind.CONTENT_SCRIPT_JS, path, replacePath (newPath: string) { this.path = newPath; script.js!.splice(i, 1, newPath); }, })) ), ...(manifest.manifest_version === 2 ? (manifest.background?.scripts || []).map((path, i) => ({ type: ManifestEntrypointKind.BACKGROUND_SCRIPT, path, replacePath (newPath: string) { this.path = newPath; manifest.background!.scripts!.splice(i, 1, newPath); }, })) : (manifest.background?.service_worker ? [{ type: ManifestEntrypointKind.BACKGROUND_SERVICE_WORKER, path: manifest.background.service_worker, replacePath (newPath: string) { this.path = newPath; manifest.background!.service_worker = newPath; }, }] : [])), ]; /** * Gets all asset entrypoints from a manifest, returning them as * {@link ManifestEntrypoint} objects which allow for rewriting the path of each * individual entrypoint in place. * @param manifest Parsed `manifest.json` data. */ export const getAssetEntrypoints = (manifest: chrome.runtime.Manifest): ManifestEntrypoint[] => [ ...(manifest.content_scripts ?? []).flatMap(script => (script.css ?? []).map((path, i) => ({ type: ManifestEntrypointKind.CONTENT_SCRIPT_CSS, path, replacePath (newPath: string) { this.path = newPath; script.css!.splice(i, 1, newPath); }, })) ), ...Object.entries(manifest.icons || {}).map(([iconSize, path]) => ({ type: ManifestEntrypointKind.ICON, path, replacePath (newPath: string) { this.path = newPath; manifest.icons![iconSize as unknown as number] = newPath; }, })), ...(manifest.manifest_version === 2 ? (manifest.web_accessible_resources ?? []).map((path, i) => ({ type: ManifestEntrypointKind.WEB_ACCESSIBLE_RESOURCE_V2, path, replacePath (newPath: string) { this.path = newPath; manifest.web_accessible_resources![i] = newPath; }, })) : (manifest.web_accessible_resources ?? []).flatMap(entry => entry.resources.map((path, i) => ({ type: ManifestEntrypointKind.WEB_ACCESSIBLE_RESOURCE_V3, path, replacePath (newPath: string) { this.path = newPath; entry.resources.splice(i, 1, newPath); }, })) )), ];