Bug 1499335 - Support module specifiers containing inline data in the shell r=evilpie
authorJon Coppeard <jcoppeard@mozilla.com>
Mon, 22 Oct 2018 13:33:02 +0100
changeset 490641 80235331ce5f2bc78444739b388e5d64b7970eb9
parent 490640 dedd03c893c8cfa5a721b0a04cf5b26cee98db4b
child 490642 74061c1b02a17da7d3e346d5c1e1a6cfd3e561b4
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersevilpie
bugs1499335
milestone64.0a1
Bug 1499335 - Support module specifiers containing inline data in the shell r=evilpie
js/src/jit-test/tests/modules/inline-data.js
js/src/shell/ModuleLoader.js
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/modules/inline-data.js
@@ -0,0 +1,17 @@
+// |jit-test| module
+
+import { a } from "javascript: export let a = 42;";
+assertEq(a, 42);
+
+let result = null;
+let error = null;
+let promise = import("javascript: export let b = 100;");
+promise.then((ns) => {
+    result = ns;
+}).catch((e) => {
+    error = e;
+});
+
+drainJobQueue();
+assertEq(error, null);
+assertEq(result.b, 100);
--- a/js/src/shell/ModuleLoader.js
+++ b/js/src/shell/ModuleLoader.js
@@ -3,39 +3,49 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* global getModuleLoadPath setModuleLoadHook setModuleResolveHook setModuleMetadataHook */
 /* global getModulePrivate setModulePrivate parseModule os */
 /* global setModuleDynamicImportHook finishDynamicModuleImport abortDynamicModuleImport */
 
 // A basic synchronous module loader for testing the shell.
+//
+// Supports loading files and 'javascript:' URLs that embed JS source text.
+
 {
 // Save standard built-ins before scripts can modify them.
 const ArrayPrototypeJoin = Array.prototype.join;
 const MapPrototypeGet = Map.prototype.get;
 const MapPrototypeHas = Map.prototype.has;
 const MapPrototypeSet = Map.prototype.set;
 const ObjectDefineProperty = Object.defineProperty;
 const ReflectApply = Reflect.apply;
 const StringPrototypeIndexOf = String.prototype.indexOf;
 const StringPrototypeLastIndexOf = String.prototype.lastIndexOf;
 const StringPrototypeStartsWith = String.prototype.startsWith;
 const StringPrototypeSubstring = String.prototype.substring;
 const ErrorClass = Error;
 
+const JAVASCRIPT_SCHEME = "javascript:";
+
 const ReflectLoader = new class {
     constructor() {
         this.registry = new Map();
         this.loadPath = getModuleLoadPath();
     }
 
+    isJavascriptURL(name) {
+        return ReflectApply(StringPrototypeStartsWith, name, [JAVASCRIPT_SCHEME]);
+    }
+
     resolve(name, referencingInfo) {
-        if (os.path.isAbsolute(name))
+        if (this.isJavascriptURL(name) || os.path.isAbsolute(name)) {
             return name;
+        }
 
         let loadPath = this.loadPath;
 
         // Treat |name| as a relative path if it starts with either "./"
         // or "../".
         let isRelative = ReflectApply(StringPrototypeStartsWith, name, ["./"])
                       || ReflectApply(StringPrototypeStartsWith, name, ["../"])
 #ifdef XP_WIN
@@ -62,16 +72,20 @@ const ReflectLoader = new class {
             if (sepIndex >= 0)
                 loadPath = ReflectApply(StringPrototypeSubstring, path, [0, sepIndex]);
         }
 
         return os.path.join(loadPath, name);
     }
 
     normalize(path) {
+        if (this.isJavascriptURL(path)) {
+            return path;
+        }
+
 #ifdef XP_WIN
         // Replace all forward slashes with backward slashes.
         // NB: It may be tempting to replace this loop with a call to
         // String.prototype.replace, but user scripts may have modified
         // String.prototype or RegExp.prototype built-in functions, which makes
         // it unsafe to call String.prototype.replace.
         let newPath = "";
         let lastSlash = 0;
@@ -145,16 +159,20 @@ const ReflectLoader = new class {
         let normalized = ReflectApply(ArrayPrototypeJoin, components, [pathsep]);
 #ifdef XP_WIN
         normalized = drive + normalized;
 #endif
         return normalized;
     }
 
     fetch(path) {
+        if (this.isJavascriptURL(path)) {
+            return ReflectApply(StringPrototypeSubstring, path, [JAVASCRIPT_SCHEME.length]);
+        }
+
         return os.file.readFile(path);
     }
 
     loadAndParse(path) {
         let normalized = this.normalize(path);
         if (ReflectApply(MapPrototypeHas, this.registry, [normalized]))
             return ReflectApply(MapPrototypeGet, this.registry, [normalized]);