prefs.sys.mjs (5120B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 const { PREF_BOOL, PREF_INT, PREF_INVALID, PREF_STRING } = Ci.nsIPrefBranch; 6 7 export class Branch { 8 /** 9 * @param {string=} branch 10 * Preference subtree. Uses root tree given `null`. 11 */ 12 constructor(branch) { 13 this._branch = Services.prefs.getBranch(branch); 14 } 15 16 /** 17 * Gets value of `pref` in its known type. 18 * 19 * @param {string} pref 20 * Preference name. 21 * @param {*=} fallback 22 * Fallback value to return if `pref` does not exist. 23 * 24 * @returns {(string|boolean|number)} 25 * Value of `pref`, or the `fallback` value if `pref` does 26 * not exist. 27 * 28 * @throws {TypeError} 29 * If `pref` is not a recognised preference and no `fallback` 30 * value has been provided. 31 */ 32 get(pref, fallback = null) { 33 switch (this._branch.getPrefType(pref)) { 34 case PREF_STRING: 35 return this._branch.getStringPref(pref); 36 37 case PREF_BOOL: 38 return this._branch.getBoolPref(pref); 39 40 case PREF_INT: 41 return this._branch.getIntPref(pref); 42 43 case PREF_INVALID: 44 default: 45 if (fallback != null) { 46 return fallback; 47 } 48 throw new TypeError(`Unrecognised preference: ${pref}`); 49 } 50 } 51 52 /** 53 * Sets the value of `pref`. 54 * 55 * @param {string} pref 56 * Preference name. 57 * @param {(string|boolean|number)} value 58 * `pref`'s new value. 59 * 60 * @throws {TypeError} 61 * If `value` is not the correct type for `pref`. 62 */ 63 set(pref, value) { 64 let typ; 65 if (typeof value != "undefined" && value != null) { 66 typ = value.constructor.name; 67 } 68 69 switch (typ) { 70 case "String": 71 // Unicode compliant 72 return this._branch.setStringPref(pref, value); 73 74 case "Boolean": 75 return this._branch.setBoolPref(pref, value); 76 77 case "Number": 78 return this._branch.setIntPref(pref, value); 79 80 default: 81 throw new TypeError(`Illegal preference type value: ${typ}`); 82 } 83 } 84 } 85 86 /** 87 * Provides shortcuts for lazily getting and setting typed Marionette 88 * preferences. 89 * 90 * Some of Marionette's preferences are stored using primitive values 91 * that internally are represented by complex types. 92 * 93 * Because we cannot trust the input of many of these preferences, 94 * this class provides abstraction that lets us safely deal with 95 * potentially malformed input. 96 * 97 * A further complication is that we cannot rely on `Preferences.sys.mjs` 98 * in Marionette. See https://bugzilla.mozilla.org/show_bug.cgi?id=1357517 99 * for further details. 100 */ 101 class MarionetteBranch extends Branch { 102 constructor(branch = "marionette.") { 103 super(branch); 104 } 105 106 /** 107 * The `marionette.debugging.clicktostart` preference delays 108 * server startup until a modal dialogue has been clicked to allow 109 * time for user to set breakpoints in the Browser Toolbox. 110 * 111 * @returns {boolean} 112 */ 113 get clickToStart() { 114 return this.get("debugging.clicktostart", false); 115 } 116 117 /** 118 * The `marionette.navigate-after-click.enabled` preference enables the 119 * fallback logic for Selenium clients to wait for a potential navigation 120 * after clicking an element via "WebDriver:ElementClick". 121 * 122 * @returns {boolean} 123 */ 124 get navigateAfterClickEnabled() { 125 return this.get("marionette.navigate-after-click.enabled", true); 126 } 127 128 /** 129 * The `marionette.navigate-after-click.timeout` preference defines the 130 * amount of milliseconds to wait for a potential navigation after a click 131 * event was dispatches via "WebDriver:ElementClick". 132 * 133 * @returns {number} 134 */ 135 get navigateAfterClickTimeout() { 136 return this.get("marionette.navigate-after-click.timeout", 50); 137 } 138 139 /** 140 * The `marionette.port` preference, detailing which port 141 * the TCP server should listen on. 142 * 143 * @returns {number} 144 */ 145 get port() { 146 return this.get("port", 2828); 147 } 148 149 set port(newPort) { 150 this.set("port", newPort); 151 } 152 } 153 154 /** Reads a JSON serialised blob stored in the environment. */ 155 export class EnvironmentPrefs { 156 /** 157 * Reads the environment variable `key` and tries to parse it as 158 * JSON Object, then provides an iterator over its keys and values. 159 * 160 * If the environment variable is not set, this function returns empty. 161 * 162 * @param {string} key 163 * Environment variable. 164 * 165 * @returns {Iterable.<string, (string|boolean|number)>} 166 */ 167 static *from(key) { 168 if (!Services.env.exists(key)) { 169 return; 170 } 171 172 let prefs; 173 try { 174 prefs = JSON.parse(Services.env.get(key)); 175 } catch (e) { 176 throw new TypeError(`Unable to parse prefs from ${key}`, e); 177 } 178 179 for (let prefName of Object.keys(prefs)) { 180 yield [prefName, prefs[prefName]]; 181 } 182 } 183 } 184 185 // There is a future potential of exposing this as Marionette.prefs.port 186 // if we introduce a Marionette.sys.mjs module. 187 export const MarionettePrefs = new MarionetteBranch();