From 881325b7ed359dea53308b01265a43dcc6f7241f Mon Sep 17 00:00:00 2001 From: natecain Date: Tue, 17 Sep 2013 20:20:37 -0400 Subject: [PATCH 1/5] Make require() compliant with CommonJS 1.0 This includes potentially breaking changes. Specifically, before this patch tiddlywiki would default to relative module identifiers Now, tiddlywiki will only search relative paths if explicitly specified Additionally, some "defaulted export contexts" were removed (some modules may make assumptions about context) Some unit tests were modified slightly from their originals Tiddlywiki doesn't have a notion of a "main" program's path Some require calls were explicitly made relative None of these changes should affect the requirement under test in each case --- boot/boot.js | 55 +++++++++++++------ .../testcommonjs/tiddlers/GettingStarted.tid | 7 +++ editions/testcommonjs/tiddlers/absolute/b.js | 11 ++++ .../testcommonjs/tiddlers/absolute/program.js | 16 ++++++ .../tiddlers/absolute/submodule/a.js | 14 +++++ editions/testcommonjs/tiddlers/allTests.js | 23 ++++++++ editions/testcommonjs/tiddlers/cyclic/a.js | 15 +++++ editions/testcommonjs/tiddlers/cyclic/b.js | 16 ++++++ .../testcommonjs/tiddlers/cyclic/program.js | 22 ++++++++ .../tiddlers/determinism/program.js | 14 +++++ .../tiddlers/determinism/submodule/a.js | 20 +++++++ .../testcommonjs/tiddlers/exactExports/a.js | 15 +++++ .../tiddlers/exactExports/program.js | 16 ++++++ .../tiddlers/hasOwnProperty/hasOwnProperty.js | 6 ++ .../tiddlers/hasOwnProperty/program.js | 15 +++++ .../tiddlers/hasOwnProperty/toString.js | 6 ++ editions/testcommonjs/tiddlers/method/a.js | 23 ++++++++ .../testcommonjs/tiddlers/method/program.js | 19 +++++++ .../testcommonjs/tiddlers/missing/program.js | 19 +++++++ editions/testcommonjs/tiddlers/monkeys/a.js | 12 ++++ .../testcommonjs/tiddlers/monkeys/program.js | 15 +++++ .../testcommonjs/tiddlers/nested/a/b/c/d.js | 14 +++++ .../testcommonjs/tiddlers/nested/program.js | 14 +++++ .../testcommonjs/tiddlers/relative/program.js | 16 ++++++ .../tiddlers/relative/submodule/a.js | 13 +++++ .../tiddlers/relative/submodule/b.js | 12 ++++ editions/testcommonjs/tiddlers/test.js | 23 ++++++++ .../testcommonjs/tiddlers/transitive/a.js | 11 ++++ .../testcommonjs/tiddlers/transitive/b.js | 12 ++++ .../testcommonjs/tiddlers/transitive/c.js | 14 +++++ .../tiddlers/transitive/program.js | 13 +++++ editions/testcommonjs/tiddlywiki.info | 8 +++ 32 files changed, 493 insertions(+), 16 deletions(-) create mode 100644 editions/testcommonjs/tiddlers/GettingStarted.tid create mode 100644 editions/testcommonjs/tiddlers/absolute/b.js create mode 100644 editions/testcommonjs/tiddlers/absolute/program.js create mode 100644 editions/testcommonjs/tiddlers/absolute/submodule/a.js create mode 100644 editions/testcommonjs/tiddlers/allTests.js create mode 100644 editions/testcommonjs/tiddlers/cyclic/a.js create mode 100644 editions/testcommonjs/tiddlers/cyclic/b.js create mode 100644 editions/testcommonjs/tiddlers/cyclic/program.js create mode 100644 editions/testcommonjs/tiddlers/determinism/program.js create mode 100644 editions/testcommonjs/tiddlers/determinism/submodule/a.js create mode 100644 editions/testcommonjs/tiddlers/exactExports/a.js create mode 100644 editions/testcommonjs/tiddlers/exactExports/program.js create mode 100644 editions/testcommonjs/tiddlers/hasOwnProperty/hasOwnProperty.js create mode 100644 editions/testcommonjs/tiddlers/hasOwnProperty/program.js create mode 100644 editions/testcommonjs/tiddlers/hasOwnProperty/toString.js create mode 100644 editions/testcommonjs/tiddlers/method/a.js create mode 100644 editions/testcommonjs/tiddlers/method/program.js create mode 100644 editions/testcommonjs/tiddlers/missing/program.js create mode 100644 editions/testcommonjs/tiddlers/monkeys/a.js create mode 100644 editions/testcommonjs/tiddlers/monkeys/program.js create mode 100644 editions/testcommonjs/tiddlers/nested/a/b/c/d.js create mode 100644 editions/testcommonjs/tiddlers/nested/program.js create mode 100644 editions/testcommonjs/tiddlers/relative/program.js create mode 100644 editions/testcommonjs/tiddlers/relative/submodule/a.js create mode 100644 editions/testcommonjs/tiddlers/relative/submodule/b.js create mode 100644 editions/testcommonjs/tiddlers/test.js create mode 100644 editions/testcommonjs/tiddlers/transitive/a.js create mode 100644 editions/testcommonjs/tiddlers/transitive/b.js create mode 100644 editions/testcommonjs/tiddlers/transitive/c.js create mode 100644 editions/testcommonjs/tiddlers/transitive/program.js create mode 100644 editions/testcommonjs/tiddlywiki.info diff --git a/boot/boot.js b/boot/boot.js index 2d61d8ec0..e50dbd704 100644 --- a/boot/boot.js +++ b/boot/boot.js @@ -313,6 +313,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 +333,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 +370,9 @@ $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,{ + var contextCopy = $tw.utils.extend({},context/*,{ exports: {} - }); + }*/); // 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 +397,9 @@ 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: {} - }); + //$tw.utils.extend(sandbox,{ + // exports: {} + //}); vm.runInNewContext(code,sandbox,filename); return sandbox.exports; }; @@ -540,12 +548,13 @@ $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: {}, + exports: _exports, console: console, setInterval: setInterval, clearInterval: clearInterval, @@ -553,7 +562,7 @@ $tw.modules.execute = function(moduleName,moduleRoot) { clearTimeout: clearTimeout, $tw: $tw, require: function(title) { - return $tw.modules.execute(title,name); + return $tw.modules.execute(title, name); } }; if(!$tw.browser) { @@ -562,12 +571,19 @@ $tw.modules.execute = function(moduleName,moduleRoot) { }); } 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); + return require(moduleName) } } // Execute the module if we haven't already done so @@ -575,10 +591,17 @@ $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); + var temp; + moduleInfo.exports = _exports; + temp = $tw.utils.evalSandboxed(moduleInfo.definition,sandbox,tiddler.fields.title); + for(var k in temp) { + moduleInfo.exports[k] = temp[k] + } + //$tw.utils.extend(exports, temp) + //moduleInfo.exports = temp; } else { // Object moduleInfo.exports = moduleInfo.definition; } diff --git a/editions/testcommonjs/tiddlers/GettingStarted.tid b/editions/testcommonjs/tiddlers/GettingStarted.tid new file mode 100644 index 000000000..c7f551a8b --- /dev/null +++ b/editions/testcommonjs/tiddlers/GettingStarted.tid @@ -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. + + diff --git a/editions/testcommonjs/tiddlers/absolute/b.js b/editions/testcommonjs/tiddlers/absolute/b.js new file mode 100644 index 000000000..f7bca1410 --- /dev/null +++ b/editions/testcommonjs/tiddlers/absolute/b.js @@ -0,0 +1,11 @@ +/*\ +title: absolute/b.js +type: application/javascript +module-type: library + +Absolute require test + +\*/ + + +exports.foo = function() {}; diff --git a/editions/testcommonjs/tiddlers/absolute/program.js b/editions/testcommonjs/tiddlers/absolute/program.js new file mode 100644 index 000000000..19983f4ce --- /dev/null +++ b/editions/testcommonjs/tiddlers/absolute/program.js @@ -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'); + diff --git a/editions/testcommonjs/tiddlers/absolute/submodule/a.js b/editions/testcommonjs/tiddlers/absolute/submodule/a.js new file mode 100644 index 000000000..4726e59cf --- /dev/null +++ b/editions/testcommonjs/tiddlers/absolute/submodule/a.js @@ -0,0 +1,14 @@ +/*\ +title: absolute/submodule/a.js +type: application/javascript +module-type: library + +Absolute require test + +\*/ + + +exports.foo = function () { + return require('../b'); +}; + diff --git a/editions/testcommonjs/tiddlers/allTests.js b/editions/testcommonjs/tiddlers/allTests.js new file mode 100644 index 000000000..2e1fead16 --- /dev/null +++ b/editions/testcommonjs/tiddlers/allTests.js @@ -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'); + + + diff --git a/editions/testcommonjs/tiddlers/cyclic/a.js b/editions/testcommonjs/tiddlers/cyclic/a.js new file mode 100644 index 000000000..1541d7252 --- /dev/null +++ b/editions/testcommonjs/tiddlers/cyclic/a.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'); + + diff --git a/editions/testcommonjs/tiddlers/cyclic/b.js b/editions/testcommonjs/tiddlers/cyclic/b.js new file mode 100644 index 000000000..f041fa86e --- /dev/null +++ b/editions/testcommonjs/tiddlers/cyclic/b.js @@ -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; +}; + diff --git a/editions/testcommonjs/tiddlers/cyclic/program.js b/editions/testcommonjs/tiddlers/cyclic/program.js new file mode 100644 index 000000000..f76ae2a2f --- /dev/null +++ b/editions/testcommonjs/tiddlers/cyclic/program.js @@ -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'); + diff --git a/editions/testcommonjs/tiddlers/determinism/program.js b/editions/testcommonjs/tiddlers/determinism/program.js new file mode 100644 index 000000000..66620856e --- /dev/null +++ b/editions/testcommonjs/tiddlers/determinism/program.js @@ -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'); + diff --git a/editions/testcommonjs/tiddlers/determinism/submodule/a.js b/editions/testcommonjs/tiddlers/determinism/submodule/a.js new file mode 100644 index 000000000..50934fd1a --- /dev/null +++ b/editions/testcommonjs/tiddlers/determinism/submodule/a.js @@ -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.') + diff --git a/editions/testcommonjs/tiddlers/exactExports/a.js b/editions/testcommonjs/tiddlers/exactExports/a.js new file mode 100644 index 000000000..567c1936c --- /dev/null +++ b/editions/testcommonjs/tiddlers/exactExports/a.js @@ -0,0 +1,15 @@ +/*\ +title: exactExports/a.js +type: application/javascript +module-type: library + +ExactExports test A + +\*/ + + +exports.program = function () { + return require('./program'); +}; + + diff --git a/editions/testcommonjs/tiddlers/exactExports/program.js b/editions/testcommonjs/tiddlers/exactExports/program.js new file mode 100644 index 000000000..dffc094db --- /dev/null +++ b/editions/testcommonjs/tiddlers/exactExports/program.js @@ -0,0 +1,16 @@ +/*\ +title: exactExports/program.js +type: application/javascript +module-type: library + +ExactExports test + +\*/ + + + +var test = require('test'); +var a = require('./a'); +test.assert(a.program() === exports, 'exact exports'); +test.print('DONE', 'info'); + diff --git a/editions/testcommonjs/tiddlers/hasOwnProperty/hasOwnProperty.js b/editions/testcommonjs/tiddlers/hasOwnProperty/hasOwnProperty.js new file mode 100644 index 000000000..d2cd5f7ae --- /dev/null +++ b/editions/testcommonjs/tiddlers/hasOwnProperty/hasOwnProperty.js @@ -0,0 +1,6 @@ +/*\ +title: hasOwnProperty.js +type: application/javascript +module-type: library + +\*/ diff --git a/editions/testcommonjs/tiddlers/hasOwnProperty/program.js b/editions/testcommonjs/tiddlers/hasOwnProperty/program.js new file mode 100644 index 000000000..3d924ae1c --- /dev/null +++ b/editions/testcommonjs/tiddlers/hasOwnProperty/program.js @@ -0,0 +1,15 @@ +/*\ +title: hasOwnProperty/program.js +type: application/javascript +module-type: library + +OwnProperty test + +\*/ + +var hasOwnProperty = require('hasOwnProperty'); +var toString = require('toString'); +var test = require('test'); +test.print('DONE', 'info'); + + diff --git a/editions/testcommonjs/tiddlers/hasOwnProperty/toString.js b/editions/testcommonjs/tiddlers/hasOwnProperty/toString.js new file mode 100644 index 000000000..8cff4c578 --- /dev/null +++ b/editions/testcommonjs/tiddlers/hasOwnProperty/toString.js @@ -0,0 +1,6 @@ +/*\ +title: toString.js +type: application/javascript +module-type: library + +\*/ diff --git a/editions/testcommonjs/tiddlers/method/a.js b/editions/testcommonjs/tiddlers/method/a.js new file mode 100644 index 000000000..bb88479c9 --- /dev/null +++ b/editions/testcommonjs/tiddlers/method/a.js @@ -0,0 +1,23 @@ +/*\ +title: method/a.js +type: application/javascript +module-type: library + +Method test + +\*/ + + +exports.foo = function () { + return this; +}; +exports.set = function (x) { + this.x = x; +}; +exports.get = function () { + return this.x; +}; +exports.getClosed = function () { + return exports.x; +}; + diff --git a/editions/testcommonjs/tiddlers/method/program.js b/editions/testcommonjs/tiddlers/method/program.js new file mode 100644 index 000000000..9cab6d1ce --- /dev/null +++ b/editions/testcommonjs/tiddlers/method/program.js @@ -0,0 +1,19 @@ +/*\ +title: method/program.js +type: application/javascript +module-type: library + +Method test + +\*/ + + +var test = require('test'); +var a = require('./a'); +var foo = a.foo; +test.assert(a.foo() == a, 'calling a module member'); +test.assert(foo() == (function (){return this})(), 'members not implicitly bound'); +a.set(10); +test.assert(a.get() == 10, 'get and set') +test.print('DONE', 'info'); + diff --git a/editions/testcommonjs/tiddlers/missing/program.js b/editions/testcommonjs/tiddlers/missing/program.js new file mode 100644 index 000000000..07165b1ba --- /dev/null +++ b/editions/testcommonjs/tiddlers/missing/program.js @@ -0,0 +1,19 @@ +/*\ +title: missing/program.js +type: application/javascript +module-type: library + +Missing test + +\*/ + + +var test = require('test'); +try { + require('bogus'); + test.print('FAIL require throws error when module missing', 'fail'); +} catch (exception) { + test.print('PASS require throws error when module missing', 'pass'); +} +test.print('DONE', 'info'); + diff --git a/editions/testcommonjs/tiddlers/monkeys/a.js b/editions/testcommonjs/tiddlers/monkeys/a.js new file mode 100644 index 000000000..73cf6e377 --- /dev/null +++ b/editions/testcommonjs/tiddlers/monkeys/a.js @@ -0,0 +1,12 @@ +/*\ +title: monkeys/a.js +type: application/javascript +module-type: library + +Missing test A + +\*/ + +require('./program').monkey = 10; + + diff --git a/editions/testcommonjs/tiddlers/monkeys/program.js b/editions/testcommonjs/tiddlers/monkeys/program.js new file mode 100644 index 000000000..9a752eaa9 --- /dev/null +++ b/editions/testcommonjs/tiddlers/monkeys/program.js @@ -0,0 +1,15 @@ +/*\ +title: monkeys/program.js +type: application/javascript +module-type: library + +Monkeys test + +\*/ + + +var a = require('./a'); +var test = require('test'); +test.assert(exports.monkey == 10, 'monkeys permitted'); +test.print('DONE', 'info'); + diff --git a/editions/testcommonjs/tiddlers/nested/a/b/c/d.js b/editions/testcommonjs/tiddlers/nested/a/b/c/d.js new file mode 100644 index 000000000..b84d55ebe --- /dev/null +++ b/editions/testcommonjs/tiddlers/nested/a/b/c/d.js @@ -0,0 +1,14 @@ +/*\ +title: a/b/c/d.js +type: application/javascript +module-type: library + +Nested test + +\*/ + +exports.foo = function () { + return 1; +}; + + diff --git a/editions/testcommonjs/tiddlers/nested/program.js b/editions/testcommonjs/tiddlers/nested/program.js new file mode 100644 index 000000000..e750cf887 --- /dev/null +++ b/editions/testcommonjs/tiddlers/nested/program.js @@ -0,0 +1,14 @@ +/*\ +title: nested/program.js +type: application/javascript +module-type: library + +Nested test + +\*/ + + +var test = require('test'); +test.assert(require('a/b/c/d').foo() == 1, 'nested module identifier'); +test.print('DONE', 'info'); + diff --git a/editions/testcommonjs/tiddlers/relative/program.js b/editions/testcommonjs/tiddlers/relative/program.js new file mode 100644 index 000000000..d5cb0ad7a --- /dev/null +++ b/editions/testcommonjs/tiddlers/relative/program.js @@ -0,0 +1,16 @@ +/*\ +title: relative/program.js +type: application/javascript +module-type: library + +Relative test + +\*/ + + +var test = require('test'); +var a = require('submodule/a'); +var b = require('submodule/b'); +test.assert(a.foo == b.foo, 'a and b share foo through a relative require'); +test.print('DONE', 'info'); + diff --git a/editions/testcommonjs/tiddlers/relative/submodule/a.js b/editions/testcommonjs/tiddlers/relative/submodule/a.js new file mode 100644 index 000000000..ebb9f2080 --- /dev/null +++ b/editions/testcommonjs/tiddlers/relative/submodule/a.js @@ -0,0 +1,13 @@ +/*\ +title: submodule/a.js +type: application/javascript +module-type: library + +Relative test A + +\*/ + + + +exports.foo = require('./b').foo; + diff --git a/editions/testcommonjs/tiddlers/relative/submodule/b.js b/editions/testcommonjs/tiddlers/relative/submodule/b.js new file mode 100644 index 000000000..93f6ed4ce --- /dev/null +++ b/editions/testcommonjs/tiddlers/relative/submodule/b.js @@ -0,0 +1,12 @@ +/*\ +title: submodule/b.js +type: application/javascript +module-type: library + +Relative test B + +\*/ + +exports.foo = function () { +}; + diff --git a/editions/testcommonjs/tiddlers/test.js b/editions/testcommonjs/tiddlers/test.js new file mode 100644 index 000000000..154088bdb --- /dev/null +++ b/editions/testcommonjs/tiddlers/test.js @@ -0,0 +1,23 @@ +/*\ +title: test.js +type: application/javascript +module-type: library + +testing lib + +\*/ + + +exports.assert = function(cond, msg) { + if(!cond) { + if(msg) { + throw msg + } else { + throw "ASSERT FAILED" + } + } +} + +exports.print = function() { + console.log.apply(console, arguments); +} diff --git a/editions/testcommonjs/tiddlers/transitive/a.js b/editions/testcommonjs/tiddlers/transitive/a.js new file mode 100644 index 000000000..be4c1af2a --- /dev/null +++ b/editions/testcommonjs/tiddlers/transitive/a.js @@ -0,0 +1,11 @@ +/*\ +title: transitive/a.js +type: application/javascript +module-type: library + +Transitive test A + +\*/ + +exports.foo = require('./b').foo; + diff --git a/editions/testcommonjs/tiddlers/transitive/b.js b/editions/testcommonjs/tiddlers/transitive/b.js new file mode 100644 index 000000000..371c52f82 --- /dev/null +++ b/editions/testcommonjs/tiddlers/transitive/b.js @@ -0,0 +1,12 @@ +/*\ +title: transitive/b.js +type: application/javascript +module-type: library + +Transitive test B + +\*/ + + + +exports.foo = require('./c').foo; diff --git a/editions/testcommonjs/tiddlers/transitive/c.js b/editions/testcommonjs/tiddlers/transitive/c.js new file mode 100644 index 000000000..984134396 --- /dev/null +++ b/editions/testcommonjs/tiddlers/transitive/c.js @@ -0,0 +1,14 @@ +/*\ +title: transitive/c.js +type: application/javascript +module-type: library + +Transitive test C + +\*/ + + +exports.foo = function () { + return 1; +}; + diff --git a/editions/testcommonjs/tiddlers/transitive/program.js b/editions/testcommonjs/tiddlers/transitive/program.js new file mode 100644 index 000000000..9b8b747c6 --- /dev/null +++ b/editions/testcommonjs/tiddlers/transitive/program.js @@ -0,0 +1,13 @@ +/*\ +title: transitive/program.js +type: application/javascript +module-type: library + +Transitive test + +\*/ + +var test = require('test'); +test.assert(require('./a').foo() == 1, 'transitive'); +test.print('DONE', 'info'); + diff --git a/editions/testcommonjs/tiddlywiki.info b/editions/testcommonjs/tiddlywiki.info new file mode 100644 index 000000000..7fc99bd64 --- /dev/null +++ b/editions/testcommonjs/tiddlywiki.info @@ -0,0 +1,8 @@ +{ + "plugins": [ + "tiddlywiki/fullscreen" + ], + "themes": [ + "tiddlywiki/snowwhite" + ] +} \ No newline at end of file From c9d2364e0cc56c58bef830418da2630cd59be25b Mon Sep 17 00:00:00 2001 From: natecain Date: Tue, 17 Sep 2013 22:24:17 -0400 Subject: [PATCH 2/5] Fix up descriptions for tests --- editions/testcommonjs/tiddlers/hasOwnProperty/hasOwnProperty.js | 2 ++ editions/testcommonjs/tiddlers/hasOwnProperty/toString.js | 2 ++ editions/testcommonjs/tiddlers/monkeys/a.js | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/editions/testcommonjs/tiddlers/hasOwnProperty/hasOwnProperty.js b/editions/testcommonjs/tiddlers/hasOwnProperty/hasOwnProperty.js index d2cd5f7ae..6c2bd8b0d 100644 --- a/editions/testcommonjs/tiddlers/hasOwnProperty/hasOwnProperty.js +++ b/editions/testcommonjs/tiddlers/hasOwnProperty/hasOwnProperty.js @@ -3,4 +3,6 @@ title: hasOwnProperty.js type: application/javascript module-type: library +OwnProperty test A + \*/ diff --git a/editions/testcommonjs/tiddlers/hasOwnProperty/toString.js b/editions/testcommonjs/tiddlers/hasOwnProperty/toString.js index 8cff4c578..76da31d77 100644 --- a/editions/testcommonjs/tiddlers/hasOwnProperty/toString.js +++ b/editions/testcommonjs/tiddlers/hasOwnProperty/toString.js @@ -3,4 +3,6 @@ title: toString.js type: application/javascript module-type: library +OwnProperty test B + \*/ diff --git a/editions/testcommonjs/tiddlers/monkeys/a.js b/editions/testcommonjs/tiddlers/monkeys/a.js index 73cf6e377..37023fc9a 100644 --- a/editions/testcommonjs/tiddlers/monkeys/a.js +++ b/editions/testcommonjs/tiddlers/monkeys/a.js @@ -3,7 +3,7 @@ title: monkeys/a.js type: application/javascript module-type: library -Missing test A +Monkeys test A \*/ From 5c92ec3617b82d4970abdac0171b5b34b8141a35 Mon Sep 17 00:00:00 2001 From: natecain Date: Tue, 17 Sep 2013 22:38:14 -0400 Subject: [PATCH 3/5] Cleaned up some dead/commented in patches. --- boot/boot.js | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/boot/boot.js b/boot/boot.js index e50dbd704..575346fbe 100644 --- a/boot/boot.js +++ b/boot/boot.js @@ -370,9 +370,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) { @@ -397,9 +395,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; }; @@ -594,14 +589,8 @@ $tw.modules.execute = function(moduleName,moduleRoot) { moduleInfo.exports = _exports; moduleInfo.definition(moduleInfo,moduleInfo.exports,sandbox.require); } else if(typeof moduleInfo.definition === "string") { // String - var temp; moduleInfo.exports = _exports; - temp = $tw.utils.evalSandboxed(moduleInfo.definition,sandbox,tiddler.fields.title); - for(var k in temp) { - moduleInfo.exports[k] = temp[k] - } - //$tw.utils.extend(exports, temp) - //moduleInfo.exports = temp; + $tw.utils.evalSandboxed(moduleInfo.definition,sandbox,tiddler.fields.title); } else { // Object moduleInfo.exports = moduleInfo.definition; } From fbc80e379d5d78894cd6fa795940c9c743089014 Mon Sep 17 00:00:00 2001 From: natecain Date: Tue, 1 Oct 2013 17:56:05 -0400 Subject: [PATCH 4/5] Some quick style cleanup to commonjs patches --- boot/boot.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/boot/boot.js b/boot/boot.js index 575346fbe..ac312c39c 100644 --- a/boot/boot.js +++ b/boot/boot.js @@ -336,8 +336,8 @@ $tw.utils.resolvePath = function(sourcepath,rootpath) { if(rootpath) { var root = rootpath.split("/"); // Remove the filename part of the root - root.splice(root.length-1,1); - return root.join('/')+'/'+sourcepath + root.splice(root.length - 1, 1); + return root.join("/") + "/" + sourcepath; } else { return sourcepath; } @@ -543,9 +543,9 @@ $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 = 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') , + 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, @@ -566,19 +566,19 @@ $tw.modules.execute = function(moduleName,moduleRoot) { }); } if(!moduleInfo) { - //we could not find the module on this path - //try to defer to browserify etc, or node + // We could not find the module on this path + // Try to defer to browserify etc, or node var deferredModule; if($tw.browser) { if(window.require) { try { - return window.require(moduleName) + 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) + return require(moduleName); } } // Execute the module if we haven't already done so From b8c37a26efb46819b42d63777ba8f5415979c3d9 Mon Sep 17 00:00:00 2001 From: natecain Date: Fri, 11 Oct 2013 11:32:58 -0400 Subject: [PATCH 5/5] Additional improvement to CommonJS Modules support Now implements (and mostly follows) requirements of Modules/1.1 spec implementes only the required "secure sandbox" subset of the spec `module` free variable changed from the `moduleInfo` to an id container `require` free variable given a "main" property boot module scope closed and exported this also changes the interface between boot and bootprefix slightly (should now be able to create multiple TW instances under node) BREAKING CHANGES: The tiddlywiki module itself now exports a single constructor function Modules which depended on `module` referring to `moduleInfo` will break Modules which don't conform to Modules/1.1 will break (by attempting to modify require.main or module.id) --- boot/boot.js | 53 ++++++++++++++++++++++++++++++++++------------ boot/bootprefix.js | 26 +++++++++++++++++------ tiddlywiki.js | 2 +- 3 files changed, 60 insertions(+), 21 deletions(-) diff --git a/boot/boot.js b/boot/boot.js index ac312c39c..5719b0183 100644 --- a/boot/boot.js +++ b/boot/boot.js @@ -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 || {}; @@ -548,7 +541,8 @@ $tw.modules.execute = function(moduleName,moduleRoot) { tiddler = $tw.wiki.getTiddler(name) || $tw.wiki.getTiddler(name + ".js") || $tw.wiki.getTiddler(moduleName) || $tw.wiki.getTiddler(moduleName + ".js") , _exports = {}, sandbox = { - module: moduleInfo, + module: {}, + //moduleInfo: moduleInfo, exports: _exports, console: console, setInterval: setInterval, @@ -560,10 +554,30 @@ $tw.modules.execute = function(moduleName,moduleRoot) { 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 @@ -1417,4 +1431,15 @@ if($tw.browser) { $tw.boot.boot(); } -})(); +return $tw; + +}); + +if(typeof(exports) !== "undefined") { + exports.TiddlyWiki = _boot; +} else { + _boot(window.$tw); +} + + + diff --git a/boot/bootprefix.js b/boot/bootprefix.js index 90e30a80c..7de3309cd 100644 --- a/boot/bootprefix.js +++ b/boot/bootprefix.js @@ -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; +} + + + diff --git a/tiddlywiki.js b/tiddlywiki.js index 0d8704810..3bbb7f567 100755 --- a/tiddlywiki.js +++ b/tiddlywiki.js @@ -4,7 +4,7 @@ This is invoked as a shell script by NPM when the `tiddlywiki` command is typed */ -var $tw = require("./boot/boot.js").$tw; +var $tw = require("./boot/boot.js").TiddlyWiki(); // Pass the command line arguments to the boot kernel $tw.boot.argv = Array.prototype.slice.call(process.argv,2);