Bug 756887 - Require.jsm should have support and tests for firebug/NetMonitor style modules; r=robcee
authorJoe Walker <jwalker@mozilla.com>
Wed, 30 May 2012 08:47:28 +0100
changeset 95254 e27fa361af61850f4e7755df975d56cf9d97db8a
parent 95253 3e44979fad652236998d3c356e01a3728d6a9272
child 95255 806f4c2ec2e29be14364392a85b33df8bef427ff
push id22796
push userdcamp@campd.org
push dateThu, 31 May 2012 02:21:39 +0000
treeherdermozilla-central@fccdf5c4feda [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrobcee
bugs756887
milestone15.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 756887 - Require.jsm should have support and tests for firebug/NetMonitor style modules; r=robcee
browser/devtools/shared/Require.jsm
browser/devtools/shared/test/browser_require_basic.js
--- a/browser/devtools/shared/Require.jsm
+++ b/browser/devtools/shared/Require.jsm
@@ -26,69 +26,61 @@ const console = (function() {
 /**
  * Define a module along with a payload.
  * @param moduleName Name for the payload
  * @param deps Ignored. For compatibility with CommonJS AMD Spec
  * @param payload Function with (require, exports, module) params
  */
 function define(moduleName, deps, payload) {
   if (typeof moduleName != "string") {
-    console.error(this.depth + " Error: Module name is not a string.");
-    console.trace();
-    return;
+    throw new Error("Error: Module name is not a string");
   }
 
   if (arguments.length == 2) {
     payload = deps;
   }
   else {
     payload.deps = deps;
   }
 
   if (define.debugDependencies) {
     console.log("define: " + moduleName + " -> " + payload.toString()
         .slice(0, 40).replace(/\n/, '\\n').replace(/\r/, '\\r') + "...");
   }
 
   if (moduleName in define.modules) {
-    console.error(this.depth + " Error: Redefining module: " + moduleName);
+    throw new Error("Error: Redefining module: " + moduleName);
   }
+
+  // Mark the payload so we know we need to call it to get the real module
+  payload.__uncompiled = true;
   define.modules[moduleName] = payload;
 }
 
 /**
  * The global store of un-instantiated modules
  */
 define.modules = {};
 
 /**
  * Should we console.log on module definition/instantiation/requirement?
  */
 define.debugDependencies = false;
 
 
 /**
- * Self executing function in which Domain is defined, and attached to define
- */
-var Syntax = {
-  COMMON_JS: 'commonjs',
-  AMD: 'amd'
-};
-
-/**
  * We invoke require() in the context of a Domain so we can have multiple
  * sets of modules running separate from each other.
  * This contrasts with JSMs which are singletons, Domains allows us to
  * optionally load a CommonJS module twice with separate data each time.
  * Perhaps you want 2 command lines with a different set of commands in each,
  * for example.
  */
 function Domain() {
   this.modules = {};
-  this.syntax = Syntax.COMMON_JS;
 
   if (define.debugDependencies) {
     this.depth = "";
   }
 }
 
 /**
  * Lookup module names and resolve them by calling the definition function if
@@ -106,17 +98,16 @@ function Domain() {
 Domain.prototype.require = function(config, deps, callback) {
   if (arguments.length <= 2) {
     callback = deps;
     deps = config;
     config = undefined;
   }
 
   if (Array.isArray(deps)) {
-    this.syntax = Syntax.AMD;
     var params = deps.map(function(dep) {
       return this.lookup(dep);
     }, this);
     if (callback) {
       callback.apply(null, params);
     }
     return undefined;
   }
@@ -136,49 +127,52 @@ Domain.prototype.lookup = function(modul
     var module = this.modules[moduleName];
     if (define.debugDependencies) {
       console.log(this.depth + " Using module: " + moduleName);
     }
     return module;
   }
 
   if (!(moduleName in define.modules)) {
-    console.error(this.depth + " Missing module: " + moduleName);
-    return null;
+    throw new Error("Missing module: " + moduleName);
   }
 
   var module = define.modules[moduleName];
 
   if (define.debugDependencies) {
     console.log(this.depth + " Compiling module: " + moduleName);
   }
 
-  if (typeof module == "function") {
+  if (module.__uncompiled) {
     if (define.debugDependencies) {
       this.depth += ".";
     }
 
-    var exports;
+    var exports = {};
     try {
-      if (this.syntax === Syntax.COMMON_JS) {
-        exports = {};
-        module(this.require.bind(this), exports, { id: moduleName, uri: "" });
-      }
-      else {
-        var modules = module.deps.map(function(dep) {
-          return this.lookup(dep);
-        }.bind(this));
-        exports = module.apply(null, modules);
-      }
+      var params = module.deps.map(function(dep) {
+        if (dep === "require") {
+          return this.require.bind(this);
+        }
+        if (dep === "exports") {
+          return exports;
+        }
+        if (dep === "module") {
+          return { id: moduleName, uri: "" };
+        }
+        return this.lookup(dep);
+      }.bind(this));
+
+      var reply = module.apply(null, params);
+      module = (reply !== undefined) ? reply : exports;
     }
     catch (ex) {
-      console.error("Error using module: " + moduleName, ex);
+      dump("Error using module '" + moduleName + "' - " + ex + "\n");
       throw ex;
     }
-    module = exports;
 
     if (define.debugDependencies) {
       this.depth = this.depth.slice(0, -1);
     }
   }
 
   // cache the resulting module object for next time
   this.modules[moduleName] = module;
--- a/browser/devtools/shared/test/browser_require_basic.js
+++ b/browser/devtools/shared/test/browser_require_basic.js
@@ -16,47 +16,54 @@ function test() {
     setup();
 
     testWorking();
     testDomains();
     testLeakage();
     testMultiImport();
     testRecursive();
     testUncompilable();
+    testFirebug();
 
     shutdown();
   });
 }
 
 function setup() {
-  define('gclitest/requirable', [], function(require, exports, module) {
+  define('gclitest/requirable', [ 'require', 'exports', 'module' ], function(require, exports, module) {
     exports.thing1 = 'thing1';
     exports.thing2 = 2;
 
     let status = 'initial';
     exports.setStatus = function(aStatus) { status = aStatus; };
     exports.getStatus = function() { return status; };
   });
 
-  define('gclitest/unrequirable', [], function(require, exports, module) {
+  define('gclitest/unrequirable', [ 'require', 'exports', 'module' ], function(require, exports, module) {
     null.throwNPE();
   });
 
-  define('gclitest/recurse', [], function(require, exports, module) {
+  define('gclitest/recurse', [ 'require', 'exports', 'module', 'gclitest/recurse' ], function(require, exports, module) {
     require('gclitest/recurse');
   });
+
+  define('gclitest/firebug', [ 'gclitest/requirable' ], function(requirable) {
+    return { requirable: requirable, fb: true };
+  });
 }
 
 function shutdown() {
   delete define.modules['gclitest/requirable'];
   delete define.globalDomain.modules['gclitest/requirable'];
   delete define.modules['gclitest/unrequirable'];
   delete define.globalDomain.modules['gclitest/unrequirable'];
   delete define.modules['gclitest/recurse'];
   delete define.globalDomain.modules['gclitest/recurse'];
+  delete define.modules['gclitest/firebug'];
+  delete define.globalDomain.modules['gclitest/firebug'];
 
   define = undefined;
   require = undefined;
 
   finish();
 }
 
 function testWorking() {
@@ -119,8 +126,15 @@ function testUncompilable() {
   }
 }
 
 function testRecursive() {
   // See Bug 658583
   // require('gclitest/recurse');
   // Also see the comments in the testRecursive() function
 }
+
+function testFirebug() {
+  let requirable = require('gclitest/requirable');
+  let firebug = require('gclitest/firebug');
+  ok(firebug.fb, 'firebug.fb is true');
+  is(requirable, firebug.requirable, 'requirable pass-through');
+}