Permalink
Browse files

Make require() compliant with CommonJS Modules/1.1

  • Loading branch information...
1 parent 539915d commit 951019eacc08403cf029526d5775f52ae5d503e5 @natecain natecain committed Oct 12, 2013
Showing with 546 additions and 37 deletions.
  1. +67 −30 boot/boot.js
  2. +20 −6 boot/bootprefix.js
  3. +7 −0 editions/testcommonjs/tiddlers/GettingStarted.tid
  4. +11 −0 editions/testcommonjs/tiddlers/absolute/b.js
  5. +16 −0 editions/testcommonjs/tiddlers/absolute/program.js
  6. +14 −0 editions/testcommonjs/tiddlers/absolute/submodule/a.js
  7. +23 −0 editions/testcommonjs/tiddlers/allTests.js
  8. +15 −0 editions/testcommonjs/tiddlers/cyclic/a.js
  9. +16 −0 editions/testcommonjs/tiddlers/cyclic/b.js
  10. +22 −0 editions/testcommonjs/tiddlers/cyclic/program.js
  11. +14 −0 editions/testcommonjs/tiddlers/determinism/program.js
  12. +20 −0 editions/testcommonjs/tiddlers/determinism/submodule/a.js
  13. +15 −0 editions/testcommonjs/tiddlers/exactExports/a.js
  14. +16 −0 editions/testcommonjs/tiddlers/exactExports/program.js
  15. +8 −0 editions/testcommonjs/tiddlers/hasOwnProperty/hasOwnProperty.js
  16. +15 −0 editions/testcommonjs/tiddlers/hasOwnProperty/program.js
  17. +8 −0 editions/testcommonjs/tiddlers/hasOwnProperty/toString.js
  18. +23 −0 editions/testcommonjs/tiddlers/method/a.js
  19. +19 −0 editions/testcommonjs/tiddlers/method/program.js
  20. +19 −0 editions/testcommonjs/tiddlers/missing/program.js
  21. +12 −0 editions/testcommonjs/tiddlers/monkeys/a.js
  22. +15 −0 editions/testcommonjs/tiddlers/monkeys/program.js
  23. +14 −0 editions/testcommonjs/tiddlers/nested/a/b/c/d.js
  24. +14 −0 editions/testcommonjs/tiddlers/nested/program.js
  25. +16 −0 editions/testcommonjs/tiddlers/relative/program.js
  26. +13 −0 editions/testcommonjs/tiddlers/relative/submodule/a.js
  27. +12 −0 editions/testcommonjs/tiddlers/relative/submodule/b.js
  28. +23 −0 editions/testcommonjs/tiddlers/test.js
  29. +11 −0 editions/testcommonjs/tiddlers/transitive/a.js
  30. +12 −0 editions/testcommonjs/tiddlers/transitive/b.js
  31. +14 −0 editions/testcommonjs/tiddlers/transitive/c.js
  32. +13 −0 editions/testcommonjs/tiddlers/transitive/program.js
  33. +8 −0 editions/testcommonjs/tiddlywiki.info
  34. +1 −1 tiddlywiki.js
View
@@ -20,23 +20,16 @@ The module definitions on the browser look like this:
In practice, each module is wrapped in a separate script block.
\*/
-(function() {
+
+var _boot = (function($tw) {
/*jslint node: true, browser: true */
/*global modules: false, $tw: false */
"use strict";
-/////////////////////////// Setting up $tw
-
-// Set up $tw global for the server (set up for browser is in bootprefix.js)
-if(typeof(window) === "undefined") {
- global.$tw = global.$tw || {}; // No `browser` member for the server
- exports.$tw = $tw; // Export $tw for when boot.js is required directly in node.js
-}
-
-// Include bootprefix if we're on the server
-if(!$tw.browser) {
- require("./bootprefix.js");
+// Include bootprefix if we're not given module data
+if(!$tw) {
+ $tw = require("./bootprefix.js").bootprefix();
}
$tw.utils = $tw.utils || {};
@@ -313,6 +306,7 @@ name `.` refers to the current directory
*/
$tw.utils.resolvePath = function(sourcepath,rootpath) {
// If the source path starts with ./ or ../ then it is relative to the root
+
if(sourcepath.substr(0,2) === "./" || sourcepath.substr(0,3) === "../" ) {
var src = sourcepath.split("/"),
root = rootpath.split("/");
@@ -332,7 +326,14 @@ $tw.utils.resolvePath = function(sourcepath,rootpath) {
return root.join("/");
} else {
// If it isn't relative, just return the path
- return sourcepath;
+ if(rootpath) {
+ var root = rootpath.split("/");
+ // Remove the filename part of the root
+ root.splice(root.length - 1, 1);
+ return root.join("/") + "/" + sourcepath;
+ } else {
+ return sourcepath;
+ }
}
};
@@ -362,9 +363,7 @@ $tw.utils.registerFileType = function(type,encoding,extension) {
Run code globally with specified context variables in scope
*/
$tw.utils.evalGlobal = function(code,context,filename) {
- var contextCopy = $tw.utils.extend({},context,{
- exports: {}
- });
+ var contextCopy = $tw.utils.extend({},context);
// Get the context variables as a pair of arrays of names and values
var contextNames = [], contextValues = [];
$tw.utils.each(contextCopy,function(value,name) {
@@ -389,9 +388,6 @@ Run code in a sandbox with only the specified context variables in scope
*/
$tw.utils.evalSandboxed = $tw.browser ? $tw.utils.evalGlobal : function(code,context,filename) {
var sandbox = $tw.utils.extend({},context);
- $tw.utils.extend(sandbox,{
- exports: {}
- });
vm.runInNewContext(code,sandbox,filename);
return sandbox.exports;
};
@@ -540,31 +536,60 @@ $tw.utils.Crypto = function() {
Execute the module named 'moduleName'. The name can optionally be relative to the module named 'moduleRoot'
*/
$tw.modules.execute = function(moduleName,moduleRoot) {
- var name = moduleRoot ? $tw.utils.resolvePath(moduleName,moduleRoot) : moduleName,
- moduleInfo = $tw.modules.titles[name],
- tiddler = $tw.wiki.getTiddler(name),
+ var name = moduleName[0] === "." ? $tw.utils.resolvePath(moduleName,moduleRoot) : moduleName,
+ moduleInfo = $tw.modules.titles[name] || $tw.modules.titles[name + ".js"] || $tw.modules.titles[moduleName] || $tw.modules.titles[moduleName + ".js"] ,
+ tiddler = $tw.wiki.getTiddler(name) || $tw.wiki.getTiddler(name + ".js") || $tw.wiki.getTiddler(moduleName) || $tw.wiki.getTiddler(moduleName + ".js") ,
+ _exports = {},
sandbox = {
- module: moduleInfo,
- exports: {},
+ module: {},
+ //moduleInfo: moduleInfo,
+ exports: _exports,
console: console,
setInterval: setInterval,
clearInterval: clearInterval,
setTimeout: setTimeout,
clearTimeout: clearTimeout,
$tw: $tw,
require: function(title) {
- return $tw.modules.execute(title,name);
+ return $tw.modules.execute(title, name);
}
};
+
+ Object.defineProperty(sandbox.module, "id", {
+ value: name,
+ writable: false,
+ enumerable: true,
+ configurable: false
+ });
+
if(!$tw.browser) {
$tw.utils.extend(sandbox,{
process: process
});
+ } else {
+ /*
+ CommonJS optional require.main property:
+ In a browser we offer a fake main module which points back to the boot function
+ (Theoretically, this may allow TW to eventually load itself as a module in the browser)
+ */
+ Object.defineProperty(sandbox.require, "main", {
+ value: (typeof(require) !== "undefined") ? require.main : {TiddlyWiki: _boot},
+ writable: false,
+ enumerable: true,
+ configurable: false
+ });
}
if(!moduleInfo) {
+ // We could not find the module on this path
+ // Try to defer to browserify etc, or node
+ var deferredModule;
if($tw.browser) {
- return $tw.utils.error("Cannot find module named '" + moduleName + "' required by module '" + moduleRoot + "', resolved to " + name);
-
+ if(window.require) {
+ try {
+ return window.require(moduleName);
+ } catch(e) {}
+ }
+ throw "Cannot find module named '" + moduleName + "' required by module '" + moduleRoot + "', resolved to " + name;
} else {
// If we don't have a module with that name, let node.js try to find it
return require(moduleName);
@@ -575,10 +600,11 @@ $tw.modules.execute = function(moduleName,moduleRoot) {
try {
// Check the type of the definition
if(typeof moduleInfo.definition === "function") { // Function
- moduleInfo.exports = {};
+ moduleInfo.exports = _exports;
moduleInfo.definition(moduleInfo,moduleInfo.exports,sandbox.require);
} else if(typeof moduleInfo.definition === "string") { // String
- moduleInfo.exports = $tw.utils.evalSandboxed(moduleInfo.definition,sandbox,tiddler.fields.title);
+ moduleInfo.exports = _exports;
+ $tw.utils.evalSandboxed(moduleInfo.definition,sandbox,tiddler.fields.title);
} else { // Object
moduleInfo.exports = moduleInfo.definition;
}
@@ -1405,4 +1431,15 @@ if($tw.browser) {
$tw.boot.boot();
}
-})();
+return $tw;
+
+});
+
+if(typeof(exports) !== "undefined") {
+ exports.TiddlyWiki = _boot;
+} else {
+ _boot(window.$tw);
+}
+
+
+
View
@@ -12,12 +12,11 @@ See Boot.js for further details of the boot process.
\*/
-// Set up $tw global for the browser
-if(typeof(window) === "undefined") {
- global.$tw = global.$tw || {}; // No `browser` member for the server
-} else {
- window.$tw = window.$tw || {browser: {}};
-}
+var _bootprefix = (function($tw) {
+
+"use strict";
+
+$tw = $tw || {browser: typeof(window) !== "undefined" ? {} : null};
/*
Information about each module is kept in an object with these members:
@@ -81,3 +80,18 @@ Convenience function for pushing a tiddler onto the preloading array
$tw.preloadTiddler = function(fields) {
$tw.preloadTiddlers.push(fields);
};
+
+return $tw
+
+});
+
+if(typeof(exports) === "undefined") {
+ // Set up $tw global for the browser
+ window.$tw = _bootprefix();
+} else {
+ // Export functionality as a module
+ exports.bootprefix = _bootprefix;
+}
+
+
+
@@ -0,0 +1,7 @@
+title: GettingStarted
+
+This wiki instance contains the CommonJS Modules/1.0 unit tests.
+
+To run them, open a console repl and execute "$tw.modules.execute('allTests')" there. You should see no exceptions or output starting with "FAIL" in the console.
+
+
@@ -0,0 +1,11 @@
+/*\
+title: absolute/b.js
+type: application/javascript
+module-type: library
+
+Absolute require test
+
+\*/
+
+
+exports.foo = function() {};
@@ -0,0 +1,16 @@
+/*\
+title: absolute/program.js
+type: application/javascript
+module-type: library
+
+Absolute require test
+
+\*/
+
+
+var test = require('test');
+var a = require('./submodule/a');
+var b = require('./b');
+test.assert(a.foo().foo === b.foo, 'require works with absolute identifiers');
+test.print('DONE', 'info');
+
@@ -0,0 +1,14 @@
+/*\
+title: absolute/submodule/a.js
+type: application/javascript
+module-type: library
+
+Absolute require test
+
+\*/
+
+
+exports.foo = function () {
+ return require('../b');
+};
+
@@ -0,0 +1,23 @@
+/*\
+title: allTests.js
+type: application/javascript
+module-type: library
+
+Runs all CommonJS Modules tests
+
+\*/
+
+$tw.modules.execute('absolute/program.js');
+$tw.modules.execute('cyclic/program.js');
+$tw.modules.execute('determinism/program.js');
+$tw.modules.execute('exactExports/program.js');
+$tw.modules.execute('hasOwnProperty/program.js');
+$tw.modules.execute('method/program.js');
+$tw.modules.execute('missing/program.js');
+$tw.modules.execute('monkeys/program.js');
+$tw.modules.execute('nested/program.js');
+$tw.modules.execute('relative/program.js');
+$tw.modules.execute('transitive/program.js');
+
+
+
@@ -0,0 +1,15 @@
+/*\
+title: cyclic/a.js
+type: application/javascript
+module-type: library
+
+Cycle require test A
+
+\*/
+
+exports.a = function () {
+ return b;
+};
+var b = require('./b');
+
+
@@ -0,0 +1,16 @@
+/*\
+title: cyclic/b.js
+type: application/javascript
+module-type: library
+
+Cycle require test B
+
+\*/
+
+
+
+var a = require('./a');
+exports.b = function () {
+ return a;
+};
+
@@ -0,0 +1,22 @@
+/*\
+title: cyclic/program.js
+type: application/javascript
+module-type: library
+
+Cycle require test
+
+\*/
+
+
+
+var test = require('test');
+var a = require('./a');
+var b = require('./b');
+
+test.assert(a.a, 'a exists');
+test.assert(b.b, 'b exists')
+test.assert(a.a().b === b.b, 'a gets b');
+test.assert(b.b().a === a.a, 'b gets a');
+
+test.print('DONE', 'info');
+
@@ -0,0 +1,14 @@
+/*\
+title: determinism/program.js
+type: application/javascript
+module-type: library
+
+Determinism test
+
+\*/
+
+
+var test = require('test');
+require('submodule/a');
+test.print('DONE', 'info');
+
@@ -0,0 +1,20 @@
+/*\
+title: determinism/submodule/a.js
+type: application/javascript
+module-type: library
+
+Determinism require test A
+
+\*/
+
+
+var test = require('test');
+var pass = false;
+var test = require('test');
+try {
+ require('a');
+} catch (exception) {
+ pass = true;
+}
+test.assert(pass, 'require does not fall back to relative modules when absolutes are not available.')
+
@@ -0,0 +1,15 @@
+/*\
+title: exactExports/a.js
+type: application/javascript
+module-type: library
+
+ExactExports test A
+
+\*/
+
+
+exports.program = function () {
+ return require('./program');
+};
+
+
Oops, something went wrong.

0 comments on commit 951019e

Please sign in to comment.