diff --git a/src/node.js b/src/node.js index 1e81684fc9..f96eeb719e 100644 --- a/src/node.js +++ b/src/node.js @@ -1,16 +1,38 @@ -// module search paths -node.includes = ["."]; +// Timers + +function setTimeout (callback, delay) { + var timer = new node.Timer(callback, delay, 0); + timer.start(); + return timer; +} + +function setInterval (callback, delay) { + var timer = new node.Timer(callback, delay, delay); + timer.start(); + return timer; +} + +function clearTimeout (timer) { + timer.stop(); + delete timer; +} + +clearInterval = clearTimeout; // This is useful for dealing with raw encodings. Array.prototype.encodeUtf8 = function () { return String.fromCharCode.apply(String, this); -} +}; node.path = new function () { this.join = function () { var joined = ""; for (var i = 0; i < arguments.length; i++) { var part = arguments[i].toString(); + + if (part === ".") continue; + while (/^\.\//.exec(part)) part = part.replace(/^\.\//, ""); + if (i === 0) { part = part.replace(/\/*$/, "/"); } else if (i === arguments.length - 1) { @@ -32,149 +54,93 @@ node.path = new function () { }; }; -// Timers - -function setTimeout (callback, delay) { - var timer = new node.Timer(callback, delay, 0); - timer.start(); - return timer; -}; - -function setInterval (callback, delay) { - var timer = new node.Timer(callback, delay, delay); - timer.start(); - return timer; -}; - -function clearTimeout (timer) { - timer.stop(); - delete timer; -}; -clearInterval = clearTimeout; +// Module -// Modules +node.Module = function (o) { + this.parent = o.parent; + this.target = o.target || {}; -(function () { - function findScript(base_directory, name, callback) { - // in the future this function will be more complicated - if (name.charAt(0) == "/") - throw "absolute module paths are not yet supported."; + if (!o.path) throw "path argument required"; + if (o.path.charAt(0) == "/") + throw "Absolute module paths are not yet supported in Node"; - var filename = node.path.join(base_directory, name) + ".js"; + var dir = o.base_directory || "."; + this.filename = node.path.join(dir, o.path); - node.fs.exists(filename, function (status) { - callback(status ? filename : null); - }); - } + this.loaded = false; + this.exited = false; + this.children = []; +}; - // Constructor for submodule. - // "name" is like a path but without .js. e.g. "database/mysql" - // "target" is an object into which the submodule will be loaded. - function Sub (name, target) { - this.name = name; - this.target = target; - - this.load = function (base_directory, callback) { - //node.debug("sub.load from <" + base_directory + "> " + this.toString()); - findScript(base_directory, name, function (filename) { - if (filename === null) { - stderr.puts("Cannot find a script matching: " + name); - node.exit(1); - } - loadScript(filename, target, callback); - }); - }; - - this.toString = function () { - return "[sub name=" + name + " target=" + target.toString() + "]"; - } - } +node.Module.prototype.load = function (callback) { + var self = this; + if (self.loaded) + throw "Module '" + self.filename + "' is already loaded."; - function Scaffold (source, filename, module) { - // wrap the source in a strange function - var source = "function (__filename) {" - + " var onLoad;" - + " var exports = this;" - + " var require = this.__require;" - + " var include = this.__include;" - + source - + " this.__onLoad = onLoad;" - + "};" - ; - // returns the function - var compiled = node.compile(source, filename); - - if (module.__onLoad) { - //node.debug("<"+ filename+"> has onload! this is bad"); + node.fs.cat(self.filename, "utf8", function (status, content) { + if (status != 0) { + stderr.puts("Error reading " + self.filename); + node.exit(1); } - module.__subs = []; - module.__require = function (name) { - var target = {}; - module.__subs.push(new Sub(name, target)); - return target; - } - module.__include = function (name) { - module.__subs.push(new Sub(name, module)); - } - // execute the script of interest - compiled.apply(module, [filename]); - - // The module still needs to have its submodules loaded. - this.filename = filename; - this.module = module; - this.subs = module.__subs; - this.onLoad = module.__onLoad; - - // remove these references so they don't get exported. - delete module.__subs; - delete module.__onLoad; - delete module.__require; - delete module.__include; - } - - function loadScript (filename, target, callback) { - node.fs.cat(filename, "utf8", function (status, content) { - if (status != 0) { - stderr.puts("Error reading " + filename); - node.exit(1); - } + self.target.__require = function (path) { return self.newChild(path, {}); }; + self.target.__include = function (path) { self.newChild(path, self.target); }; + + // create wrapper function + var wrapper = "function (__filename) {\n" + + " var onLoad;\n" + + " var onExit;\n" + + " var exports = this;\n" + + " var require = this.__require;\n" + + " var include = this.__include;\n" + + content + + "\n" + + " this.__onLoad = onLoad;\n" + + " this.__onExit = onExit;\n" + + "};\n" + ; + var compiled_wrapper = node.compile(wrapper, self.filename); - var scaffold = new Scaffold(content, filename, target); - - //node.debug("after scaffold <" + filename + ">"); - - function finish() { - //node.debug("finish 1 load <" + filename + ">"); - if (scaffold.onLoad instanceof Function) { - //node.debug("calling onLoad for <" + filename + ">"); - scaffold.onLoad(); - } - //node.debug("finish 2 load <" + filename + ">"); + // execute the script of interest + compiled_wrapper.apply(self.target, [self.filename]); + self.onLoad = self.target.__onLoad; + self.onExit = self.target.__onExit; + + self.loadChildren(function () { + if (self.onLoad) self.onLoad(); + self.loaded = true; + if (callback) callback(); + }); + }); +}; - if (callback instanceof Function) - callback(); - } +node.Module.prototype.newChild = function (path, target) { + var child = new node.Module({ + target: target, + path: path, + base_directory: node.path.dirname(this.filename), + parent: this + }); + this.children.push(child); + return target; +}; - // Each time require() or include() was called inside the script - // a key/value was added to scaffold.__subs. - // Now we loop though each one and recursively load each. - if (scaffold.subs.length == 0) { - finish(); - } else { - var ncomplete = 0; - for (var i = 0; i < scaffold.subs.length; i++) { - var sub = scaffold.subs[i]; - sub.load(node.path.dirname(filename), function () { - ncomplete += 1; - //node.debug("<" + filename + "> ncomplete = " + ncomplete.toString() + " scaffold.subs.length = " + scaffold.subs.length.toString()); - if (ncomplete === scaffold.subs.length) - finish(); - }); - } - } +node.Module.prototype.loadChildren = function (callback) { + var children = this.children; + if (children.length == 0 && callback) callback(); + var nloaded = 0; + for (var i = 0; i < children.length; i++) { + var child = children[i]; + child.load(function () { + nloaded += 1; + if (nloaded == children.length && callback) callback(); }); } +}; + +node.Module.prototype.exit = function (callback) { + throw "not implemented"; +}; - loadScript(ARGV[1], this); -})(); +// Load the root module. I.E. the command line argument. +(new node.Module({ path: ARGV[1], target: this })).load(); diff --git a/test/fixtures/a.js b/test/fixtures/a.js index 111417ac1c..d1405e2d16 100644 --- a/test/fixtures/a.js +++ b/test/fixtures/a.js @@ -1,5 +1,10 @@ -var c = require("b/c"); +var c = require("b/c.js"); exports.A = function () { return "A"; -} -exports.C = function () { return c.C(); } +}; +exports.C = function () { + return c.C(); +}; +exports.D = function () { + return c.D(); +}; diff --git a/test/fixtures/b/c.js b/test/fixtures/b/c.js index 3524a64601..72b539e729 100644 --- a/test/fixtures/b/c.js +++ b/test/fixtures/b/c.js @@ -1,3 +1,9 @@ +var d = require("d.js"); + exports.C = function () { return "C"; -} +}; + +exports.D = function () { + return d.D(); +}; diff --git a/test/fixtures/b/d.js b/test/fixtures/b/d.js new file mode 100644 index 0000000000..e7ae0e8d1a --- /dev/null +++ b/test/fixtures/b/d.js @@ -0,0 +1,4 @@ +exports.D = function () { + return "D"; +}; + diff --git a/test/test-cat-noexist.js b/test/test-cat-noexist.js index 961f6ecf5a..a460feff81 100644 --- a/test/test-cat-noexist.js +++ b/test/test-cat-noexist.js @@ -1,4 +1,4 @@ -include("mjsunit"); +include("mjsunit.js"); function onLoad () { var dirname = node.path.dirname(__filename); diff --git a/test/test-file-open.js b/test/test-file-open.js index 98da2f7dff..ad33a97f37 100644 --- a/test/test-file-open.js +++ b/test/test-file-open.js @@ -1,4 +1,4 @@ -include("mjsunit"); +include("mjsunit.js"); var assert_count = 0; function onLoad () { diff --git a/test/test-http-server.js b/test/test-http-server.js index a813d0afd2..9ea99228d5 100644 --- a/test/test-http-server.js +++ b/test/test-http-server.js @@ -1,4 +1,4 @@ -include("mjsunit"); +include("mjsunit.js"); var port = 8222; diff --git a/test/test-module-loading.js b/test/test-module-loading.js new file mode 100644 index 0000000000..aa4c28823a --- /dev/null +++ b/test/test-module-loading.js @@ -0,0 +1,23 @@ +include("mjsunit.js"); +var a = require("fixtures/a.js"); +var d = require("fixtures/b/d.js"); +var d2 = require("fixtures/b/d.js"); + +function onLoad () { + assertFalse(false, "testing the test program."); + + assertInstanceof(a.A, Function); + assertEquals("A", a.A()); + + assertInstanceof(a.C, Function); + assertEquals("C", a.C()); + + assertInstanceof(a.D, Function); + assertEquals("D", a.D()); + + assertInstanceof(d.D, Function); + assertEquals("D", d.D()); + + assertInstanceof(d2.D, Function); + assertEquals("D", d2.D()); +} diff --git a/test/test-pingpong.js b/test/test-pingpong.js index 5eff9bb3cd..b373d820a5 100644 --- a/test/test-pingpong.js +++ b/test/test-pingpong.js @@ -1,4 +1,4 @@ -include("mjsunit"); +include("mjsunit.js"); var port = 12123; var N = 1000; diff --git a/test/test-reconnecting-socket.js b/test/test-reconnecting-socket.js index 593fb5ef42..f3464be164 100644 --- a/test/test-reconnecting-socket.js +++ b/test/test-reconnecting-socket.js @@ -1,4 +1,4 @@ -include("mjsunit"); +include("mjsunit.js"); var port = 8921; function onLoad () { diff --git a/test/test-setTimeout.js b/test/test-setTimeout.js index 8973bc9eae..718373c607 100644 --- a/test/test-setTimeout.js +++ b/test/test-setTimeout.js @@ -1,4 +1,4 @@ -include("mjsunit"); +include("mjsunit.js"); function onLoad () { assertInstanceof(setTimeout, Function); diff --git a/test/test-test.js b/test/test-test.js deleted file mode 100644 index 41906740ce..0000000000 --- a/test/test-test.js +++ /dev/null @@ -1,12 +0,0 @@ -include("mjsunit"); -var a = require("fixtures/a"); - -function onLoad () { - assertFalse(false, "testing the test program."); - - assertInstanceof(a.A, Function); - assertEquals("A", a.A()); - - assertInstanceof(a.C, Function); - assertEquals("C", a.C()); -} diff --git a/website/api.html b/website/api.html index 00a9a7904f..d67e67a4e4 100644 --- a/website/api.html +++ b/website/api.html @@ -880,7 +880,7 @@ req.finish(function (res) {

The contents of foo.js:

-include("mjsunit");
+include("mjsunit.js");
 function onLoad () {
   assertEquals(1, 2);
 }
@@ -900,12 +900,11 @@ exports.assertEquals = function (expected, found, name_opt) { };

- The module mjsunit has exported a function + The module mjsunit.js has exported a function assertEquals(). mjsunit.js must be in the same directory as foo.js for include() to find it. The module path is relative - to the file calling include(). The module path does - not include filename extensions like .js. + to the file calling include().

@@ -935,7 +934,7 @@ exports.assertEquals = function (expected, found, name_opt) { after the onLoad() callback is made. For example:

-var mjsunit = require("mjsunit");
+var mjsunit = require("mjsunit.js");
 function onLoad () {
   mjsunit.assertEquals(1, 2);
 }