toolkit/components/workerloader/require.js

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5
michael@0 6 /**
michael@0 7 * Implementation of a CommonJS module loader for workers.
michael@0 8 *
michael@0 9 * Use:
michael@0 10 * // in the .js file loaded by the constructor of the worker
michael@0 11 * importScripts("resource://gre/modules/workers/require.js");
michael@0 12 * let module = require("resource://gre/modules/worker/myModule.js");
michael@0 13 *
michael@0 14 * // in myModule.js
michael@0 15 * // Load dependencies
michael@0 16 * let SimpleTest = require("resource://gre/modules/workers/SimpleTest.js");
michael@0 17 * let Logger = require("resource://gre/modules/workers/Logger.js");
michael@0 18 *
michael@0 19 * // Define things that will not be exported
michael@0 20 * let someValue = // ...
michael@0 21 *
michael@0 22 * // Export symbols
michael@0 23 * exports.foo = // ...
michael@0 24 * exports.bar = // ...
michael@0 25 *
michael@0 26 *
michael@0 27 * Note #1:
michael@0 28 * Properties |fileName| and |stack| of errors triggered from a module
michael@0 29 * contain file names that do not correspond to human-readable module paths.
michael@0 30 * Human readers should rather use properties |moduleName| and |moduleStack|.
michael@0 31 *
michael@0 32 * Note #2:
michael@0 33 * The current version of |require()| only accepts absolute URIs.
michael@0 34 *
michael@0 35 * Note #3:
michael@0 36 * By opposition to some other module loader implementations, this module
michael@0 37 * loader does not enforce separation of global objects. Consequently, if
michael@0 38 * a module modifies a global object (e.g. |String.prototype|), all other
michael@0 39 * modules in the same worker may be affected.
michael@0 40 */
michael@0 41
michael@0 42
michael@0 43 (function(exports) {
michael@0 44 "use strict";
michael@0 45
michael@0 46 if (exports.require) {
michael@0 47 // Avoid double-imports
michael@0 48 return;
michael@0 49 }
michael@0 50
michael@0 51 // Simple implementation of |require|
michael@0 52 let require = (function() {
michael@0 53
michael@0 54 /**
michael@0 55 * Mapping from module paths to module exports.
michael@0 56 *
michael@0 57 * @keys {string} The absolute path to a module.
michael@0 58 * @values {object} The |exports| objects for that module.
michael@0 59 */
michael@0 60 let modules = new Map();
michael@0 61
michael@0 62 /**
michael@0 63 * Mapping from object urls to module paths.
michael@0 64 */
michael@0 65 let paths = {
michael@0 66 /**
michael@0 67 * @keys {string} The object url holding a module.
michael@0 68 * @values {string} The absolute path to that module.
michael@0 69 */
michael@0 70 _map: new Map(),
michael@0 71 /**
michael@0 72 * A regexp that may be used to search for all mapped paths.
michael@0 73 */
michael@0 74 get regexp() {
michael@0 75 if (this._regexp) {
michael@0 76 return this._regexp;
michael@0 77 }
michael@0 78 let objectURLs = [];
michael@0 79 for (let [objectURL, _] of this._map) {
michael@0 80 objectURLs.push(objectURL);
michael@0 81 }
michael@0 82 return this._regexp = new RegExp(objectURLs.join("|"), "g");
michael@0 83 },
michael@0 84 _regexp: null,
michael@0 85 /**
michael@0 86 * Add a mapping from an object url to a path.
michael@0 87 */
michael@0 88 set: function(url, path) {
michael@0 89 this._regexp = null; // invalidate regexp
michael@0 90 this._map.set(url, path);
michael@0 91 },
michael@0 92 /**
michael@0 93 * Get a mapping from an object url to a path.
michael@0 94 */
michael@0 95 get: function(url) {
michael@0 96 return this._map.get(url);
michael@0 97 },
michael@0 98 /**
michael@0 99 * Transform a string by replacing all the instances of objectURLs
michael@0 100 * appearing in that string with the corresponding module path.
michael@0 101 *
michael@0 102 * This is used typically to translate exception stacks.
michael@0 103 *
michael@0 104 * @param {string} source A source string.
michael@0 105 * @return {string} The same string as |source|, in which every occurrence
michael@0 106 * of an objectURL registered in this object has been replaced with the
michael@0 107 * corresponding module path.
michael@0 108 */
michael@0 109 substitute: function(source) {
michael@0 110 let map = this._map;
michael@0 111 return source.replace(this.regexp, function(url) {
michael@0 112 return map.get(url) || url;
michael@0 113 }, "g");
michael@0 114 }
michael@0 115 };
michael@0 116
michael@0 117 /**
michael@0 118 * A human-readable version of |stack|.
michael@0 119 *
michael@0 120 * @type {string}
michael@0 121 */
michael@0 122 Object.defineProperty(Error.prototype, "moduleStack",
michael@0 123 {
michael@0 124 get: function() {
michael@0 125 return paths.substitute(this.stack);
michael@0 126 }
michael@0 127 });
michael@0 128 /**
michael@0 129 * A human-readable version of |fileName|.
michael@0 130 *
michael@0 131 * @type {string}
michael@0 132 */
michael@0 133 Object.defineProperty(Error.prototype, "moduleName",
michael@0 134 {
michael@0 135 get: function() {
michael@0 136 return paths.substitute(this.fileName);
michael@0 137 }
michael@0 138 });
michael@0 139
michael@0 140 /**
michael@0 141 * Import a module
michael@0 142 *
michael@0 143 * @param {string} path The path to the module.
michael@0 144 * @return {*} An object containing the properties exported by the module.
michael@0 145 */
michael@0 146 return function require(path) {
michael@0 147 if (typeof path != "string" || path.indexOf("://") == -1) {
michael@0 148 throw new TypeError("The argument to require() must be a string uri, got " + path);
michael@0 149 }
michael@0 150 // Automatically add ".js" if there is no extension
michael@0 151 let uri;
michael@0 152 if (path.lastIndexOf(".") <= path.lastIndexOf("/")) {
michael@0 153 uri = path + ".js";
michael@0 154 } else {
michael@0 155 uri = path;
michael@0 156 }
michael@0 157
michael@0 158 // Exports provided by the module
michael@0 159 let exports = Object.create(null);
michael@0 160
michael@0 161 // Identification of the module
michael@0 162 let module = {
michael@0 163 id: path,
michael@0 164 uri: uri,
michael@0 165 exports: exports
michael@0 166 };
michael@0 167
michael@0 168 // Make module available immediately
michael@0 169 // (necessary in case of circular dependencies)
michael@0 170 if (modules.has(path)) {
michael@0 171 return modules.get(path).exports;
michael@0 172 }
michael@0 173 modules.set(path, module);
michael@0 174
michael@0 175 let name = ":" + path;
michael@0 176 let objectURL;
michael@0 177 try {
michael@0 178 // Load source of module, synchronously
michael@0 179 let xhr = new XMLHttpRequest();
michael@0 180 xhr.open("GET", uri, false);
michael@0 181 xhr.responseType = "text";
michael@0 182 xhr.send();
michael@0 183
michael@0 184
michael@0 185 let source = xhr.responseText;
michael@0 186 if (source == "") {
michael@0 187 // There doesn't seem to be a better way to detect that the file couldn't be found
michael@0 188 throw new Error("Could not find module " + path);
michael@0 189 }
michael@0 190 // From the source, build a function and an object URL. We
michael@0 191 // avoid any newline at the start of the file to ensure that
michael@0 192 // we do not mess up with line numbers. However, using object URLs
michael@0 193 // messes up with stack traces in instances of Error().
michael@0 194 source = "require._tmpModules[\"" + name + "\"] = " +
michael@0 195 "function(exports, require, module) {" +
michael@0 196 source +
michael@0 197 "\n}\n";
michael@0 198 let blob = new Blob(
michael@0 199 [
michael@0 200 (new TextEncoder()).encode(source)
michael@0 201 ], {
michael@0 202 type: "application/javascript"
michael@0 203 });
michael@0 204 objectURL = URL.createObjectURL(blob);
michael@0 205 paths.set(objectURL, path);
michael@0 206 importScripts(objectURL);
michael@0 207 require._tmpModules[name].call(null, exports, require, module);
michael@0 208
michael@0 209 } catch (ex) {
michael@0 210 // Module loading has failed, exports should not be made available
michael@0 211 // after all.
michael@0 212 modules.delete(path);
michael@0 213 throw ex;
michael@0 214 } finally {
michael@0 215 if (objectURL) {
michael@0 216 // Clean up the object url as soon as possible. It will not be needed.
michael@0 217 URL.revokeObjectURL(objectURL);
michael@0 218 }
michael@0 219 delete require._tmpModules[name];
michael@0 220 }
michael@0 221
michael@0 222 Object.freeze(module.exports);
michael@0 223 Object.freeze(module);
michael@0 224 return module.exports;
michael@0 225 };
michael@0 226 })();
michael@0 227
michael@0 228 /**
michael@0 229 * An object used to hold temporarily the module constructors
michael@0 230 * while they are being loaded.
michael@0 231 *
michael@0 232 * @keys {string} The path to the module, prefixed with ":".
michael@0 233 * @values {function} A function wrapping the module.
michael@0 234 */
michael@0 235 require._tmpModules = Object.create(null);
michael@0 236 Object.freeze(require);
michael@0 237
michael@0 238 Object.defineProperty(exports, "require", {
michael@0 239 value: require,
michael@0 240 enumerable: true,
michael@0 241 configurable: false
michael@0 242 });
michael@0 243 })(this);

mercurial