Permalink
Browse files

Circular require now also works with module.exports.

  • Loading branch information...
1 parent a729886 commit 6f70cff07b954426cd0c13098345823177dcc34e @raroni raroni committed Dec 29, 2011
View
@@ -1,17 +1,23 @@
(function() {
- var CoffeeScript, Package, async, compilers, eco, extname, fs, join, normalize, _, _ref;
- var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
+ var CoffeeScript, Package, async, compilers, eco, extname, fs, join, normalize, _, _ref,
+ __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
+
_ = require('underscore');
+
async = require('async');
+
fs = require('fs');
+
_ref = require('path'), extname = _ref.extname, join = _ref.join, normalize = _ref.normalize;
+
exports.compilers = compilers = {
js: function(module, filename) {
var content;
content = fs.readFileSync(filename, 'utf8');
return module._compile(content, filename);
}
};
+
try {
CoffeeScript = require('coffee-script');
compilers.coffee = function(module, filename) {
@@ -22,6 +28,7 @@
} catch (err) {
}
+
try {
eco = require('eco');
if (eco.precompile) {
@@ -40,10 +47,13 @@
} catch (err) {
}
+
exports.Package = Package = (function() {
+
function Package(config) {
- this.compileSources = __bind(this.compileSources, this);;
- this.compileDependencies = __bind(this.compileDependencies, this);; var _ref2, _ref3, _ref4, _ref5;
+ this.compileSources = __bind(this.compileSources, this);
+ this.compileDependencies = __bind(this.compileDependencies, this);
+ var _ref2, _ref3, _ref4, _ref5;
this.identifier = (_ref2 = config.identifier) != null ? _ref2 : 'require';
this.paths = (_ref3 = config.paths) != null ? _ref3 : ['lib'];
this.dependencies = (_ref4 = config.dependencies) != null ? _ref4 : [];
@@ -52,6 +62,7 @@
this.mtimeCache = {};
this.compileCache = {};
}
+
Package.prototype.compile = function(callback) {
return async.parallel([this.compileDependencies, this.compileSources], function(err, parts) {
if (err) {
@@ -61,22 +72,24 @@
}
});
};
+
Package.prototype.compileDependencies = function(callback) {
- return async.map(this.dependencies, fs.readFile, __bind(function(err, dependencySources) {
+ var _this = this;
+ return async.map(this.dependencies, fs.readFile, function(err, dependencySources) {
if (err) {
return callback(err);
} else {
return callback(null, dependencySources.join("\n"));
}
- }, this));
+ });
};
+
Package.prototype.compileSources = function(callback) {
- return async.reduce(this.paths, {}, _.bind(this.gatherSourcesFromPath, this), __bind(function(err, sources) {
+ var _this = this;
+ return async.reduce(this.paths, {}, _.bind(this.gatherSourcesFromPath, this), function(err, sources) {
var filename, index, name, result, source, _ref2;
- if (err) {
- return callback(err);
- }
- result = "(function(/*! Stitch !*/) {\n if (!this." + this.identifier + ") {\n var modules = {}, cache = {}, require = function(name, root) {\n var module = cache[name], path = expand(root, name), fn;\n if (module) {\n return module;\n } else if (fn = modules[path] || modules[path = expand(path, './index')]) {\n module = {id: name, exports: {}};\n try {\n cache[name] = module.exports;\n fn(module.exports, function(name) {\n return require(name, dirname(path));\n }, module);\n return cache[name] = module.exports;\n } catch (err) {\n delete cache[name];\n throw err;\n }\n } else {\n throw 'module \\'' + name + '\\' not found';\n }\n }, expand = function(root, name) {\n var results = [], parts, part;\n if (/^\\.\\.?(\\/|$)/.test(name)) {\n parts = [root, name].join('/').split('/');\n } else {\n parts = name.split('/');\n }\n for (var i = 0, length = parts.length; i < length; i++) {\n part = parts[i];\n if (part == '..') {\n results.pop();\n } else if (part != '.' && part != '') {\n results.push(part);\n }\n }\n return results.join('/');\n }, dirname = function(path) {\n return path.split('/').slice(0, -1).join('/');\n };\n this." + this.identifier + " = function(name) {\n return require(name, '');\n }\n this." + this.identifier + ".define = function(bundle) {\n for (var key in bundle)\n modules[key] = bundle[key];\n };\n }\n return this." + this.identifier + ".define;\n}).call(this)({";
+ if (err) return callback(err);
+ result = "(function(/*! Stitch !*/) {\n if (!this." + _this.identifier + ") {\n var modules = {}, cache = {}, require = function(name, root) {\n var path = expand(root, name), module = cache[path], fn;\n if (module) {\n return module.exports;\n } else if (fn = modules[path] || modules[path = expand(path, './index')]) {\n module = {id: path, exports: {}};\n try {\n cache[path] = module;\n fn(module.exports, function(name) {\n return require(name, dirname(path));\n }, module);\n return module.exports;\n } catch (err) {\n delete cache[path];\n throw err;\n }\n } else {\n throw 'module \\'' + name + '\\' not found';\n }\n }, expand = function(root, name) {\n var results = [], parts, part;\n if (/^\\.\\.?(\\/|$)/.test(name)) {\n parts = [root, name].join('/').split('/');\n } else {\n parts = name.split('/');\n }\n for (var i = 0, length = parts.length; i < length; i++) {\n part = parts[i];\n if (part == '..') {\n results.pop();\n } else if (part != '.' && part != '') {\n results.push(part);\n }\n }\n return results.join('/');\n }, dirname = function(path) {\n return path.split('/').slice(0, -1).join('/');\n };\n this." + _this.identifier + " = function(name) {\n return require(name, '');\n }\n this." + _this.identifier + ".define = function(bundle) {\n for (var key in bundle)\n modules[key] = bundle[key];\n };\n }\n return this." + _this.identifier + ".define;\n}).call(this)({";
index = 0;
for (name in sources) {
_ref2 = sources[name], filename = _ref2.filename, source = _ref2.source;
@@ -86,11 +99,13 @@
}
result += "});\n";
return callback(err, result);
- }, this));
+ });
};
+
Package.prototype.createServer = function() {
- return __bind(function(req, res, next) {
- return this.compile(function(err, source) {
+ var _this = this;
+ return function(req, res, next) {
+ return _this.compile(function(err, source) {
var message;
if (err) {
console.error("" + err.stack);
@@ -106,32 +121,30 @@
return res.end(source);
}
});
- }, this);
+ };
};
+
Package.prototype.gatherSourcesFromPath = function(sources, sourcePath, callback) {
- return fs.stat(sourcePath, __bind(function(err, stat) {
- if (err) {
- return callback(err);
- }
+ var _this = this;
+ return fs.stat(sourcePath, function(err, stat) {
+ if (err) return callback(err);
if (stat.isDirectory()) {
- return this.getFilesInTree(sourcePath, __bind(function(err, paths) {
- if (err) {
- return callback(err);
- }
- return async.reduce(paths, sources, _.bind(this.gatherCompilableSource, this), callback);
- }, this));
+ return _this.getFilesInTree(sourcePath, function(err, paths) {
+ if (err) return callback(err);
+ return async.reduce(paths, sources, _.bind(_this.gatherCompilableSource, _this), callback);
+ });
} else {
- return this.gatherCompilableSource(sources, sourcePath, callback);
+ return _this.gatherCompilableSource(sources, sourcePath, callback);
}
- }, this));
+ });
};
+
Package.prototype.gatherCompilableSource = function(sources, path, callback) {
+ var _this = this;
if (this.compilers[extname(path).slice(1)]) {
- return this.getRelativePath(path, __bind(function(err, relativePath) {
- if (err) {
- return callback(err);
- }
- return this.compileFile(path, function(err, source) {
+ return this.getRelativePath(path, function(err, relativePath) {
+ if (err) return callback(err);
+ return _this.compileFile(path, function(err, source) {
var extension, key;
if (err) {
return callback(err);
@@ -145,21 +158,19 @@
return callback(err, sources);
}
});
- }, this));
+ });
} else {
return callback(null, sources);
}
};
+
Package.prototype.getRelativePath = function(path, callback) {
- return fs.realpath(path, __bind(function(err, sourcePath) {
- if (err) {
- return callback(err);
- }
- return async.map(this.paths, fs.realpath, function(err, expandedPaths) {
+ var _this = this;
+ return fs.realpath(path, function(err, sourcePath) {
+ if (err) return callback(err);
+ return async.map(_this.paths, fs.realpath, function(err, expandedPaths) {
var base, expandedPath, _i, _len;
- if (err) {
- return callback(err);
- }
+ if (err) return callback(err);
for (_i = 0, _len = expandedPaths.length; _i < _len; _i++) {
expandedPath = expandedPaths[_i];
base = expandedPath + "/";
@@ -169,10 +180,11 @@
}
return callback(new Error("" + path + " isn't in the require path"));
});
- }, this));
+ });
};
+
Package.prototype.compileFile = function(path, callback) {
- var compile, err, extension, mod, mtime, source;
+ var compile, extension, mod, mtime, source;
extension = extname(path).slice(1);
if (this.cache && this.compileCache[path] && this.mtimeCache[path] === this.compileCache[path].mtime) {
return callback(null, this.compileCache[path].source);
@@ -204,22 +216,20 @@
return callback(new Error("no compiler for '." + extension + "' files"));
}
};
+
Package.prototype.walkTree = function(directory, callback) {
- return fs.readdir(directory, __bind(function(err, files) {
- if (err) {
- return callback(err);
- }
- return async.forEach(files, __bind(function(file, next) {
+ var _this = this;
+ return fs.readdir(directory, function(err, files) {
+ if (err) return callback(err);
+ return async.forEach(files, function(file, next) {
var filename;
- if (file.match(/^\./)) {
- return next();
- }
+ if (file.match(/^\./)) return next();
filename = join(directory, file);
- return fs.stat(filename, __bind(function(err, stats) {
+ return fs.stat(filename, function(err, stats) {
var _ref2;
- this.mtimeCache[filename] = stats != null ? (_ref2 = stats.mtime) != null ? _ref2.toString() : void 0 : void 0;
+ _this.mtimeCache[filename] = stats != null ? (_ref2 = stats.mtime) != null ? _ref2.toString() : void 0 : void 0;
if (!err && stats.isDirectory()) {
- return this.walkTree(filename, function(err, filename) {
+ return _this.walkTree(filename, function(err, filename) {
if (filename) {
return callback(err, filename);
} else {
@@ -230,10 +240,11 @@
callback(err, filename);
return next();
}
- }, this));
- }, this), callback);
- }, this));
+ });
+ }, callback);
+ });
};
+
Package.prototype.getFilesInTree = function(directory, callback) {
var files;
files = [];
@@ -247,9 +258,13 @@
}
});
};
+
return Package;
+
})();
+
exports.createPackage = function(config) {
return new Package(config);
};
+
}).call(this);
View
@@ -61,19 +61,19 @@ exports.Package = class Package
(function(/*! Stitch !*/) {
if (!this.#{@identifier}) {
var modules = {}, cache = {}, require = function(name, root) {
- var module = cache[name], path = expand(root, name), fn;
+ var path = expand(root, name), module = cache[path], fn;
if (module) {
- return module;
+ return module.exports;
} else if (fn = modules[path] || modules[path = expand(path, './index')]) {
- module = {id: name, exports: {}};
+ module = {id: path, exports: {}};
try {
- cache[name] = module.exports;
+ cache[path] = module;
fn(module.exports, function(name) {
return require(name, dirname(path));
}, module);
- return cache[name] = module.exports;
+ return module.exports;
} catch (err) {
- delete cache[name];
+ delete cache[path];
throw err;
}
} else {
@@ -1,4 +0,0 @@
-exports.a = function() {
- return "a";
-};
-exports.b = require("./b").b;
@@ -1,2 +1,2 @@
-exports.a = require('./a');
+exports.a = require('./using_exports_a');
throw 'hello';
@@ -1,2 +1,4 @@
-exports.a = require("./a");
-exports.b = require("./b");
+exports.using_exports_a = require("./using_exports_a");
+exports.using_exports_b = require("./using_exports_b");
+exports.using_module_exports_a = require("./using_module_exports_a");
+exports.using_module_exports_b = require("./using_module_exports_b");
@@ -0,0 +1,4 @@
+exports.a = function() {
+ return "a";
+};
+exports.b = require("./using_exports_b").b;
@@ -1,4 +1,4 @@
-var a = require("./a");
+var a = require("./using_exports_a");
exports.b = function() {
return a.a();
}
@@ -0,0 +1,12 @@
+var B;
+
+module.exports = {
+ a: function() {
+ return 'a';
+ },
+ b: function() {
+ return B.b()
+ }
+};
+
+B = require('./using_module_exports_b');
@@ -0,0 +1,7 @@
+A = require('./using_module_exports_a');
+
+module.exports = {
+ b: function() {
+ return A.a()
+ }
+};
@@ -8,7 +8,7 @@ altFixtures = fixtureRoot + "/alternate"
addlFixtures = fixtureRoot + "/additional"
ecoFixtures = fixtureRoot + "/eco"
linkFixtures = fixtureRoot + "/link"
-fixtureCount = 15
+fixtureCount = 17
defaultOptions =
identifier: "testRequire"
@@ -256,16 +256,21 @@ module.exports =
test.done()
"circular require": (test) ->
- test.expect 4
+ test.expect 7
defaultPackage.compile (err, sources) ->
test.ok !err
testRequire = load sources
circular = testRequire("circular")
- test.same "a", circular.a.a()
- test.same "a", circular.b.b()
- test.same "a", circular.a.b()
+ test.same "a", circular.using_exports_a.a()
+ test.same "a", circular.using_exports_b.b()
+ test.same "a", circular.using_exports_a.b()
+
+ test.same "a", circular.using_module_exports_a.a()
+ test.same "a", circular.using_module_exports_b.b()
+ test.same "a", circular.using_module_exports_a.b()
+
test.done()
"errors at require time don't leave behind a partially loaded cache": (test) ->

0 comments on commit 6f70cff

Please sign in to comment.