Created
January 13, 2016 13:23
-
-
Save ravihara/9bc6908741db1fc9d732 to your computer and use it in GitHub Desktop.
CommonJS require function implementation for Nashorn / Java8
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Based on https://github.com/nodyn/jvm-npm | |
"use strict"; | |
(function() { | |
var System = java.lang.System, | |
File = java.io.File, | |
FileInputStream = java.io.FileInputStream, | |
StringBuilder = java.lang.StringBuilder, | |
BufferedReader = java.io.BufferedReader, | |
InputStreamReader = java.io.InputStreamReader; | |
/* Helper function until ECMAScript 6 is complete */ | |
if (typeof String.prototype.endsWith !== 'function') { | |
String.prototype.endsWith = function(suffix) { | |
if (!suffix) { return false; } | |
return (this.indexOf(suffix, (this.length - suffix.length)) !== -1); | |
}; | |
} | |
/* Define ModuleError to throw exception */ | |
var ModuleError = function(message, code, cause) { | |
this.code = code || "MODULE_ERROR"; | |
this.message = message || "Error loading module"; | |
this.cause = cause; | |
}; | |
ModuleError.prototype = new Error(); | |
ModuleError.prototype.constructor = ModuleError; | |
/* Define the actual Module function */ | |
var Module = function(id, parent, core) { | |
this.id = id; | |
this.core = core; | |
this.parent = parent; | |
this.children = []; | |
this.filename = id; | |
this.loaded = false; | |
Object.defineProperty(this, 'exports', { | |
get: function() { | |
return this._exports; | |
}.bind(this), | |
set: function(val) { | |
Require.cache[this.filename] = val; | |
this._exports = val; | |
}.bind(this) | |
}); | |
this.exports = {}; | |
if (parent && parent.children) { parent.children.push(this); } | |
this.require = function(id) { | |
return Require(id, this); | |
}.bind(this); | |
}; | |
Module.load = function(file, parent, core, main) { | |
var module = new Module(file, parent, core); | |
var __FILENAME__ = module.filename; | |
var body = readFile(module.filename, module.core), | |
dir = new File(module.filename).getParent(), | |
args = ['exports', 'module', 'require', '__filename', '__dirname'], | |
func = new Function(args, body); | |
func.apply(module, [module.exports, module, module.require, module.filename, dir]); | |
module.loaded = true; | |
module.main = main; | |
return module.exports; | |
}; | |
/* Define the actual Require function */ | |
var Require = function(id, parent) { | |
var core, file = Require.resolve(id, parent); | |
if (!file) { | |
System.err.println("Cannot find module " + id); | |
throw new ModuleError("Cannot find module " + id, "MODULE_NOT_FOUND"); | |
} | |
if (file.core) { | |
file = file.path; | |
core = true; | |
} | |
try { | |
if (Require.cache[file]) { | |
return Require.cache[file]; | |
} else if (file.endsWith('.js')) { | |
return Module.load(file, parent, core); | |
} else if (file.endsWith('.json')) { | |
return loadJSON(file); | |
} | |
} catch(ex) { | |
if (ex instanceof java.lang.Exception) { | |
throw new ModuleError("Cannot load module " + id, "LOAD_ERROR", ex); | |
} else { | |
System.out.println("Cannot load module " + id + " LOAD_ERROR"); | |
throw ex; | |
} | |
} | |
}; | |
Require.resolve = function(id, parent) { | |
var roots = findRoots(parent); | |
for (var i = 0 ; i < roots.length ; ++i) { | |
var root = roots[i]; | |
var result = resolveCoreModule(id, root) || | |
resolveAsFile(id, root, '.js') || | |
resolveAsFile(id, root, '.json') || | |
resolveAsDirectory(id, root) || | |
resolveAsJjsModule(id, root); | |
if (result) { return result; } | |
} | |
return false; | |
}; | |
Require.paths = function() { | |
var r = []; | |
r.push(java.lang.System.getProperty( "user.home" ) + "/.jjs_mods"); | |
r.push(java.lang.System.getProperty( "user.home" ) + "/.jjs_libs"); | |
if (Require.JJS_MODS_PATH) { | |
r = r.concat(parsePaths(Require.JJS_MODS_PATH)); | |
} else { | |
var JJS_MODS_PATH = java.lang.System.getenv.JJS_MODS_PATH; | |
if (JJS_MODS_PATH) { | |
r = r.concat(parsePaths(JJS_MODS_PATH)); | |
} | |
} | |
return r; | |
}; | |
/*** internal functions to setup and load the module ***/ | |
var findRoots = function(parent) { | |
var r = []; | |
r.push(findRoot(parent)); | |
return r.concat(Require.paths()); | |
}; | |
var parsePaths = function(paths) { | |
if (! paths) { return []; } | |
if (paths === '') { return []; } | |
var osName = java.lang.System.getProperty("os.name").toLowerCase(); | |
var separator; | |
if (osName.indexOf('win') >= 0 ) { | |
separator = ';'; | |
} else { | |
separator = ':'; | |
} | |
return paths.split(separator); | |
}; | |
var findRoot = function(parent) { | |
if (!parent || !parent.id) { return Require.root; } | |
var pathParts = parent.id.split(/[\/|\\,]+/g); | |
pathParts.pop(); | |
return pathParts.join('/'); | |
}; | |
var loadJSON = function(file) { | |
var json = JSON.parse(readFile(file)); | |
Require.cache[file] = json; | |
return json; | |
}; | |
var resolveAsJjsModule = function(id, root) { | |
var base = [root, 'jjs_mods'].join('/'); | |
return resolveAsFile(id, base) || | |
resolveAsDirectory(id, base) || | |
(root ? resolveAsJjsModule(id, new File(root).getParent()) : false); | |
}; | |
var resolveAsDirectory = function(id, root) { | |
var base = [root, id].join('/'), | |
file = new File([base, 'jjspkg.json'].join('/')); | |
if (file.exists()) { | |
try { | |
var body = readFile(file.getCanonicalPath()), | |
jjspkg = JSON.parse(body); | |
if (jjspkg.main) { | |
return (resolveAsFile(jjspkg.main, base) || resolveAsDirectory(jjspkg.main, base)); | |
} | |
// if no jjspkg.main exists, look for index.js | |
return resolveAsFile('index.js', base); | |
} catch(ex) { | |
throw new ModuleError("Cannot load JSON file", "PARSE_ERROR", ex); | |
} | |
} | |
return resolveAsFile('index.js', base); | |
}; | |
var resolveAsFile = function(id, root, ext) { | |
var file; | |
if ( id.length > 0 && id[0] === '/' ) { | |
file = new File(normalizeName(id, ext || '.js')); | |
if (!file.exists()) { | |
return resolveAsDirectory(id); | |
} | |
} else { | |
file = new File([root, normalizeName(id, ext || '.js')].join('/')); | |
} | |
if (file.exists()) { | |
return file.getCanonicalPath(); | |
} | |
}; | |
var resolveCoreModule = function(id, root) { | |
var name = normalizeName(id); | |
var classloader = java.lang.Thread.currentThread().getContextClassLoader(); | |
if (classloader.getResource(name)) | |
return { path: name, core: true }; | |
}; | |
var normalizeName = function(fileName, ext) { | |
var extension = ext || '.js'; | |
if (fileName.endsWith(extension)) { | |
return fileName; | |
} | |
return fileName + extension; | |
}; | |
var readFile = function(filename, core) { | |
var inStream = null, | |
buffReader = null, | |
strBuilder = new StringBuilder(); | |
try { | |
if (core) { | |
var classloader = java.lang.Thread.currentThread().getContextClassLoader(); | |
inStream = classloader.getResourceAsStream(filename); | |
} else { | |
inStream = new FileInputStream(filename); | |
} | |
buffReader = new BufferedReader(new InputStreamReader(inStream)); | |
var line = buffReader.readLine(); | |
while (line != null) { | |
strBuilder.append(line); | |
line = buffReader.readLine(); | |
} | |
} catch(e) { | |
throw new ModuleError("Cannot read file [" + filename + "]: ", "IO_ERROR", e); | |
} finally { | |
if (null != buffReader) { | |
try { | |
buffReader.close(); | |
} catch (e) { | |
throw new ModuleError("Unable to close buffer-reader for '" + filename + "'"); | |
} | |
} | |
} | |
return strBuilder.toString(); | |
}; | |
/*** Final, export configuration ***/ | |
Require.root = System.getProperty('user.dir'); | |
Require.JJS_MODS_PATH = undefined; | |
Require.debug = true; | |
Require.cache = {}; | |
Require.extensions = {}; | |
return Require; | |
}()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
// Example usage: app.js
var require = load("./jjs-require.js"); // This line is to be added in every file, where 'require' function is needed.
var myDep = require("./my-dep");
myDep.printMe();