Provide more helpful errors when trying to require non-existent modules

This commit is contained in:
walterhiggins 2015-05-31 16:44:42 +01:00
parent 9eb95113c2
commit 4a1c1b7b01
4 changed files with 131 additions and 115 deletions

29
src/main/js/lib/find.js Normal file
View file

@ -0,0 +1,29 @@
'use strict';
var File = java.io.File;
module.exports = function find(dir, filter) {
var result = [];
function recurse( dir, store ) {
var files,
len,
i,
file,
dirfile = new File( dir );
if ( typeof filter == 'undefined' ) {
files = dirfile.list();
} else {
files = dirfile.list(filter);
}
len = files.length; i = 0;
for (; i < len; i++){
file = new File( dir + '/' + files[i] );
if ( file.isDirectory() ) {
recurse( file.canonicalPath, store );
} else {
store.push( ('' + file.canonicalPath).replace(/\\\\/g,'/') );
}
}
}
recurse( dir, result );
return result;
};

View file

@ -2,13 +2,14 @@
/*global persist,exports,config,__plugin,require*/
var File = java.io.File,
FileWriter = java.io.FileWriter,
PrintWriter = java.io.PrintWriter;
PrintWriter = java.io.PrintWriter,
find = require('./find');
/*
plugin management
*/
var _plugins = {};
var _plugin = function(/* String */ moduleName, /* Object */ moduleObject, isPersistent ) {
function _plugin(/* String */ moduleName, /* Object */ moduleObject, isPersistent ) {
//
// don't load plugin more than once
//
@ -26,43 +27,17 @@ var _plugin = function(/* String */ moduleName, /* Object */ moduleObject, isPer
moduleObject.store = persist( moduleName, moduleObject.store );
}
return moduleObject;
};
}
exports.plugin = _plugin;
exports.autoload = function( context, pluginDir, options ) {
var _canonize = function( file ) {
return '' + file.canonicalPath.replaceAll('\\\\','/');
};
/*
recursively walk the given directory and return a list of all .js files
*/
var _listSourceFiles = function( store, dir ) {
var files = dir.listFiles(),
file;
if ( !files ) {
return;
}
for ( var i = 0; i < files.length; i++ ) {
file = files[i];
if ( file.isDirectory( ) ) {
_listSourceFiles( store, file );
}else{
if ( file.canonicalPath.endsWith( '.js' ) ) {
store.push( file );
}
}
}
};
function _autoload( context, pluginDir, options ) {
/*
Reload all of the .js files in the given directory
*/
(function( pluginDir ) {
var sourceFiles = [],
property,
module,
pluginPath;
_listSourceFiles( sourceFiles, pluginDir );
sourceFiles = find(pluginDir);
var len = sourceFiles.length;
if ( config && config.verbose ) {
@ -71,7 +46,10 @@ exports.autoload = function( context, pluginDir, options ) {
for ( var i = 0; i < len; i++ ) {
pluginPath = _canonize( sourceFiles[i] );
pluginPath = sourceFiles[i];
if (!pluginPath.match(/\.js$/)){
continue;
}
module = {};
try {
@ -87,6 +65,8 @@ exports.autoload = function( context, pluginDir, options ) {
console.error( msg );
}
}
}(pluginDir));
};
}
exports.plugin = _plugin;
exports.autoload = _autoload;

View file

@ -66,7 +66,19 @@ module specification, the '.js' suffix is optional.
FileReader = java.io.FileReader,
BufferedReader = java.io.BufferedReader;
var readModuleFromDirectory = function( dir ) {
function fileExists( file ) {
if ( file.isDirectory() ) {
return readModuleFromDirectory( file );
} else {
return file;
}
}
function _canonize(file){
return "" + file.canonicalPath.replaceAll("\\\\","/");
}
function readModuleFromDirectory( dir ) {
// look for a package.json file
var pkgJsonFile = new File( dir, './package.json' );
@ -87,19 +99,8 @@ module specification, the '.js' suffix is optional.
return null;
}
}
};
var fileExists = function( file ) {
if ( file.isDirectory() ) {
return readModuleFromDirectory( file );
} else {
return file;
}
};
var _canonize = function(file){
return "" + file.canonicalPath.replaceAll("\\\\","/");
};
/**********************************************************************
### module name resolution
@ -135,7 +136,7 @@ When resolving module names to file paths, ScriptCraft uses the following rules.
3.2 if no package.json file exists then look for an index.js file in the directory
***/
var resolveModuleToFile = function ( moduleName, parentDir ) {
function resolveModuleToFile( moduleName, parentDir ) {
var file = new File(moduleName),
i = 0,
pathWithJSExt,
@ -179,13 +180,11 @@ When resolving module names to file paths, ScriptCraft uses the following rules.
}
}
return null;
};
var _loadedModules = {};
var _format = java.lang.String.format;
}
/*
require() function implementation
*/
var _require = function( parentFile, path, options ) {
function _require( parentFile, path, options ) {
var file,
canonizedFilename,
moduleInfo,
@ -209,6 +208,29 @@ When resolving module names to file paths, ScriptCraft uses the following rules.
if (! ( (''+path).match( /^\./ ) ) ) {
errMsg = errMsg + ' and not found in paths ' + JSON.stringify(modulePaths);
}
var find = _require(parentFile, 'find').exports;
var allJS = [];
for (var i = 0;i < modulePaths.length; i++){
var js = find( modulePaths[i] );
for (var j = 0;j < js.length; j++){
if (js[j].match(/\.js$/)){
allJS.push( js[j].replace(modulePaths[i],'') );
}
}
}
var pathL = path.toLowerCase();
var candidates = [];
for (i = 0;i < allJS.length;i++){
var filenameparts = allJS[i];
var candidate = filenameparts.replace(/\.js/,'') ;
var lastpart = candidate.toLowerCase();
if (pathL.indexOf(lastpart) > -1 || lastpart.indexOf(pathL) > -1){
candidates.push(candidate);
}
}
if (candidates.length > 0){
errMsg += '\nBut found module/s named: ' + candidates.join(',') + ' - is this what you meant?';
}
throw new Error(errMsg);
}
canonizedFilename = _canonize(file);
@ -285,14 +307,16 @@ When resolving module names to file paths, ScriptCraft uses the following rules.
}
moduleInfo.loaded = true;
return moduleInfo;
};
}
var _requireClosure = function( parent ) {
return function( path, options ) {
function _requireClosure( parent ) {
return function requireBoundToParent( path, options ) {
var module = _require( parent, path , options);
return module.exports;
};
};
}
var _loadedModules = {};
var _format = java.lang.String.format;
return _requireClosure( new java.io.File(rootDir) );
// last line deliberately has no semicolon!
})

View file

@ -143,7 +143,7 @@ This can be useful if you write a plugin that needs to store location data since
A JSON object in the above form.
***/
var _locationToJSON = function( location ) {
function _locationToJSON( location ) {
var yaw = __plugin.bukkit ? location.yaw : (__plugin.canary ? location.rotation : 0);
return {
world: ''+location.world.name,
@ -175,7 +175,7 @@ lookupTable[key] = player.name;
```
***/
exports.locationToString = function( location ) {
exports.locationToString = function locationToString( location ) {
return JSON.stringify( _locationToJSON( location ) );
};
exports.locationToJSON = _locationToJSON;
@ -190,7 +190,7 @@ returned by locationToJSON() and reconstructs and returns a bukkit
Location object.
***/
exports.locationFromJSON = function( json ) {
exports.locationFromJSON = function locationFromJSON( json ) {
var world;
if ( json.constructor == Array ) {
// for support of legacy format
@ -210,7 +210,7 @@ exports.locationFromJSON = function( json ) {
exports.player = _player;
exports.getPlayerObject = function( player ) {
exports.getPlayerObject = function getPlayerObject( player ) {
console.warn( 'utils.getPlayerObject() is deprecated. Use utils.player() instead.' );
return _player(player);
};
@ -281,7 +281,7 @@ if (targetPos){
```
***/
exports.getMousePos = function( player ) {
exports.getMousePos = function getMousePos( player ) {
player = _player(player);
if ( !player ) {
@ -366,20 +366,20 @@ utils.foreach (players, function( player ) {
Java-style collection. This is important because many objects in the
CanaryMod and Bukkit APIs use Java-style collections.
***/
var _foreach = function( array, callback, context, delay, onCompletion ) {
function _foreach( array, callback, context, delay, onCompletion ) {
if ( array instanceof java.util.Collection ) {
array = array.toArray();
}
var i = 0;
var len = array.length;
if ( delay ) {
var next = function( ) {
function next() {
callback(array[i], i, context, array);
i++;
};
var hasNext = function( ) {
}
function hasNext() {
return i < len;
};
}
if ( delay ) {
_nicely( next, hasNext, onCompletion, delay );
} else {
for ( ;i < len; i++ ) {
@ -412,7 +412,7 @@ function and the start of the next `next()` function.
See the source code to utils.foreach for an example of how utils.nicely is used.
***/
var _nicely = function( next, hasNext, onDone, delay ) {
function _nicely( next, hasNext, onDone, delay ) {
if ( hasNext() ){
next();
setTimeout( function() {
@ -426,11 +426,12 @@ var _nicely = function( next, hasNext, onDone, delay ) {
};
exports.nicely = _nicely;
exports.at = function( time24hr, callback, pWorlds, repeat ) {
function _at( time24hr, callback, pWorlds, repeat ) {
console.warn("utils.at() is deprecated, use require('at') instead");
var at = require('at');
return at( time24hr, callback, pWorlds, repeat);
};
}
exports.at = _at;
/*************************************************************************
### utils.time( world ) function
@ -501,27 +502,9 @@ var jsFiles = utils.find('./', function(dir,name){
});
```
***/
exports.find = function( dir , filter ) {
var result = [];
var recurse = function( dir, store ) {
var files, dirfile = new File( dir );
if ( typeof filter == 'undefined' ) {
files = dirfile.list();
} else {
files = dirfile.list(filter);
}
_foreach( files, function( file ) {
file = new File( dir + '/' + file );
if ( file.isDirectory() ) {
recurse( file.canonicalPath, store );
} else {
store.push( file.canonicalPath );
}
});
};
recurse( dir, result );
return result;
exports.find = function( path, filter){
console.warn("utils.find() is deprecated, use require('find') instead");
return require('find')(path, filter);
};
/************************************************************************
### utils.serverAddress() function
@ -534,7 +517,7 @@ var serverAddress = utils.serverAddress();
console.log(serverAddress);
```
***/
exports.serverAddress = function() {
exports.serverAddress = function serverAddress() {
var interfaces = java.net.NetworkInterface.getNetworkInterfaces();
var current,
addresses,
@ -682,7 +665,7 @@ if (__plugin.canary){
function getPlayerNames(){
return getPlayers().map(function(p){ return p.name; });
}
exports.players = function(fn){
exports.players = function players(fn){
var result = getPlayers();
if (fn){
result.forEach(fn);