diff options
Diffstat (limited to 'modules/firefox.home/chrome/utils/ChromeManifest.sys.mjs')
| -rw-r--r-- | modules/firefox.home/chrome/utils/ChromeManifest.sys.mjs | 415 |
1 files changed, 0 insertions, 415 deletions
diff --git a/modules/firefox.home/chrome/utils/ChromeManifest.sys.mjs b/modules/firefox.home/chrome/utils/ChromeManifest.sys.mjs deleted file mode 100644 index f2ebc18..0000000 --- a/modules/firefox.home/chrome/utils/ChromeManifest.sys.mjs +++ /dev/null @@ -1,415 +0,0 @@ -/* exported ChromeManifest */ -"use strict"; - -/** - * A default map, which assumes a default value on get() if the key doesn't exist - */ -class DefaultMap extends Map { - /** - * Constructs the default map - * - * @param {Function} _default A function that returns the default value for this map - * @param {*} iterable An iterable to initialize the map with - */ - constructor(_default, iterable) { - super(iterable); - this._default = _default; - } - - /** - * Get the given key, creating if necessary - * - * @param {String} key The key of the map to get - * @param {Boolean} create True, if the key should be created in case it doesn't exist. - */ - get(key, create = true) { - if (this.has(key)) { - return super.get(key); - } else if (create) { - this.set(key, this._default()); - return super.get(key); - } - - return this._default(); - } -} - -/** - * A parser for chrome.manifest files. Implements a subset of - * https://developer.mozilla.org/en-US/docs/Mozilla/Chrome_Registration - */ -export class ChromeManifest { - /** - * Constucts the chrome.manifest parser - * - * @param {Function} loader An asynchronous function that will load further files, e.g. - * those included via the |manifest| instruction. The - * function will take the file as an argument and should - * resolve with the string contents of that file - * @param {Object} options Object describing the current system. The keys are manifest - * instructions - */ - constructor(loader, options) { - this.loader = loader; - this.options = options; - - this.overlay = new DefaultMap(() => []); - this.locales = new DefaultMap(() => new Map()); - this.style = new DefaultMap(() => new Set()); - this.category = new DefaultMap(() => new Map()); - - this.component = new Map(); - this.contract = new Map(); - - this.content = new Map(); - this.skin = new DefaultMap(() => new Map()); - this.resource = new Map(); - this.override = new Map(); - } - - /** - * Parse the given file. - * - * @param {String} filename The filename to load - * @param {String} base The relative directory this file is expected to be in. - * @return {Promise} Resolved when loading completes - */ - async parse(filename = "chrome.manifest", base = "") { - await this.parseString(await this.loader(filename), base); - } - - /** - * Parse the given string. - * - * @param {String} data The file data to load - * @param {String} base The relative directory this file is expected to be in. - * @return {Promise} Resolved when loading completes - */ - async parseString(data, base = "") { - const lines = data.split("\n"); - const extraManifests = []; - for (const line of lines) { - const parts = line.split(/\s+/); - const directive = parts.shift(); - switch (directive) { - case "manifest": - extraManifests.push(this._parseManifest(base, ...parts)); - break; - case "component": this._parseComponent(...parts); - break; - case "contract": this._parseContract(...parts); - break; - case "category": this._parseCategory(...parts); - break; - case "content": this._parseContent(...parts); - break; - case "locale": this._parseLocale(...parts); - break; - case "skin": this._parseSkin(...parts); - break; - case "resource": this._parseResource(...parts); - break; - case "overlay": this._parseOverlay(...parts); - break; - case "style": this._parseStyle(...parts); - break; - case "override": this._parseOverride(...parts); - break; - } - } - - await Promise.all(extraManifests); - } - - /** - * Ensure the flags provided for the instruction match our options - * - * @param {String[]} flags An array of raw flag values in the form key=value. - * @return {Boolean} True, if the flags match the options provided in the constructor - */ - _parseFlags(flags) { - const matchString = (a, sign, b) => { - if (sign != "=") { - console.warn(`Invalid sign ${sign} in ${a}${sign}${b}, dropping manifest instruction`); - return false; - } - return a == b; - }; - - const matchVersion = (a, sign, b) => { - switch (sign) { - case "=": return Services.vc.compare(a, b) == 0; - case ">": return Services.vc.compare(a, b) > 0; - case "<": return Services.vc.compare(a, b) < 0; - case ">=": return Services.vc.compare(a, b) >= 0; - case "<=": return Services.vc.compare(a, b) <= 0; - default: - console.warn(`Invalid sign ${sign} in ${a}${sign}${b}, dropping manifest instruction`); - return false; - } - }; - - const flagdata = new DefaultMap(() => []); - - const flagMatches = (key, typeMatch) => { - return !flagdata.has(key) || flagdata.get(key).some(val => typeMatch(this.options[key], ...val)); - }; - - for (const flag of flags) { - const match = flag.match(/(\w+)(>=|<=|<|>|=)(.*)/); - if (match) { - flagdata.get(match[1]).push([match[2], match[3]]); - } else { - console.warn(`Invalid flag ${flag}, dropping manifest instruction`); - } - } - - return flagMatches("application", matchString) && - flagMatches("appversion", matchVersion) && - flagMatches("platformversion", matchVersion) && - flagMatches("os", matchString) && - flagMatches("osversion", matchVersion) && - flagMatches("abi", matchString); - } - - /** - * Parse the manifest instruction, to load other files - * - * @param {String} base The base directory the manifest file is in - * @param {String} filename The file and path to load - * @param {...String} flags The flags for this instruction - * @return {Promise} Promise resolved when the manifest is loaded - */ - async _parseManifest(base, filename, ...flags) { - if (this._parseFlags(flags)) { - const dirparts = filename.split("/"); - dirparts.pop(); - - try { - await this.parse(filename, base + "/" + dirparts.join("/")); - } catch (e) { - console.log(`Could not read manifest '${base}/${filename}'.`); - } - } - return null; - } - - /** - * Parse the component instruction, to load xpcom components - * - * @param {String} classid The xpcom class id to load - * @param {String} loction The file location of this component - * @param {...String} flags The flags for this instruction - */ - _parseComponent(classid, location, ...flags) { - if (this._parseFlags(flags)) { - this.component.set(classid, location); - } - } - - /** - * Parse the contract instruction, to load xpcom contract ids - * - * @param {String} contractid The xpcom contract id to load - * @param {String} location The file location of this component - * @param {...String} flags The flags for this instruction - */ - _parseContract(contractid, location, ...flags) { - if (this._parseFlags(flags)) { - this.contract.set(contractid, location); - } - } - - /** - * Parse the category instruction, to set up xpcom categories - * - * @param {String} category The name of the category - * @param {String} entryName The category entry name - * @param {String} value The category entry value - * @param {...String} flags The flags for this instruction - */ - _parseCategory(category, entryName, value, ...flags) { - if (this._parseFlags(flags)) { - this.category.get(category).set(entryName, value); - } - } - - /** - * Parse the content instruction, to set chrome content locations - * - * @param {String} shortname The content short name, e.g. chrome://shortname/content/ - * @param {String} location The location for this content registration - * @param {...String} flags The flags for this instruction - */ - _parseContent(shortname, location, ...flags) { - if (this._parseFlags(flags)) { - this.content.set(shortname, location); - } - } - - /** - * Parse the locale instruction, to set chrome locale locations - * - * @param {String} shortname The locale short name, e.g. chrome://shortname/locale/ - * @param {String} location The location for this locale registration - * @param {...String} flags The flags for this instruction - */ - _parseLocale(shortname, locale, location, ...flags) { - if (this._parseFlags(flags)) { - this.locales.get(shortname).set(locale, location); - } - } - - /** - * Parse the skin instruction, to set chrome skin locations - * - * @param {String} shortname The skin short name, e.g. chrome://shortname/skin/ - * @param {String} location The location for this skin registration - * @param {...String} flags The flags for this instruction - */ - _parseSkin(packagename, skinname, location, ...flags) { - if (this._parseFlags(flags)) { - this.skin.get(packagename).set(skinname, location); - } - } - - /** - * Parse the resource instruction, to set up resource uri subtitutions - * - * @param {String} packagename The resource package name, e.g. resource://packagename/ - * @param {String} url The location for this content registration - * @param {...String} flags The flags for this instruction - */ - _parseResource(packagename, location, ...flags) { - if (this._parseFlags(flags)) { - this.resource.set(packagename, location); - } - } - - /** - * Parse the overlay instruction, to set up xul overlays - * - * @param {String} targetUrl The chrome target url - * @param {String} overlayUrl The url of the xul overlay - * @param {...String} flags The flags for this instruction - */ - _parseOverlay(targetUrl, overlayUrl, ...flags) { - if (this._parseFlags(flags)) { - this.overlay.get(targetUrl).push(overlayUrl); - } - } - - /** - * Parse the style instruction, to add stylesheets into chrome windows - * - * @param {String} uri The uri of the chrome window - * @param {String} sheet The uri of the css sheet - * @param {...String} flags The flags for this instruction - */ - _parseStyle(uri, sheet, ...flags) { - if (this._parseFlags(flags)) { - this.style.get(uri).add(sheet); - } - } - - /** - * Parse the override instruction, to set chrome uri overrides - * - * @param {String} uri The uri being overridden - * @param {String} newuri The replacement uri for the original location - * @param {...String} flags The flags for this instruction - */ - _parseOverride(uri, newuri, ...flags) { - if (this._parseFlags(flags)) { - this.override.set(uri, newuri); - } - } - - /** - * Output the manifest data as a string in chrome.manifest format - * If root is provided, convert all relative locations to absolute paths. - * - * @param {String} [root] The absolute path root to resolve relative locations - * @return {String} The manifest contents as a string - */ - toString(root = "") { - const lines = []; - const isRelative = loc => { - // Not absolute if doesn't start with /, \, or protocol (chrome://, resource://, etc) - return ( - typeof loc === "string" && - !loc.match(/^(?:[a-zA-Z]+:|\\|\/)/) - ); - }; - const absolutize = loc => { - if (!root) return loc; - if (loc === "/") return root; - if (isRelative(loc)) { - return root.replace(/[\\/]$/, "") + "/" + loc.replace(/^([\\\/])/, ""); - } - return loc; - }; - - // Output components - for (const [classid, location] of this.component) { - lines.push(`component ${classid} ${absolutize(location)}`); - } - - // Output contracts - for (const [contractid, location] of this.contract) { - lines.push(`contract ${contractid} ${absolutize(location)}`); - } - - // Output categories - for (const [category, entries] of this.category) { - for (const [entryName, value] of entries) { - lines.push(`category ${category} ${entryName} ${value}`); - } - } - - // Output content - for (const [shortname, location] of this.content) { - lines.push(`content ${shortname} ${absolutize(location)}`); - } - - // Output locales - for (const [shortname, locales] of this.locales) { - for (const [locale, location] of locales) { - lines.push(`locale ${shortname} ${locale} ${absolutize(location)}`); - } - } - - // Output skins - for (const [packagename, skins] of this.skin) { - for (const [skinname, location] of skins) { - lines.push(`skin ${packagename} ${skinname} ${absolutize(location)}`); - } - } - - // Output resources - for (const [packagename, location] of this.resource) { - lines.push(`resource ${packagename} ${absolutize(location)}`); - } - - // Output overlays - for (const [targetUrl, overlays] of this.overlay) { - for (const overlayUrl of overlays) { - lines.push(`overlay ${targetUrl} ${absolutize(overlayUrl)}`); - } - } - - // Output styles - for (const [uri, sheets] of this.style) { - for (const sheet of sheets) { - lines.push(`style ${uri} ${absolutize(sheet)}`); - } - } - - // Output overrides - for (const [uri, newuri] of this.override) { - lines.push(`override ${uri} ${newuri}`); - } - - return lines.join("\n"); - } -} |
