From 2223114f200888ad8176c8d4191bf75a5b0d033d Mon Sep 17 00:00:00 2001 From: Felix Rieseberg Date: Tue, 19 Feb 2019 13:09:44 +0000 Subject: [PATCH] refactor: Port chrome-api to TypeScript (#17014) --- filenames.gni | 2 +- lib/renderer/{chrome-api.js => chrome-api.ts} | 96 +++++++++++++------ typings/internal-electron.d.ts | 24 +++++ 3 files changed, 92 insertions(+), 30 deletions(-) rename lib/renderer/{chrome-api.js => chrome-api.ts} (66%) diff --git a/filenames.gni b/filenames.gni index 38c76d982..124b8c34f 100644 --- a/filenames.gni +++ b/filenames.gni @@ -63,7 +63,7 @@ filenames = { "lib/common/reset-search-paths.ts", "lib/common/web-view-methods.js", "lib/renderer/callbacks-registry.js", - "lib/renderer/chrome-api.js", + "lib/renderer/chrome-api.ts", "lib/renderer/content-scripts-injector.ts", "lib/renderer/init.js", "lib/renderer/inspector.js", diff --git a/lib/renderer/chrome-api.js b/lib/renderer/chrome-api.ts similarity index 66% rename from lib/renderer/chrome-api.js rename to lib/renderer/chrome-api.ts index a9bc0cabf..e5fa7dcda 100644 --- a/lib/renderer/chrome-api.js +++ b/lib/renderer/chrome-api.ts @@ -1,18 +1,24 @@ -'use strict' +import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal' +import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-internal-utils' +import * as url from 'url' -const { ipcRendererInternal } = require('@electron/internal/renderer/ipc-renderer-internal') -const ipcRendererUtils = require('@electron/internal/renderer/ipc-renderer-internal-utils') +// Todo: Import once extensions have been turned into TypeScript const Event = require('@electron/internal/renderer/extensions/event') -const url = require('url') class Tab { - constructor (tabId) { + public id: number + + constructor (tabId: number) { this.id = tabId } } class MessageSender { - constructor (tabId, extensionId) { + public tab: Tab | null + public id: string + public url: string + + constructor (tabId: number, extensionId: string) { this.tab = tabId ? new Tab(tabId) : null this.id = extensionId this.url = `chrome-extension://${extensionId}` @@ -20,12 +26,12 @@ class MessageSender { } class Port { - constructor (tabId, portId, extensionId, name) { - this.tabId = tabId - this.portId = portId - this.disconnected = false + public disconnected: boolean = false + public onDisconnect = new Event() + public onMessage = new Event() + public sender: MessageSender - this.name = name + constructor (public tabId: number, public portId: number, extensionId: string, public name: string) { this.onDisconnect = new Event() this.onMessage = new Event() this.sender = new MessageSender(tabId, extensionId) @@ -33,7 +39,10 @@ class Port { ipcRendererInternal.once(`CHROME_PORT_DISCONNECT_${portId}`, () => { this._onDisconnect() }) - ipcRendererInternal.on(`CHROME_PORT_POSTMESSAGE_${portId}`, (event, message) => { + + ipcRendererInternal.on(`CHROME_PORT_POSTMESSAGE_${portId}`, ( + _event: Electron.Event, message: string + ) => { const sendResponse = function () { console.error('sendResponse is not implemented') } this.onMessage.emit(message, this.sender, sendResponse) }) @@ -46,7 +55,7 @@ class Port { this._onDisconnect() } - postMessage (message) { + postMessage (message: string) { ipcRendererInternal.sendToAll(this.tabId, `CHROME_PORT_POSTMESSAGE_${this.portId}`, message) } @@ -58,32 +67,38 @@ class Port { } // Inject chrome API to the |context| -exports.injectTo = function (extensionId, isBackgroundPage, context) { +export function injectTo (extensionId: string, isBackgroundPage: boolean, context: any) { const chrome = context.chrome = context.chrome || {} let originResultID = 1 - ipcRendererInternal.on(`CHROME_RUNTIME_ONCONNECT_${extensionId}`, (event, tabId, portId, connectInfo) => { + ipcRendererInternal.on(`CHROME_RUNTIME_ONCONNECT_${extensionId}`, ( + _event: Electron.Event, tabId: number, portId: number, connectInfo: { name: string } + ) => { chrome.runtime.onConnect.emit(new Port(tabId, portId, extensionId, connectInfo.name)) - }) + } + ) - ipcRendererInternal.on(`CHROME_RUNTIME_ONMESSAGE_${extensionId}`, (event, tabId, message, resultID) => { - chrome.runtime.onMessage.emit(message, new MessageSender(tabId, extensionId), (messageResult) => { + ipcRendererInternal.on(`CHROME_RUNTIME_ONMESSAGE_${extensionId}`, ( + _event: Electron.Event, tabId: number, message: string, resultID: number + ) => { + chrome.runtime.onMessage.emit(message, new MessageSender(tabId, extensionId), (messageResult: any) => { ipcRendererInternal.send(`CHROME_RUNTIME_ONMESSAGE_RESULT_${resultID}`, messageResult) }) }) - ipcRendererInternal.on('CHROME_TABS_ONCREATED', (event, tabId) => { + ipcRendererInternal.on('CHROME_TABS_ONCREATED', (_event: Electron.Event, tabId: number) => { chrome.tabs.onCreated.emit(new Tab(tabId)) }) - ipcRendererInternal.on('CHROME_TABS_ONREMOVED', (event, tabId) => { + ipcRendererInternal.on('CHROME_TABS_ONREMOVED', (_event: Electron.Event, tabId: number) => { chrome.tabs.onRemoved.emit(tabId) }) chrome.runtime = { id: extensionId, - getURL: function (path) { + // https://developer.chrome.com/extensions/runtime#method-getURL + getURL: function (path: string) { return url.format({ protocol: 'chrome-extension', slashes: true, @@ -92,12 +107,14 @@ exports.injectTo = function (extensionId, isBackgroundPage, context) { }) }, + // https://developer.chrome.com/extensions/runtime#method-getManifest getManifest: function () { const manifest = ipcRendererUtils.invokeSync('CHROME_EXTENSION_MANIFEST', extensionId) return manifest }, - connect (...args) { + // https://developer.chrome.com/extensions/runtime#method-connect + connect (...args: Array) { if (isBackgroundPage) { console.error('chrome.runtime.connect is not supported in background page') return @@ -116,7 +133,8 @@ exports.injectTo = function (extensionId, isBackgroundPage, context) { return new Port(tabId, portId, extensionId, connectInfo.name) }, - sendMessage (...args) { + // https://developer.chrome.com/extensions/runtime#method-sendMessage + sendMessage (...args: Array) { if (isBackgroundPage) { console.error('chrome.runtime.sendMessage is not supported in background page') return @@ -130,14 +148,19 @@ exports.injectTo = function (extensionId, isBackgroundPage, context) { } else if (args.length === 2) { // A case of not provide extension-id: (message, responseCallback) if (typeof args[1] === 'function') { - ipcRendererInternal.once(`CHROME_RUNTIME_SENDMESSAGE_RESULT_${originResultID}`, (event, result) => args[1](result)) + ipcRendererInternal.once(`CHROME_RUNTIME_SENDMESSAGE_RESULT_${originResultID}`, + (_event: Electron.Event, result: any) => args[1](result) + ) + message = args[0] } else { [targetExtensionId, message] = args } } else { console.error('options is not supported') - ipcRendererInternal.once(`CHROME_RUNTIME_SENDMESSAGE_RESULT_${originResultID}`, (event, result) => args[2](result)) + ipcRendererInternal.once(`CHROME_RUNTIME_SENDMESSAGE_RESULT_${originResultID}`, + (event: Electron.Event, result: any) => args[2](result) + ) } ipcRendererInternal.send('CHROME_RUNTIME_SENDMESSAGE', targetExtensionId, message, originResultID) @@ -150,17 +173,32 @@ exports.injectTo = function (extensionId, isBackgroundPage, context) { } chrome.tabs = { - executeScript (tabId, details, resultCallback) { + // https://developer.chrome.com/extensions/tabs#method-executeScript + executeScript ( + tabId: number, + details: Chrome.Tabs.ExecuteScriptDetails, + resultCallback: Chrome.Tabs.ExecuteScriptCallback + ) { if (resultCallback) { - ipcRendererInternal.once(`CHROME_TABS_EXECUTESCRIPT_RESULT_${originResultID}`, (event, result) => resultCallback([result])) + ipcRendererInternal.once(`CHROME_TABS_EXECUTESCRIPT_RESULT_${originResultID}`, + (_event: Electron.Event, result: any) => resultCallback([result]) + ) } ipcRendererInternal.send('CHROME_TABS_EXECUTESCRIPT', originResultID, tabId, extensionId, details) originResultID++ }, - sendMessage (tabId, message, options, responseCallback) { + // https://developer.chrome.com/extensions/tabs#method-sendMessage + sendMessage ( + tabId: number, + message: any, + _options: Chrome.Tabs.SendMessageDetails, + responseCallback: Chrome.Tabs.SendMessageCallback + ) { if (responseCallback) { - ipcRendererInternal.once(`CHROME_TABS_SEND_MESSAGE_RESULT_${originResultID}`, (event, result) => responseCallback(result)) + ipcRendererInternal.once(`CHROME_TABS_SEND_MESSAGE_RESULT_${originResultID}`, + (_event: Electron.Event, result: any) => responseCallback(result) + ) } ipcRendererInternal.send('CHROME_TABS_SEND_MESSAGE', tabId, extensionId, isBackgroundPage, message, originResultID) originResultID++ diff --git a/typings/internal-electron.d.ts b/typings/internal-electron.d.ts index c6bb3952c..9d52bbc70 100644 --- a/typings/internal-electron.d.ts +++ b/typings/internal-electron.d.ts @@ -79,3 +79,27 @@ declare namespace ElectronInternal { once(channel: string, listener: (event: IpcMainInternalEvent, ...args: any[]) => void): this; } } + +declare namespace Chrome { + namespace Tabs { + // https://developer.chrome.com/extensions/tabs#method-executeScript + interface ExecuteScriptDetails { + code?: string; + file?: string; + allFrames?: boolean; + frameId?: number; + matchAboutBlank?: boolean; + runAt?: 'document-start' | 'document-end' | 'document_idle'; + cssOrigin: 'author' | 'user'; + } + + type ExecuteScriptCallback = (result: Array) => void; + + // https://developer.chrome.com/extensions/tabs#method-sendMessage + interface SendMessageDetails { + frameId?: number; + } + + type SendMessageCallback = (result: any) => void; + } +}