From 0c9b65ef90838a43874719cf23f00b7e729977e3 Mon Sep 17 00:00:00 2001 From: Mark Striemer Date: Fri, 29 Sep 2017 13:19:03 -0500 Subject: [PATCH] Firefox 57 schema import (fixes #1577) --- src/schema/firefox-schemas-import.js | 1 + src/schema/formats.js | 8 + src/schema/imported/bookmarks.json | 29 ++++ src/schema/imported/browser_action.json | 34 ++--- src/schema/imported/browser_settings.json | 58 ++++++- src/schema/imported/browsing_data.json | 1 - .../imported/chrome_settings_overrides.json | 5 +- src/schema/imported/clipboard.json | 36 +++++ .../imported/contextual_identities.json | 94 +++++++++++- src/schema/imported/devtools.json | 24 ++- src/schema/imported/downloads.json | 8 +- src/schema/imported/find.json | 114 ++++++++++++++ src/schema/imported/index.js | 5 +- src/schema/imported/manifest.json | 144 +++++++++++++++++- src/schema/imported/notifications.json | 12 ++ src/schema/imported/page_action.json | 21 ++- src/schema/imported/privacy.json | 22 ++- src/schema/imported/sessions.json | 122 +++++++++++++++ src/schema/imported/sidebar_action.json | 16 ++ src/schema/imported/tabs.json | 26 +++- src/schema/imported/theme.json | 24 ++- src/schema/imported/web_request.json | 19 +++ src/schema/validator.js | 3 + tests/schema/test.formats.js | 43 ++++++ 24 files changed, 809 insertions(+), 60 deletions(-) create mode 100644 src/schema/imported/clipboard.json create mode 100644 src/schema/imported/find.json diff --git a/src/schema/firefox-schemas-import.js b/src/schema/firefox-schemas-import.js index a861f558..303d49ab 100644 --- a/src/schema/firefox-schemas-import.js +++ b/src/schema/firefox-schemas-import.js @@ -37,6 +37,7 @@ const schemaRegexes = [ export const refMap = { ExtensionURL: 'manifest#/types/ExtensionURL', HttpURL: 'manifest#/types/HttpURL', + ImageDataOrExtensionURL: 'manifest#/types/ImageDataOrExtensionURL', }; // Reference some functions on inner so they can be stubbed in tests. diff --git a/src/schema/formats.js b/src/schema/formats.js index 5c6e5f60..f780e9ae 100644 --- a/src/schema/formats.js +++ b/src/schema/formats.js @@ -97,3 +97,11 @@ export function isSecureUrl(value) { // URL is absolute, check against secure protocols. return ['https:', 'wss:'].includes(url.protocol); } + +export function imageDataOrStrictRelativeUrl(value) { + // Do not accept a string which resolves as an absolute URL, or any + // protocol-relative URL, except PNG or JPG data URLs. + return value.startsWith('data:image/png;base64,') + || value.startsWith('data:image/jpeg;base64,') + || isStrictRelativeUrl(value); +} diff --git a/src/schema/imported/bookmarks.json b/src/schema/imported/bookmarks.json index 1c4879c7..02a5aa29 100644 --- a/src/schema/imported/bookmarks.json +++ b/src/schema/imported/bookmarks.json @@ -558,6 +558,15 @@ ], "description": "Indicates the reason why this node is unmodifiable. The managed value indicates that this node was configured by the system administrator or by the custodian of a supervised user. Omitted if the node can be modified by the user and the extension (default)." }, + "BookmarkTreeNodeType": { + "type": "string", + "enum": [ + "bookmark", + "folder", + "separator" + ], + "description": "Indicates the type of a BookmarkTreeNode, which can be one of bookmark, folder or separator." + }, "BookmarkTreeNode": { "type": "object", "description": "A node (either a bookmark or a folder) in the bookmark tree. Child nodes are ordered within their parent folder.", @@ -600,6 +609,16 @@ } ] }, + "type": { + "allOf": [ + { + "$ref": "#/types/BookmarkTreeNodeType" + }, + { + "description": "Indicates the type of the BookmarkTreeNode, which can be one of bookmark, folder or separator." + } + ] + }, "children": { "type": "array", "items": { @@ -630,6 +649,16 @@ }, "url": { "type": "string" + }, + "type": { + "allOf": [ + { + "$ref": "#/types/BookmarkTreeNodeType" + }, + { + "description": "Indicates the type of BookmarkTreeNode to create, which can be one of bookmark, folder or separator." + } + ] } } } diff --git a/src/schema/imported/browser_action.json b/src/schema/imported/browser_action.json index f2111f50..e1d98aa4 100644 --- a/src/schema/imported/browser_action.json +++ b/src/schema/imported/browser_action.json @@ -81,8 +81,10 @@ }, { "type": "object", - "additionalProperties": { - "$ref": "#/types/ImageDataType" + "patternProperties": { + "^[1-9]\\d*$": { + "$ref": "#/types/ImageDataType" + } } } ], @@ -95,8 +97,10 @@ }, { "type": "object", - "additionalProperties": { - "type": "string" + "patternProperties": { + "^[1-9]\\d*$": { + "type": "string" + } } } ], @@ -352,24 +356,10 @@ { "name": "openPopup", "type": "function", - "description": "Opens the extension popup window in the active window but does not grant tab permissions.", - "unsupported": true, - "async": "callback", - "parameters": [ - { - "type": "function", - "name": "callback", - "parameters": [ - { - "name": "popupView", - "type": "object", - "optional": true, - "description": "JavaScript 'window' object for the popup window if it was succesfully opened.", - "additionalProperties": {} - } - ] - } - ] + "requireUserInput": true, + "description": "Opens the extension popup window in the active window.", + "async": true, + "parameters": [] } ], "events": [ diff --git a/src/schema/imported/browser_settings.json b/src/schema/imported/browser_settings.json index 38133f02..b3221fa9 100644 --- a/src/schema/imported/browser_settings.json +++ b/src/schema/imported/browser_settings.json @@ -5,6 +5,16 @@ "browserSettings" ], "properties": { + "allowPopupsForUserEvents": { + "allOf": [ + { + "$ref": "types#/types/Setting" + }, + { + "description": "Allows or disallows pop-up windows from opening in response to user events." + } + ] + }, "cacheEnabled": { "allOf": [ { @@ -14,10 +24,40 @@ "description": "Enables or disables the browser cache." } ] + }, + "homepageOverride": { + "allOf": [ + { + "$ref": "types#/types/Setting" + }, + { + "description": "Returns the value of the overridden home page. Read-only." + } + ] + }, + "imageAnimationBehavior": { + "allOf": [ + { + "$ref": "types#/types/Setting" + }, + { + "description": "Controls the behaviour of image animation in the browser. This setting's value is of type ImageAnimationBehavior, defaulting to normal." + } + ] + }, + "newTabPageOverride": { + "allOf": [ + { + "$ref": "types#/types/Setting" + }, + { + "description": "Returns the value of the overridden new tab page. Read-only." + } + ] } }, "definitions": { - "Permission": { + "OptionalPermission": { "anyOf": [ { "type": "string", @@ -29,10 +69,20 @@ } }, "refs": { - "browserSettings#/definitions/Permission": { + "browserSettings#/definitions/OptionalPermission": { "namespace": "manifest", - "type": "Permission" + "type": "OptionalPermission" } }, - "types": {} + "types": { + "ImageAnimationBehavior": { + "type": "string", + "enum": [ + "normal", + "none", + "once" + ], + "description": "How images should be animated in the browser." + } + } } diff --git a/src/schema/imported/browsing_data.json b/src/schema/imported/browsing_data.json index b9d0aebd..e7e177b1 100644 --- a/src/schema/imported/browsing_data.json +++ b/src/schema/imported/browsing_data.json @@ -297,7 +297,6 @@ "description": "Clears websites' local storage data.", "type": "function", "async": "callback", - "unsupported": true, "parameters": [ { "allOf": [ diff --git a/src/schema/imported/chrome_settings_overrides.json b/src/schema/imported/chrome_settings_overrides.json index ba3fe5c8..08319364 100644 --- a/src/schema/imported/chrome_settings_overrides.json +++ b/src/schema/imported/chrome_settings_overrides.json @@ -36,8 +36,7 @@ "suggest_url": { "type": "string", "format": "url", - "preprocess": "localize", - "deprecated": "Unsupported on Firefox at this time." + "preprocess": "localize" }, "instant_url": { "type": "string", @@ -81,7 +80,7 @@ }, "is_default": { "type": "boolean", - "deprecated": "Unsupported on Firefox at this time." + "description": "Sets the default engine to a built-in engine only." } }, "required": [ diff --git a/src/schema/imported/clipboard.json b/src/schema/imported/clipboard.json new file mode 100644 index 00000000..cd7079ee --- /dev/null +++ b/src/schema/imported/clipboard.json @@ -0,0 +1,36 @@ +{ + "id": "clipboard", + "description": "Offers the ability to write to the clipboard. Reading is not supported because the clipboard can already be read through the standard web platform APIs.", + "permissions": [ + "clipboardWrite" + ], + "functions": [ + { + "name": "setImageData", + "type": "function", + "description": "Copy an image to the clipboard. The image is re-encoded before it is written to the clipboard. If the image is invalid, the clipboard is not modified.", + "async": true, + "parameters": [ + { + "type": "object", + "isInstanceOf": "ArrayBuffer", + "additionalProperties": true, + "name": "imageData", + "description": "The image data to be copied." + }, + { + "type": "string", + "name": "imageType", + "enum": [ + "jpeg", + "png" + ], + "description": "The type of imageData." + } + ] + } + ], + "definitions": {}, + "refs": {}, + "types": {} +} diff --git a/src/schema/imported/contextual_identities.json b/src/schema/imported/contextual_identities.json index 3dd7a03a..4fc8399b 100644 --- a/src/schema/imported/contextual_identities.json +++ b/src/schema/imported/contextual_identities.json @@ -115,6 +115,86 @@ ] } ], + "events": [ + { + "name": "onUpdated", + "type": "function", + "description": "Fired when a container is updated.", + "parameters": [ + { + "type": "object", + "name": "changeInfo", + "properties": { + "contextualIdentity": { + "allOf": [ + { + "$ref": "#/types/ContextualIdentity" + }, + { + "description": "Contextual identity that has been updated" + } + ] + } + }, + "required": [ + "contextualIdentity" + ] + } + ] + }, + { + "name": "onCreated", + "type": "function", + "description": "Fired when a new container is created.", + "parameters": [ + { + "type": "object", + "name": "changeInfo", + "properties": { + "contextualIdentity": { + "allOf": [ + { + "$ref": "#/types/ContextualIdentity" + }, + { + "description": "Contextual identity that has been created" + } + ] + } + }, + "required": [ + "contextualIdentity" + ] + } + ] + }, + { + "name": "onRemoved", + "type": "function", + "description": "Fired when a container is removed.", + "parameters": [ + { + "type": "object", + "name": "changeInfo", + "properties": { + "contextualIdentity": { + "allOf": [ + { + "$ref": "#/types/ContextualIdentity" + }, + { + "description": "Contextual identity that has been removed" + } + ] + } + }, + "required": [ + "contextualIdentity" + ] + } + ] + } + ], "definitions": { "Permission": { "anyOf": [ @@ -144,11 +224,19 @@ }, "icon": { "type": "string", - "description": "The icon of the contextual identity." + "description": "The icon name of the contextual identity." + }, + "iconUrl": { + "type": "string", + "description": "The icon url of the contextual identity." }, "color": { "type": "string", - "description": "The color of the contextual identity." + "description": "The color name of the contextual identity." + }, + "colorCode": { + "type": "string", + "description": "The color hash of the contextual identity." }, "cookieStoreId": { "type": "string", @@ -158,7 +246,9 @@ "required": [ "name", "icon", + "iconUrl", "color", + "colorCode", "cookieStoreId" ] } diff --git a/src/schema/imported/devtools.json b/src/schema/imported/devtools.json index 5e8da0cc..8bb77365 100644 --- a/src/schema/imported/devtools.json +++ b/src/schema/imported/devtools.json @@ -1,5 +1,8 @@ { "id": "devtools", + "permissions": [ + "devtools" + ], "allowedContexts": [ "devtools", "devtools_only" @@ -15,12 +18,26 @@ "$ref": "manifest#/types/ExtensionURL" } } + }, + "Permission": { + "anyOf": [ + { + "type": "string", + "enum": [ + "devtools" + ] + } + ] } }, "refs": { "devtools#/definitions/WebExtensionManifest": { "namespace": "manifest", "type": "WebExtensionManifest" + }, + "devtools#/definitions/Permission": { + "namespace": "manifest", + "type": "Permission" } }, "types": { @@ -143,7 +160,7 @@ "functions": [ { "name": "createSidebarPane", - "unsupported": true, + "async": "callback", "type": "function", "description": "Creates a pane within panel's sidebar.", "parameters": [ @@ -311,6 +328,7 @@ { "name": "setExpression", "unsupported": true, + "async": "callback", "type": "function", "description": "Sets an expression that is evaluated within the inspected page. The result is displayed in the sidebar pane.", "parameters": [ @@ -335,7 +353,7 @@ }, { "name": "setObject", - "unsupported": true, + "async": "callback", "type": "function", "description": "Sets a JSON-compliant object to be displayed in the sidebar pane.", "parameters": [ @@ -375,7 +393,6 @@ "events": [ { "name": "onShown", - "unsupported": true, "type": "function", "description": "Fired when the sidebar pane becomes visible as a result of user switching to the panel that hosts it.", "parameters": [ @@ -390,7 +407,6 @@ }, { "name": "onHidden", - "unsupported": true, "type": "function", "description": "Fired when the sidebar pane becomes hidden as a result of the user switching away from the panel that hosts the sidebar pane." } diff --git a/src/schema/imported/downloads.json b/src/schema/imported/downloads.json index 1005640e..734a6b90 100644 --- a/src/schema/imported/downloads.json +++ b/src/schema/imported/downloads.json @@ -24,6 +24,11 @@ "description": "A file path relative to the Downloads directory to contain the downloaded file.", "type": "string" }, + "incognito": { + "description": "Whether to associate the download with a private browsing session.", + "default": false, + "type": "boolean" + }, "conflictAction": { "$ref": "#/types/FilenameConflictAction" }, @@ -522,8 +527,7 @@ "type": "string", "enum": [ "downloads", - "downloads.open", - "downloads.shelf" + "downloads.open" ] } ] diff --git a/src/schema/imported/find.json b/src/schema/imported/find.json new file mode 100644 index 00000000..0c43e2b2 --- /dev/null +++ b/src/schema/imported/find.json @@ -0,0 +1,114 @@ +{ + "id": "find", + "description": "Use the browser.find API to interact with the browser's Find interface.", + "permissions": [ + "find" + ], + "functions": [ + { + "name": "find", + "type": "function", + "async": true, + "description": "Search for text in document and store found ranges in array, in document order.", + "parameters": [ + { + "name": "queryphrase", + "type": "string", + "description": "The string to search for." + }, + { + "name": "params", + "type": "object", + "description": "Search parameters.", + "optional": true, + "properties": { + "tabId": { + "type": "integer", + "description": "Tab to query. Defaults to the active tab.", + "minimum": 0 + }, + "caseSensitive": { + "type": "boolean", + "description": "Find only ranges with case sensitive match." + }, + "entireWord": { + "type": "boolean", + "description": "Find only ranges that match entire word." + }, + "includeRectData": { + "description": "Return rectangle data which describes visual position of search results.", + "type": "boolean" + }, + "includeRangeData": { + "description": "Return range data which provides range data in a serializable form.", + "type": "boolean" + } + } + } + ] + }, + { + "name": "highlightResults", + "type": "function", + "async": true, + "description": "Highlight a range", + "parameters": [ + { + "name": "params", + "type": "object", + "description": "highlightResults parameters", + "optional": true, + "properties": { + "rangeIndex": { + "type": "integer", + "description": "Found range to be highlighted. Default highlights all ranges.", + "minimum": 0 + }, + "tabId": { + "type": "integer", + "description": "Tab to highlight. Defaults to the active tab.", + "minimum": 0 + }, + "noScroll": { + "type": "boolean", + "description": "Don't scroll to highlighted item." + } + } + } + ] + }, + { + "name": "removeHighlighting", + "type": "function", + "async": true, + "description": "Remove all highlighting from previous searches.", + "parameters": [ + { + "name": "tabId", + "type": "integer", + "description": "Tab to highlight. Defaults to the active tab.", + "optional": true + } + ] + } + ], + "definitions": { + "OptionalPermission": { + "anyOf": [ + { + "type": "string", + "enum": [ + "find" + ] + } + ] + } + }, + "refs": { + "find#/definitions/OptionalPermission": { + "namespace": "manifest", + "type": "OptionalPermission" + } + }, + "types": {} +} diff --git a/src/schema/imported/index.js b/src/schema/imported/index.js index 0393eb82..20857c90 100644 --- a/src/schema/imported/index.js +++ b/src/schema/imported/index.js @@ -6,6 +6,7 @@ import browserAction from './browser_action.json'; import browserSettings from './browser_settings.json'; import browsingData from './browsing_data.json'; import chrome_settings_overrides from './chrome_settings_overrides.json'; +import clipboard from './clipboard.json'; import commands from './commands.json'; import contextualIdentities from './contextual_identities.json'; import cookies from './cookies.json'; @@ -16,6 +17,7 @@ import experiments from './experiments.json'; import extension from './extension.json'; import extension_protocol_handlers from './extension_protocol_handlers.json'; import extensionTypes from './extension_types.json'; +import find from './find.json'; import geckoProfiler from './geckoProfiler.json'; import history from './history.json'; import i18n from './i18n.json'; @@ -45,7 +47,6 @@ import webNavigation from './web_navigation.json'; import webRequest from './web_request.json'; import windows from './windows.json'; import contextMenus from './contextMenus.json'; - export default [ alarms, bookmarks, @@ -53,6 +54,7 @@ export default [ browserSettings, browsingData, chrome_settings_overrides, + clipboard, commands, contextualIdentities, cookies, @@ -63,6 +65,7 @@ export default [ extension, extension_protocol_handlers, extensionTypes, + find, geckoProfiler, history, i18n, diff --git a/src/schema/imported/manifest.json b/src/schema/imported/manifest.json index dead16c4..3cbee62f 100644 --- a/src/schema/imported/manifest.json +++ b/src/schema/imported/manifest.json @@ -182,13 +182,12 @@ "optional_permissions": { "type": "array", "items": { - "anyOf": [ + "allOf": [ { "$ref": "#/types/OptionalPermission" }, { - "type": "string", - "deprecated": "Unknown optional permission ${value}" + "onError": "warn" } ] }, @@ -255,6 +254,129 @@ } ] }, + "WebExtensionLangpackManifest": { + "type": "object", + "description": "Represents a WebExtension language pack manifest.json file", + "properties": { + "manifest_version": { + "type": "integer", + "minimum": 2, + "maximum": 2 + }, + "applications": { + "type": "object", + "properties": { + "gecko": { + "$ref": "#/types/FirefoxSpecificProperties" + } + } + }, + "browser_specific_settings": { + "type": "object", + "properties": { + "gecko": { + "$ref": "#/types/FirefoxSpecificProperties" + } + } + }, + "name": { + "type": "string", + "preprocess": "localize" + }, + "short_name": { + "type": "string", + "preprocess": "localize" + }, + "description": { + "type": "string", + "preprocess": "localize" + }, + "author": { + "type": "string", + "preprocess": "localize", + "onError": "warn" + }, + "version": { + "type": "string" + }, + "homepage_url": { + "type": "string", + "format": "url", + "preprocess": "localize" + }, + "langpack_id": { + "type": "string", + "pattern": "^[a-zA-Z][a-zA-Z-]+$" + }, + "languages": { + "type": "object", + "patternProperties": { + "^[a-z]{2}[a-zA-Z-]*$": { + "type": "object", + "properties": { + "chrome_resources": { + "type": "object", + "patternProperties": { + "^[a-zA-Z-.]+$": { + "anyOf": [ + { + "$ref": "manifest#/types/ExtensionURL" + }, + { + "type": "object", + "patternProperties": { + "^[a-z]+$": { + "$ref": "manifest#/types/ExtensionURL" + } + } + } + ] + } + } + }, + "version": { + "type": "string" + } + }, + "required": [ + "chrome_resources", + "version" + ] + } + } + }, + "sources": { + "type": "object", + "patternProperties": { + "^[a-z]+$": { + "type": "object", + "properties": { + "base_path": { + "$ref": "manifest#/types/ExtensionURL" + }, + "paths": { + "type": "array", + "items": { + "type": "string", + "format": "strictRelativeUrl" + } + } + }, + "required": [ + "base_path" + ] + } + } + } + }, + "required": [ + "manifest_version", + "name", + "version", + "langpack_id", + "languages" + ] + }, "ThemeIcons": { "type": "object", "properties": { @@ -307,9 +429,15 @@ { "$ref": "bookmarks#/definitions/OptionalPermission" }, + { + "$ref": "browserSettings#/definitions/OptionalPermission" + }, { "$ref": "cookies#/definitions/OptionalPermission" }, + { + "$ref": "find#/definitions/OptionalPermission" + }, { "$ref": "history#/definitions/OptionalPermission" }, @@ -340,15 +468,15 @@ "unlimitedStorage" ] }, - { - "$ref": "browserSettings#/definitions/Permission" - }, { "$ref": "browsingData#/definitions/Permission" }, { "$ref": "contextualIdentities#/definitions/Permission" }, + { + "$ref": "devtools#/definitions/Permission" + }, { "$ref": "downloads#/definitions/Permission" }, @@ -393,6 +521,10 @@ "type": "string", "format": "strictRelativeUrl" }, + "ImageDataOrExtensionURL": { + "type": "string", + "format": "imageDataOrStrictRelativeUrl" + }, "ExtensionID": { "anyOf": [ { diff --git a/src/schema/imported/notifications.json b/src/schema/imported/notifications.json index ec70ed80..8fc4eeb1 100644 --- a/src/schema/imported/notifications.json +++ b/src/schema/imported/notifications.json @@ -224,6 +224,18 @@ "type": "function", "description": "Fired when the user clicked on a link for the app's notification settings.", "parameters": [] + }, + { + "name": "onShown", + "type": "function", + "description": "Fired when the notification is shown.", + "parameters": [ + { + "type": "string", + "name": "notificationId", + "description": "The notificationId of the shown notification." + } + ] } ], "definitions": {}, diff --git a/src/schema/imported/page_action.json b/src/schema/imported/page_action.json index 4f91653f..aec01ae8 100644 --- a/src/schema/imported/page_action.json +++ b/src/schema/imported/page_action.json @@ -124,8 +124,10 @@ }, { "type": "object", - "additionalProperties": { - "$ref": "#/types/ImageDataType" + "patternProperties": { + "^[1-9]\\d*$": { + "$ref": "#/types/ImageDataType" + } } } ], @@ -138,8 +140,10 @@ }, { "type": "object", - "additionalProperties": { - "type": "string" + "patternProperties": { + "^[1-9]\\d*$": { + "type": "string" + } } } ], @@ -161,6 +165,7 @@ { "name": "setPopup", "type": "function", + "async": true, "description": "Sets the html document to be opened as a popup when the user clicks on the page action's icon.", "parameters": [ { @@ -214,6 +219,14 @@ ] } ] + }, + { + "name": "openPopup", + "type": "function", + "requireUserInput": true, + "description": "Opens the extension page action in the active window.", + "async": true, + "parameters": [] } ], "events": [ diff --git a/src/schema/imported/privacy.json b/src/schema/imported/privacy.json index daf834a7..9b6c95f8 100644 --- a/src/schema/imported/privacy.json +++ b/src/schema/imported/privacy.json @@ -115,13 +115,24 @@ "unsupported": true } ] + }, + "trackingProtectionMode": { + "allOf": [ + { + "$ref": "types#/types/Setting" + }, + { + "description": "Allow users to specify the mode for tracking protection. This setting's value is of type TrackingProtectionModeOption, defaulting to private_browsing_only." + } + ] } }, "required": [ "thirdPartyCookiesAllowed", "hyperlinkAuditingEnabled", "referrersEnabled", - "protectedContentEnabled" + "protectedContentEnabled", + "trackingProtectionMode" ] } }, @@ -153,6 +164,15 @@ "disable_non_proxied_udp" ], "description": "The IP handling policy of WebRTC." + }, + "TrackingProtectionModeOption": { + "type": "string", + "enum": [ + "always", + "never", + "private_browsing" + ], + "description": "The mode for tracking protection." } } } diff --git a/src/schema/imported/sessions.json b/src/schema/imported/sessions.json index 467f5afe..fc5f7486 100644 --- a/src/schema/imported/sessions.json +++ b/src/schema/imported/sessions.json @@ -135,6 +135,128 @@ ] } ] + }, + { + "name": "setTabValue", + "type": "function", + "description": "Set a key/value pair on a given tab.", + "async": true, + "parameters": [ + { + "type": "integer", + "minimum": 0, + "name": "tabId", + "description": "The id of the tab that the key/value pair is being set on." + }, + { + "type": "string", + "name": "key", + "description": "The key which corresponds to the value being set." + }, + { + "name": "value", + "description": "The value being set." + } + ] + }, + { + "name": "getTabValue", + "type": "function", + "description": "Retrieve a value that was set for a given key on a given tab.", + "async": true, + "parameters": [ + { + "type": "integer", + "minimum": 0, + "name": "tabId", + "description": "The id of the tab whose value is being retrieved from." + }, + { + "type": "string", + "name": "key", + "description": "The key which corresponds to the value." + } + ] + }, + { + "name": "removeTabValue", + "type": "function", + "description": "Remove a key/value pair that was set on a given tab.", + "async": true, + "parameters": [ + { + "type": "integer", + "minimum": 0, + "name": "tabId", + "description": "The id of the tab whose key/value pair is being removed." + }, + { + "type": "string", + "name": "key", + "description": "The key which corresponds to the value." + } + ] + }, + { + "name": "setWindowValue", + "type": "function", + "description": "Set a key/value pair on a given window.", + "async": true, + "parameters": [ + { + "type": "integer", + "minimum": -2, + "name": "windowId", + "description": "The id of the window that the key/value pair is being set on." + }, + { + "type": "string", + "name": "key", + "description": "The key which corresponds to the value being set." + }, + { + "name": "value", + "description": "The value being set." + } + ] + }, + { + "name": "getWindowValue", + "type": "function", + "description": "Retrieve a value that was set for a given key on a given window.", + "async": true, + "parameters": [ + { + "type": "integer", + "minimum": -2, + "name": "windowId", + "description": "The id of the window whose value is being retrieved from." + }, + { + "type": "string", + "name": "key", + "description": "The key which corresponds to the value." + } + ] + }, + { + "name": "removeWindowValue", + "type": "function", + "description": "Remove a key/value pair that was set on a given window.", + "async": true, + "parameters": [ + { + "type": "integer", + "minimum": -2, + "name": "windowId", + "description": "The id of the window whose key/value pair is being removed." + }, + { + "type": "string", + "name": "key", + "description": "The key which corresponds to the value." + } + ] } ], "events": [ diff --git a/src/schema/imported/sidebar_action.json b/src/schema/imported/sidebar_action.json index 86dc6a94..2dda0fa8 100644 --- a/src/schema/imported/sidebar_action.json +++ b/src/schema/imported/sidebar_action.json @@ -140,6 +140,22 @@ } } ] + }, + { + "name": "open", + "type": "function", + "requireUserInput": true, + "description": "Opens the extension sidebar in the active window.", + "async": true, + "parameters": [] + }, + { + "name": "close", + "type": "function", + "requireUserInput": true, + "description": "Closes the extension sidebar in the active window if the sidebar belongs to the extension.", + "async": true, + "parameters": [] } ], "definitions": { diff --git a/src/schema/imported/tabs.json b/src/schema/imported/tabs.json index dbf56667..7ca60a8d 100644 --- a/src/schema/imported/tabs.json +++ b/src/schema/imported/tabs.json @@ -269,7 +269,6 @@ "description": "Whether the tab should be pinned. Defaults to false" }, "openerTabId": { - "unsupported": true, "type": "integer", "minimum": 0, "description": "The ID of the tab that opened this tab. If specified, the opener tab must be in the same window as the newly created tab." @@ -382,6 +381,10 @@ } ] }, + "discarded": { + "type": "boolean", + "description": "True while the tabs are not loaded with content." + }, "title": { "type": "string", "description": "Match page titles against a pattern." @@ -423,6 +426,11 @@ "cookieStoreId": { "type": "string", "description": "The CookieStoreId used for the tab." + }, + "openerTabId": { + "type": "integer", + "minimum": 0, + "description": "The ID of the tab that opened this tab. If specified, the opener tab must be in the same window as this tab." } } }, @@ -542,10 +550,13 @@ "description": "Whether the tab should be muted." }, "openerTabId": { - "unsupported": true, "type": "integer", "minimum": 0, "description": "The ID of the tab that opened this tab. If specified, the opener tab must be in the same window as this tab." + }, + "loadReplace": { + "type": "boolean", + "description": "Whether the load should replace the current history entry for the tab." } } }, @@ -1039,7 +1050,7 @@ { "type": "string", "name": "status", - "description": "Save status: Saved, Replaced, Cancelled, Not Saved, Not Replaced." + "description": "Save status: saved, replaced, canceled, not_saved, not_replaced." } ] } @@ -1084,6 +1095,10 @@ "type": "string", "description": "The status of the tab. Can be either loading or complete." }, + "discarded": { + "type": "boolean", + "description": "True while the tab is not loaded with content." + }, "url": { "type": "string", "description": "The tab's URL if it has changed." @@ -1532,7 +1547,6 @@ "description": "The ID of the window the tab is contained within." }, "openerTabId": { - "unsupported": true, "type": "integer", "minimum": 0, "description": "The ID of the tab that opened this tab, if any. This property is only present if the opener tab still exists." @@ -1598,6 +1612,10 @@ "type": "string", "description": "Either loading or complete." }, + "discarded": { + "type": "boolean", + "description": "True while the tab is not loaded with content." + }, "incognito": { "type": "boolean", "description": "Whether the tab is in an incognito window." diff --git a/src/schema/imported/theme.json b/src/schema/imported/theme.json index 1ced9d42..cd907099 100644 --- a/src/schema/imported/theme.json +++ b/src/schema/imported/theme.json @@ -11,6 +11,12 @@ "async": true, "description": "Make complete or partial updates to the theme. Resolves when the update has completed.", "parameters": [ + { + "type": "integer", + "name": "windowId", + "optional": true, + "description": "The id of the window to update. No id updates all windows." + }, { "allOf": [ { @@ -71,14 +77,14 @@ "additional_backgrounds": { "type": "array", "items": { - "$ref": "manifest#/types/ExtensionURL" + "$ref": "manifest#/types/ImageDataOrExtensionURL" } }, "headerURL": { - "$ref": "manifest#/types/ExtensionURL" + "$ref": "manifest#/types/ImageDataOrExtensionURL" }, "theme_frame": { - "$ref": "manifest#/types/ExtensionURL" + "$ref": "manifest#/types/ImageDataOrExtensionURL" } } }, @@ -102,6 +108,15 @@ }, "textcolor": { "type": "string" + }, + "toolbar": { + "type": "string" + }, + "toolbar_field": { + "type": "string" + }, + "toolbar_field_text": { + "type": "string" } } }, @@ -183,9 +198,6 @@ "sidebars": { "$ref": "manifest#/types/ExtensionURL" }, - "share_page": { - "$ref": "manifest#/types/ExtensionURL" - }, "subscribe": { "$ref": "manifest#/types/ExtensionURL" }, diff --git a/src/schema/imported/web_request.json b/src/schema/imported/web_request.json index 2ea524b5..64554c40 100644 --- a/src/schema/imported/web_request.json +++ b/src/schema/imported/web_request.json @@ -24,6 +24,25 @@ "parameters": [] } ] + }, + { + "name": "filterResponseData", + "permissions": [ + "webRequestBlocking" + ], + "type": "function", + "description": "...", + "parameters": [ + { + "name": "requestId", + "type": "string" + } + ], + "returns": { + "type": "object", + "additionalProperties": {}, + "isInstanceOf": "StreamFilter" + } } ], "events": [ diff --git a/src/schema/validator.js b/src/schema/validator.js index 33ae3780..b1e1349e 100644 --- a/src/schema/validator.js +++ b/src/schema/validator.js @@ -3,6 +3,7 @@ import ajv from 'ajv'; import schemaObject from 'schema/imported/manifest'; import { + imageDataOrStrictRelativeUrl, isAnyUrl, isAbsoluteUrl, isStrictRelativeUrl, @@ -34,4 +35,6 @@ validator.addFormat('relativeUrl', isAnyUrl); validator.addFormat('strictRelativeUrl', isStrictRelativeUrl); validator.addFormat('secureUrl', isSecureUrl); +validator.addFormat('imageDataOrStrictRelativeUrl', imageDataOrStrictRelativeUrl); + export default validator.compile(schemaObject); diff --git a/tests/schema/test.formats.js b/tests/schema/test.formats.js index 7ee13b63..ff7f3f3f 100644 --- a/tests/schema/test.formats.js +++ b/tests/schema/test.formats.js @@ -1,4 +1,5 @@ import { + imageDataOrStrictRelativeUrl, isAbsoluteUrl, isAnyUrl, isSecureUrl, @@ -64,6 +65,7 @@ describe('formats', () => { expect(isSecureUrl(value)).toEqual(true); expect(isStrictRelativeUrl(value)).toEqual(false); + expect(imageDataOrStrictRelativeUrl(value)).toEqual(false); }); it('full URL', () => { @@ -74,6 +76,7 @@ describe('formats', () => { expect(isSecureUrl(value)).toEqual(true); expect(isStrictRelativeUrl(value)).toEqual(false); + expect(imageDataOrStrictRelativeUrl(value)).toEqual(false); }); it('invalid URLs', () => { @@ -83,6 +86,7 @@ describe('formats', () => { expect(isAbsoluteUrl(value)).toEqual(false); expect(isSecureUrl(value)).toEqual(false); expect(isStrictRelativeUrl(value)).toEqual(false); + expect(imageDataOrStrictRelativeUrl(value)).toEqual(false); }); it('path only', () => { @@ -90,6 +94,7 @@ describe('formats', () => { expect(isAnyUrl(value)).toEqual(true); expect(isStrictRelativeUrl(value)).toEqual(true); + expect(imageDataOrStrictRelativeUrl(value)).toEqual(true); expect(isAbsoluteUrl(value)).toEqual(false); expect(isSecureUrl(value)).toEqual(false); @@ -103,6 +108,7 @@ describe('formats', () => { expect(isAbsoluteUrl(value)).toEqual(false); expect(isStrictRelativeUrl(value)).toEqual(false); expect(isSecureUrl(value)).toEqual(false); + expect(imageDataOrStrictRelativeUrl(value)).toEqual(false); }); it('ftp: scheme', () => { @@ -113,6 +119,7 @@ describe('formats', () => { expect(isStrictRelativeUrl(value)).toEqual(false); expect(isSecureUrl(value)).toEqual(false); + expect(imageDataOrStrictRelativeUrl(value)).toEqual(false); }); it('http: scheme', () => { @@ -123,6 +130,7 @@ describe('formats', () => { expect(isStrictRelativeUrl(value)).toEqual(false); expect(isSecureUrl(value)).toEqual(false); + expect(imageDataOrStrictRelativeUrl(value)).toEqual(false); }); it('cannot be fooled with hand-crafted URLs', () => { @@ -135,6 +143,41 @@ describe('formats', () => { expect(isStrictRelativeUrl(value)).toEqual(false); expect(isSecureUrl(value)).toEqual(false); + expect(imageDataOrStrictRelativeUrl(value)).toEqual(false); + }); + + it('image data PNG', () => { + const value = 'data:image/png;base64,thisistotallybase64'; + + expect(isAbsoluteUrl(value)).toEqual(true); + expect(isAnyUrl(value)).toEqual(true); + expect(imageDataOrStrictRelativeUrl(value)).toEqual(true); + + expect(isStrictRelativeUrl(value)).toEqual(false); + expect(isSecureUrl(value)).toEqual(false); + }); + + it('image data JPG', () => { + const value = 'data:image/jpeg;base64,thisistotallybase64'; + + expect(isAnyUrl(value)).toEqual(true); + expect(isAbsoluteUrl(value)).toEqual(true); + expect(imageDataOrStrictRelativeUrl(value)).toEqual(true); + + expect(isStrictRelativeUrl(value)).toEqual(false); + expect(isSecureUrl(value)).toEqual(false); + }); + + it('image data SVG', () => { + // Only PNG and JPG are currently supported. + const value = 'data:image/svg;base64,thisistotallybase64'; + + expect(isAnyUrl(value)).toEqual(true); + expect(isAbsoluteUrl(value)).toEqual(true); + + expect(isStrictRelativeUrl(value)).toEqual(false); + expect(isSecureUrl(value)).toEqual(false); + expect(imageDataOrStrictRelativeUrl(value)).toEqual(false); }); }); });