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
|
[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
|
Drone Module
|
||||||
============
|
============
|
||||||
The Drone is a convenience class for building. It can be used for...
|
The Drone is a convenience class for building. It can be used for...
|
||||||
|
@ -1451,30 +1498,34 @@ String class extensions
|
||||||
-----------------------
|
-----------------------
|
||||||
The following chat-formatting methods are added to the javascript String class..
|
The following chat-formatting methods are added to the javascript String class..
|
||||||
|
|
||||||
* black()
|
* aqua()
|
||||||
* darkblue()
|
* black()
|
||||||
* blue()
|
* blue()
|
||||||
* darkgreen()
|
* bold()
|
||||||
* darkaqua()
|
* brightgreen()
|
||||||
* darkred()
|
* darkaqua()
|
||||||
* purple()
|
* darkblue()
|
||||||
* gold()
|
* darkgray()
|
||||||
* gray()
|
* darkgreen()
|
||||||
* darkgray()
|
* purple()
|
||||||
* indigo()
|
* darkpurple()
|
||||||
* brightgreen()
|
* darkred()
|
||||||
* green()
|
* gold()
|
||||||
* aqua()
|
* gray()
|
||||||
* red()
|
* green()
|
||||||
* pink()
|
* italic()
|
||||||
* yellow()
|
* lightpurple()
|
||||||
* white()
|
* indigo()
|
||||||
* bold()
|
* green()
|
||||||
* random()
|
* red()
|
||||||
* strike()
|
* pink()
|
||||||
* underline()
|
* yellow()
|
||||||
* italic()
|
* white()
|
||||||
* reset()
|
* strike()
|
||||||
|
* random()
|
||||||
|
* magic()
|
||||||
|
* underline()
|
||||||
|
* reset()
|
||||||
|
|
||||||
Example
|
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")
|
if (typeof load == "function")
|
||||||
return ;
|
return ;
|
||||||
|
|
||||||
var _canonize = function(file){ return file.getCanonicalPath().replaceAll("\\\\","/"); };
|
var _canonize = function(file){
|
||||||
|
return "" + file.getCanonicalPath().replaceAll("\\\\","/");
|
||||||
|
};
|
||||||
|
|
||||||
var _originalScript = __script;
|
var _originalScript = __script;
|
||||||
var parentFileObj = new java.io.File(__script).getParentFile();
|
var parentFileObj = new java.io.File(__script).getParentFile();
|
||||||
var jsPluginsRootDir = parentFileObj.getParentFile();
|
var jsPluginsRootDir = parentFileObj.getParentFile();
|
||||||
var jsPluginsRootDirName = _canonize(jsPluginsRootDir);
|
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 = {};
|
var _loaded = {};
|
||||||
|
@ -331,7 +287,6 @@ var server = org.bukkit.Bukkit.server;
|
||||||
} else {
|
} else {
|
||||||
while ((r = br.readLine()) !== null) code += r + "\n";
|
while ((r = br.readLine()) !== null) code += r + "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
result = __engine.eval(code);
|
result = __engine.eval(code);
|
||||||
_loaded[canonizedFilename] = result || true;
|
_loaded[canonizedFilename] = result || true;
|
||||||
}catch (e){
|
}catch (e){
|
||||||
|
@ -829,7 +784,8 @@ See [issue #69][issue69] for more information.
|
||||||
global._onTabComplete = __onTabCompleteJS;
|
global._onTabComplete = __onTabCompleteJS;
|
||||||
global.addUnloadHandler = _addUnloadHandler;
|
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/
|
// assumes this was loaded from js-plugins/core/
|
||||||
// load all of the plugins.
|
// load all of the plugins.
|
||||||
|
|
Reference in a new issue