Adding support for 'require()' and node.js-style modules (not node modules per se - just support for the same module semantics)
This commit is contained in:
parent
77e9d59e9b
commit
f35a729ceb
3 changed files with 203 additions and 73 deletions
|
@ -272,6 +272,53 @@ See [issue #69][issue69] for more information.
|
|||
|
||||
[issue69]: https://github.com/walterhiggins/ScriptCraft/issues/69
|
||||
|
||||
# Require - Node.js-style module loading in ScriptCraft
|
||||
|
||||
### (Experimental as of 2013-12-21)
|
||||
|
||||
Node.js is a server-side javascript environment with an excellent
|
||||
module loading system based on CommonJS. Modules in Node.js are really
|
||||
simple. Each module is in its own javascript file and all variables
|
||||
and functions within the file are private to that file/module only. There is a very concise explanation of CommonJS modules at
|
||||
http://wiki.commonjs.org/wiki/Modules/1.1.1.
|
||||
|
||||
If you want to export a variable or function you use the module.export
|
||||
property.
|
||||
|
||||
For example imagine you have 3 files program.js, inc.js and math.js ...
|
||||
|
||||
## math.js
|
||||
|
||||
exports.add = function(a,b){
|
||||
return a + b;
|
||||
}
|
||||
|
||||
## inc.js
|
||||
|
||||
var math = require('./math');
|
||||
exports.increment = function(n){
|
||||
return math.add(n, 1);
|
||||
}
|
||||
|
||||
## program.js
|
||||
|
||||
var inc = require('./inc').increment;
|
||||
var a = 7;
|
||||
a = inc(a);
|
||||
print(a);
|
||||
|
||||
You can see from the above sample code that programs can use modules
|
||||
and modules themeselves can use other modules. Modules have full
|
||||
control over what functions and properties they want to provide to
|
||||
others.
|
||||
|
||||
## Important
|
||||
|
||||
Although ScriptCraft now supports Node.js style modules, it does not
|
||||
support node modules. Node.js and Rhino are two very different
|
||||
Javascript environments. ScriptCraft uses Rhino Javascript, not
|
||||
Node.js.
|
||||
|
||||
Drone Module
|
||||
============
|
||||
The Drone is a convenience class for building. It can be used for...
|
||||
|
@ -1451,29 +1498,33 @@ String class extensions
|
|||
-----------------------
|
||||
The following chat-formatting methods are added to the javascript String class..
|
||||
|
||||
* aqua()
|
||||
* black()
|
||||
* darkblue()
|
||||
* blue()
|
||||
* darkgreen()
|
||||
* bold()
|
||||
* brightgreen()
|
||||
* darkaqua()
|
||||
* darkred()
|
||||
* darkblue()
|
||||
* darkgray()
|
||||
* darkgreen()
|
||||
* purple()
|
||||
* darkpurple()
|
||||
* darkred()
|
||||
* gold()
|
||||
* gray()
|
||||
* darkgray()
|
||||
* indigo()
|
||||
* brightgreen()
|
||||
* green()
|
||||
* aqua()
|
||||
* italic()
|
||||
* lightpurple()
|
||||
* indigo()
|
||||
* green()
|
||||
* red()
|
||||
* pink()
|
||||
* yellow()
|
||||
* white()
|
||||
* bold()
|
||||
* random()
|
||||
* strike()
|
||||
* random()
|
||||
* magic()
|
||||
* underline()
|
||||
* italic()
|
||||
* reset()
|
||||
|
||||
Example
|
||||
|
|
123
src/main/javascript/core/_require.js
Normal file
123
src/main/javascript/core/_require.js
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*************************************************************************
|
||||
# Require - Node.js-style module loading in ScriptCraft
|
||||
|
||||
### (Experimental as of 2013-12-21)
|
||||
|
||||
Node.js is a server-side javascript environment with an excellent
|
||||
module loading system based on CommonJS. Modules in Node.js are really
|
||||
simple. Each module is in its own javascript file and all variables
|
||||
and functions within the file are private to that file/module only. There is a very concise explanation of CommonJS modules at
|
||||
http://wiki.commonjs.org/wiki/Modules/1.1.1.
|
||||
|
||||
If you want to export a variable or function you use the module.export
|
||||
property.
|
||||
|
||||
For example imagine you have 3 files program.js, inc.js and math.js ...
|
||||
|
||||
## math.js
|
||||
|
||||
exports.add = function(a,b){
|
||||
return a + b;
|
||||
}
|
||||
|
||||
## inc.js
|
||||
|
||||
var math = require('./math');
|
||||
exports.increment = function(n){
|
||||
return math.add(n, 1);
|
||||
}
|
||||
|
||||
## program.js
|
||||
|
||||
var inc = require('./inc').increment;
|
||||
var a = 7;
|
||||
a = inc(a);
|
||||
print(a);
|
||||
|
||||
You can see from the above sample code that programs can use modules
|
||||
and modules themeselves can use other modules. Modules have full
|
||||
control over what functions and properties they want to provide to
|
||||
others.
|
||||
|
||||
## Important
|
||||
|
||||
Although ScriptCraft now supports Node.js style modules, it does not
|
||||
support node modules. Node.js and Rhino are two very different
|
||||
Javascript environments. ScriptCraft uses Rhino Javascript, not
|
||||
Node.js.
|
||||
|
||||
***/
|
||||
(function(__plugin, __engine, verbose){
|
||||
/*
|
||||
wph 20131215 Experimental
|
||||
*/
|
||||
var _loadedModules = {};
|
||||
|
||||
var _require = function(parentFile, path)
|
||||
{
|
||||
var _canonize = function(file){
|
||||
return "" + file.canonicalPath.replaceAll("\\\\","/");
|
||||
};
|
||||
|
||||
var file = new java.io.File(parentFile, path);
|
||||
if (!file.exists())
|
||||
{
|
||||
if (path.match(/\.js$/i)){
|
||||
__plugin.logger.warning('require("' + path + '") failed. File [' + file.canonicalPath + '] not found');
|
||||
return;
|
||||
}else{
|
||||
path = path + '.js';
|
||||
file = new java.io.File(parentFile, path);
|
||||
if (!file.exists()){
|
||||
__plugin.logger.warning('require("' + path + '") failed. File [' + file.canonicalPath + '] not found');
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (file.isDirectory()){
|
||||
__plugin.logger.warning('require("' + path + '") directories not yet supported. ' + file.canonicalPath);
|
||||
return;
|
||||
}
|
||||
var canonizedFilename = _canonize(file);
|
||||
|
||||
var moduleInfo = _loadedModules[canonizedFilename];
|
||||
if (moduleInfo){
|
||||
return moduleInfo;
|
||||
}
|
||||
if (verbose){
|
||||
print("loading module " + canonizedFilename);
|
||||
}
|
||||
var reader = new java.io.FileReader(file);
|
||||
var br = new java.io.BufferedReader(reader);
|
||||
var code = "";
|
||||
while ((r = br.readLine()) !== null) code += r + "\n";
|
||||
|
||||
var head = "(function(exports,module,require,__filename,__dirname){ ";
|
||||
|
||||
moduleInfo = {
|
||||
loaded: false,
|
||||
id: canonizedFilename,
|
||||
exports: {}
|
||||
};
|
||||
var tail = "})";
|
||||
code = head + code + tail;
|
||||
|
||||
_loadedModules[canonizedFilename] = moduleInfo;
|
||||
moduleInfo.main = __engine.eval(code);
|
||||
moduleInfo.main(moduleInfo.exports,
|
||||
moduleInfo,
|
||||
_requireClosure(file.parentFile),
|
||||
canonizedFilename,
|
||||
"" + parentFile?parentFile.canonicalPath:"");
|
||||
moduleInfo.loaded = true;
|
||||
return moduleInfo;
|
||||
};
|
||||
|
||||
var _requireClosure = function(parent){
|
||||
return function(path){
|
||||
var module = _require(parent, path);
|
||||
return module.exports;
|
||||
};
|
||||
};
|
||||
return _requireClosure(new java.io.File("./"));
|
||||
})
|
|
@ -240,59 +240,15 @@ var server = org.bukkit.Bukkit.server;
|
|||
if (typeof load == "function")
|
||||
return ;
|
||||
|
||||
var _canonize = function(file){ return file.getCanonicalPath().replaceAll("\\\\","/"); };
|
||||
var _canonize = function(file){
|
||||
return "" + file.getCanonicalPath().replaceAll("\\\\","/");
|
||||
};
|
||||
|
||||
var _originalScript = __script;
|
||||
var parentFileObj = new java.io.File(__script).getParentFile();
|
||||
var jsPluginsRootDir = parentFileObj.getParentFile();
|
||||
var jsPluginsRootDirName = _canonize(jsPluginsRootDir);
|
||||
|
||||
/*
|
||||
wph 20131215 Experimental
|
||||
*/
|
||||
var _loadedModules = {};
|
||||
var _require = function(path)
|
||||
{
|
||||
var file = new java.io.File(path);
|
||||
if (!file.exists()){
|
||||
if (path.match(/\.js$/i)){
|
||||
__plugin.logger.warning('require("' + path + '") failed. File not found');
|
||||
return;
|
||||
}else{
|
||||
path = path + '.js';
|
||||
file = new java.io.File(path);
|
||||
if (!file.exists()){
|
||||
__plugin.logger.warning('require("' + path + '") failed. File not found');
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (file.isDirectory()){
|
||||
__plugin.logger.warning('require("' + path + '") directories not yet supported.');
|
||||
return;
|
||||
}
|
||||
var canonizedFilename = _canonize(file);
|
||||
if (_loadedModules[canonizedFilename]){
|
||||
return _loadedModules[canonizedFilename];
|
||||
}
|
||||
if (verbose){
|
||||
print("loading module " + canonizedFilename);
|
||||
}
|
||||
var reader = new java.io.FileReader(file);
|
||||
var br = new java.io.BufferedReader(reader);
|
||||
var code = "";
|
||||
var module = {id: canonizedFilename};
|
||||
while ((r = br.readLine()) !== null) code += r + "\n";
|
||||
|
||||
var head = "var result = {};(function(exports,module){ ";
|
||||
var tail = "; return exports;}(result," + JSON.stringify(module) + "))";
|
||||
code = head + code + tail;
|
||||
|
||||
_loadedModules[canonizedFilename] = __engine.eval(code);
|
||||
|
||||
return _loadedModules[canonizedFilename];
|
||||
};
|
||||
global.require = _require;
|
||||
|
||||
|
||||
var _loaded = {};
|
||||
|
@ -331,7 +287,6 @@ var server = org.bukkit.Bukkit.server;
|
|||
} else {
|
||||
while ((r = br.readLine()) !== null) code += r + "\n";
|
||||
}
|
||||
|
||||
result = __engine.eval(code);
|
||||
_loaded[canonizedFilename] = result || true;
|
||||
}catch (e){
|
||||
|
@ -829,7 +784,8 @@ See [issue #69][issue69] for more information.
|
|||
global._onTabComplete = __onTabCompleteJS;
|
||||
global.addUnloadHandler = _addUnloadHandler;
|
||||
|
||||
|
||||
var fnRequire = load(jsPluginsRootDirName + '/core/_require.js',true);
|
||||
global.require = fnRequire(__plugin, __engine, verbose);
|
||||
//
|
||||
// assumes this was loaded from js-plugins/core/
|
||||
// load all of the plugins.
|
||||
|
|
Reference in a new issue