UNPKG

crx2ff

Version:

Check the compatibility of a Chrome extension with the Firefox WebExtensions API.

317 lines (255 loc) 8.73 kB
// Processing is done based on the list found at // https://wiki.mozilla.org/WebExtensions#List_of_supported_APIs // Since support of an API is not binary, there is more logic here // than on chrome APIs detection function SupportStatus (type, msg) { this.type = type; this.msg = msg; } function FutureSupport () { return function (propsChain) { return new SupportStatus("FUTURE_SUPPORT"); }; } function FullSupport () { return function (propsChain) { return new SupportStatus("FULL_SUPPORT"); }; } function ExtensionSupport (propsChain) { var noSupport = [ "isAllowedIncognitoAccess", "isAllowedFileSchemeAccess", "setUpdateUrlData", "onRequest", "onRequestExternal" ].join('|'); var r = new RegExp("^(" + noSupport + ")"); if (r.exec(propsChain) !== null) { return new SupportStatus("NO_SUPPORT"); } return new SupportStatus("SUPPORT"); } function i18nSupport (propsChain) { var support = [ "getMessage", ].join('|'); var r = new RegExp("^(" + support + ")"); if (r.exec(propsChain) !== null) { return new SupportStatus("SUPPORT"); } var futureSupport = [ "getAcceptLanguages", "getUILanguage", "detectLanguage", ].join('|'); var r2 = new RegExp("^(" + futureSupport + ")"); if (r2.exec(propsChain) !== null) { return new SupportStatus("FUTURE_SUPPORT"); } return new SupportStatus("NO_SUPPORT"); } function NotificationsSupport (propsChain) { if (propsChain.indexOf("create") === 0) { return new SupportStatus("WARN", "The only supported notification options are iconUrl, title, and message."); } if (propsChain.indexOf("onClosed") === 0) { return new SupportStatus("WARN", "The byUser data is not provided."); } if (propsChain.match(/^(getAll|clear)/) === null) { return new SupportStatus("NO_SUPPORT"); } return new SupportStatus("SUPPORT"); } function RuntimeSupport (propsChain) { var support = [ "onStartup", "getManifest", "getURL", "id", "sendMessage", "onMessage", "onConnect", "connect", "getPlatformInfo", ].join('|'); var r = new RegExp("^(" + support + ")"); if (r.exec(propsChain) !== null) { return new SupportStatus("SUPPORT"); } var futureSupport = [ "lastError", "getBackgroundPage", "openOptionsPage", "setUninstallURL", "reload", "requestUpdateCheck", "restart", "connectNative", "sendNativeMessage", "getPackageDirectoryEntry", "onInstalled", "onSuspend", "onSuspendCanceled", "onUpdateAvailable", "onBrowserUpdateAvailable", "onConnectExternal", "onMessageExternal", "onRestartRequired", ].join('|'); var r2 = new RegExp("^(" + futureSupport + ")"); if (r2.exec(propsChain) !== null) { return new SupportStatus("FUTURE_SUPPORT"); } return new SupportStatus("NO_SUPPORT"); } function StorageSupport (propsChain) { if (propsChain.match(/^(sync|managed)/) !== null) { return new SupportStatus("NO_SUPPORT"); } if (propsChain.match(/(getBytesInUse)/) !== null) { return new SupportStatus("NO_SUPPORT"); } return new SupportStatus("WARN", "Not supported in content scripts. See bug 1197346"); } function TabsSupport (propsChain) { var noSupport = [ "sendRequest", "getSelected" ].join('|'); var r = new RegExp("^(" + noSupport + ")"); if (r.exec(propsChain) !== null) { return new SupportStatus("NO_SUPPORT"); } var highlightActive = [ "highlight", "update", "onActiveChanged", "onActivated", "onHighlightChanged", "onHighlighted" ].join('|'); var r2 = new RegExp("^(" + highlightActive + ")"); if (r2.exec(propsChain) !== null) { return new SupportStatus("WARN", "Highlighted and active are treated as the same since Firefox cannot select multiple tabs."); } if (propsChain.indexOf("sendMessage") === 0) { return new SupportStatus("WARN", "The implementation appears to be broken. See bug 1209869."); } return new SupportStatus("SUPPORT"); } function WebNavigationSupport (propsChain) { var noSupport = [ "getFrame", "getAllFrames", "onCreatedNavigationTarget", "onHistoryStateUpdated", "onTabReplaced", ].join('|'); var r = new RegExp("^(" + noSupport + ")"); if (r.exec(propsChain) !== null) { return new SupportStatus("NO_SUPPORT"); } if (propsChain.indexOf("onReferenceFragmentUpdated") === 0) { return [ new SupportStatus("WARN", "This method also triggers for pushState."), new SupportStatus("WARN", "Filtering, transition types and qualifiers are unsupported.") ]; } return new SupportStatus("WARN", "Filtering, transition types and qualifiers are unsupported."); } function WebRequestSupport (propsChain) { var noSupport = [ "handlerBehaviorChanged", "onAuthRequired", "onErrorOccurred" ].join('|'); var r = new RegExp("^(" + noSupport + ")"); if (r.exec(propsChain) !== null) { return new SupportStatus("NO_SUPPORT"); } if (propsChain.indexOf("onBeforeRequest") === 0) { return new SupportStatus("WARN", "Requests can not be modified/redirected on this method."); } if (propsChain.indexOf("onBeforeSendHeaders") === 0) { return new SupportStatus("WARN", "Requests can not be canceled on this method."); } if (propsChain.indexOf("") === 0) { return new SupportStatus("WARN", "Requests can not be redirected or canceled on this method."); } return new SupportStatus("WARN", "Requests can not be canceled, modified or redirected on this method."); } function WindowsSupport (propsChain) { if (propsChain.indexOf("onFocusChanged") === 0) { return new SupportStatus("WARN", "This method will trigger multiple times for a given focus change."); } if (propsChain.indexOf("create") === 0) { return new SupportStatus("WARN", "This method does not support the focused, type, or state options."); } if (propsChain.indexOf("update") === 0) { return new SupportStatus("WARN", "This method only supports the focused option."); } return new SupportStatus("SUPPORT"); } function BookmarksSupport (propsChain) { var noSupport = [ "getRecent", "removeTree", "onCreated", "onRemoved", "onChanged", "onMoved", "onChildrenReordered", "onImportBegan", "onImportEnded", "BookmarkTreeNodeUnmodifiable" ].join('|'); var r = new RegExp("^(" + noSupport + ")"); if (r.exec(propsChain) !== null) { return new SupportStatus("NO_SUPPORT"); } if (propsChain.indexOf("removes") === 0) { return new SupportStatus("WARN", "This method also removes non empty folders."); } return new SupportStatus("SUPPORT"); } function CookiesSupport (propsChain) { if (propsChain.indexOf("onChanged") === 0) { return new SupportStatus("WARN", "Events might be subtely different."); } if (propsChain.indexOf("set") === 0) { return new SupportStatus("WARN", "Creating session cookies with set might fail."); } if (propsChain.indexOf("getAllCookieStores") === 0) { return new SupportStatus("WARN", "This method always just returns one default store and no tabs."); } return new SupportStatus("WARN", "Accessing cookies from private tabs is impossible."); } module.exports = { // Fully supported APIs "alarms": FullSupport(), "contextMenus": FullSupport(), "browserAction": FullSupport(), "pageAction": FullSupport(), // Partially supported APIs "bookmarks": BookmarksSupport, "cookies": CookiesSupport, "extension": ExtensionSupport, "i18n": i18nSupport, "notifications": NotificationsSupport, "runtime": RuntimeSupport, "storage": StorageSupport, "tabs": TabsSupport, "webNavigation": WebNavigationSupport, "webRequest": WebRequestSupport, "windows": WindowsSupport, // Future APIs "commands": FutureSupport(), "debugger": FutureSupport(), "downloads": FutureSupport(), "history": FutureSupport(), "idle": FutureSupport(), "omnibox": FutureSupport(), "permissions": FutureSupport(), "devtools.panels": FutureSupport() };