Factoring out loader implementation from bundle, imports, exports, and framework
diff --git a/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Bundle.js b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Bundle.js
index 4d863fa..827554e 100644
--- a/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Bundle.js
+++ b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Bundle.js
@@ -76,6 +76,12 @@
 		}	
 		return this.getEntry(path);	
 	},
+	getImports : function() {
+		return this._imports;
+	},
+	getExports : function() {
+		return this._exports;
+	},
 	equals : function(other) {
 		if (this === other)
 			return true;
@@ -96,18 +102,7 @@
 		this._state = orion.Bundle.UNINSTALLED;
 	},
 	load : function(name) {
-		var value = this._scope;
-		if (value === null || value === undefined) {
-			return undefined;
-		}
-		var names = name.split(".");
-		for ( var i = 0; i < names.length; i++) {
-			if (value === null || value === undefined) {
-				return undefined;
-			}
-			value = value[names[i]];
-		}
-		return value;
+		return this._framework._loader.load(this, name);
 	},
 	_isSingleton : function() {
 		return this._singleton;
@@ -119,82 +114,11 @@
 		return this._exports;
 	},
 	_resolve : function() {
-		if (this._state != orion.Bundle.INSTALLED)
-			return;
-
-		var namedExports = {};
-		var jsExport = null;
-		var i = 0;
-		// process imports (first)
-		for (i = 0; i < this._imports.length; i++) {
-			var jsImport = this._imports[i];
-			var jsExport = jsImport.getWiredExport();
-			if (!jsExport)
-				continue; // optional
-			var name = jsExport.getName();
-			if (name.charAt(0) == "/")
-				continue; // resource
-			if (!namedExports.hasOwnProperty(name))
-				namedExports[name] = jsImport.getWiredExport();
-		}
-
-		var names = [];
-		var exportName = null;
-		for (exportName in namedExports) {
-			if (namedExports.hasOwnProperty(exportName))
-				names.push(exportName);
-		}
-
-		// this sorts the set of names we'll be importing alphabetically and
-		// perhaps more importantly will allow us to create the shorter/parent dotted entries first
-		names.sort();
-		
-		var importScope = {};
-		for (i = 0; i < names.length; i++) {
-			exportName = names[i];
-			jsExport = namedExports[exportName];
-			jsExport.addToScope(importScope);
-		}
-
-		this._evalScript(importScope);
+		this._framework._loader.resolve(this);
 		this._state = orion.Bundle.RESOLVED;
 	},
-	_evalScript : function(importScope) {
-		var parameterNames = ["bundleContext"];
-		var parameterValues = [this._framework._getBundleContext(this)];
-		var parameterName = null;
-		for (parameterName in importScope) {
-			if (importScope.hasOwnProperty(parameterName)) {
-				parameterNames.push(parameterName);
-				parameterValues.push(importScope[parameterName]);
-			}
-		}
-		
-		var exportNames = [];
-		for (var i = 0; i < this._exports.length; i++) {
-			var exportName = this._exports[i].getName();
-			if (exportName.charAt(0) == "/")
-				continue; // resource
-			var dotIndex = exportName.indexOf(".");
-			if (dotIndex !== -1)
-				exportName = exportName.substring(0,dotIndex);
-			
-			if (! exportNames.hasOwnProperty(exportName)) {
-				exportNames[exportName] = true;
-				exportNames.push(exportName + ":" + exportName);
-			}
-		}
-		
-		var parameterStatement = parameterNames.join(",");
-		var returnStatement = "\n\nreturn {" + exportNames.join(",") + "};";
-				
-		var finalScript = this._script + returnStatement;
-		// var load = new Function(parameterStatement, finalScript);
-		var load = orion.Framework._eval("(function("+parameterStatement+") {\n" + finalScript + "\n})//@ sourceURL=" + this.getLocation());
-		this._scope = load.apply(null, parameterValues);
-	},
 	_unresolve : function() {
-		this._scope = null;
+		this._framework._loader.unresolve(this);
 		if (this._state == orion.Bundle.RESOLVED)
 			this._state = orion.Bundle.INSTALLED;
 	},
diff --git a/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Export.js b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Export.js
index 71e3df3..5063501 100644
--- a/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Export.js
+++ b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Export.js
@@ -62,41 +62,5 @@
 	},
 	getMandatory : function() {
 		return this._mandatory;
-	},
-	addToScope : function (scope) {
-		var value = this._exportingBundle.load(this._name);
-		var tokens = this._name.split(".");
-		var _Wrapper = function() {};
-		var i = 0;
-		while (true) {
-			var token = tokens[i++];
-			var current = null;
-			if (scope.hasOwnProperty(token)) {
-				current = scope[token];
-			}
-			if (i === tokens.length) {
-				if (current === null || current === undefined) {
-					if (typeof value === "object") {
-						_Wrapper.prototype = value;
-						value = new _Wrapper();
-					}
-					scope[token]= value;
-					return;
-				}
-				throw "Resolve error: " + this._name + " already exists for " + this.toString();				
-			}
-			if (current === null || current === undefined) {
-				current = scope[token];
-				if (current === null || current === undefined) {
-					current = {};
-				} else if (typeof current === "object") {
-					_Wrapper.prototype = current;
-					current = new _Wrapper();
-				} else
-					throw "Resolve error: " + this._name + "-" + token + " already exists for " + this.toString(); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
-				scope[token] = current;
-			}
-			scope = current;
-		}
 	}
 };
diff --git a/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Framework.js b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Framework.js
index d03c0b5..f9516e0 100644
--- a/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Framework.js
+++ b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Framework.js
@@ -5,6 +5,7 @@
 	this._requiredBundles = {};
 	this._properties = {};
 	this._currentBundleId = 0;
+	this._loader = new orion.ModuleLoader(this);
 };
 
 orion.Framework.prototype = {
diff --git a/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Import.js b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Import.js
index 4814945..8a90859 100644
--- a/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Import.js
+++ b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Import.js
@@ -25,7 +25,7 @@
 			this._versionRange = orion.VersionRange.parseVersionRange(header.version);
 		
 		if (header.bundleName)
-			this._bundleName = orion.VersionRange.parseVersionRange(header.bundleName);
+			this._bundleName = header.bundleName;
 		
 		if (header.bundleVersion)
 			this._bundleVersionRange = orion.VersionRange.parseVersionRange(header.bundleVersion);
diff --git a/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Loader.js b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Loader.js
new file mode 100644
index 0000000..921dc02
--- /dev/null
+++ b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Loader.js
@@ -0,0 +1,140 @@
+orion.Loader = function(framework){};
+orion.Loader.prototype = {
+	resolve : function(bundle){},
+	unresolve : function(bundle){},
+	load : function(bundle, name){}
+};
+	
+orion.ModuleLoader = function(framework) {
+	this._framework = framework;
+	this._bundleScopes = {};
+};
+
+orion.ModuleLoader.prototype = {
+	resolve : function(bundle) {
+		var namedExports = {};
+		var jsExport = null;
+		var i = 0;
+		// process imports (first)
+		var imports = bundle.getImports();
+		for (i = 0; i < imports.length; i++) {
+			var jsImport = imports[i];
+			var jsExport = jsImport.getWiredExport();
+			if (!jsExport)
+				continue; // optional
+			var name = jsExport.getName();
+			if (name.charAt(0) == "/")
+				continue; // resource
+			if (!namedExports.hasOwnProperty(name))
+				namedExports[name] = jsImport.getWiredExport();
+		}
+	
+		var names = [];
+		var exportName = null;
+		for (exportName in namedExports) {
+			if (namedExports.hasOwnProperty(exportName))
+				names.push(exportName);
+		}
+	
+		// this sorts the set of names we'll be importing alphabetically and
+		// perhaps more importantly will allow us to create the shorter/parent dotted entries first
+		names.sort();
+		
+		var importScope = {};
+		for (i = 0; i < names.length; i++) {
+			exportName = names[i];
+			jsExport = namedExports[exportName];
+			this._addToScope(importScope, jsExport);
+		}
+	
+		this._evalScript(importScope, bundle);
+	},
+	_evalScript : function(importScope, bundle) {
+		var parameterNames = ["bundleContext"];
+		var parameterValues = [this._framework._getBundleContext(bundle)];
+		var parameterName = null;
+		for (parameterName in importScope) {
+			if (importScope.hasOwnProperty(parameterName)) {
+				parameterNames.push(parameterName);
+				parameterValues.push(importScope[parameterName]);
+			}
+		}
+		
+		var exportNames = [];
+		var exports = bundle.getExports();
+		for (var i = 0; i < exports.length; i++) {
+			var exportName = exports[i].getName();
+			if (exportName.charAt(0) == "/")
+				continue; // resource
+			var dotIndex = exportName.indexOf(".");
+			if (dotIndex !== -1)
+				exportName = exportName.substring(0,dotIndex);
+			
+			if (! exportNames.hasOwnProperty(exportName)) {
+				exportNames[exportName] = true;
+				exportNames.push(exportName + ":" + exportName);
+			}
+		}
+		
+		var parameterStatement = parameterNames.join(",");
+		var returnStatement = "\n\nreturn {" + exportNames.join(",") + "};";
+				
+		var finalScript = bundle._script + returnStatement;
+		// var load = new Function(parameterStatement, finalScript);
+		var load = orion.Framework._eval("(function("+parameterStatement+") {\n" + finalScript + "\n})//@ sourceURL=" + bundle.getLocation());
+		this._bundleScopes[bundle.getName + "_" + bundle.getVersion().toString()] = load.apply(null, parameterValues);
+	},
+	_addToScope: function(scope, jsExport) {
+		var value = this.load(jsExport.getExportingBundle(), jsExport.getName());
+		var tokens = jsExport.getName().split(".");
+		var _Wrapper = function() {};
+		var i = 0;
+		while (true) {
+			var token = tokens[i++];
+			var current = null;
+			if (scope.hasOwnProperty(token)) {
+				current = scope[token];
+			}
+			if (i === tokens.length) {
+				if (current === null || current === undefined) {
+					if (typeof value === "object") {
+						_Wrapper.prototype = value;
+						value = new _Wrapper();
+					}
+					scope[token]= value;
+					return;
+				}
+				throw "Resolve error: " + jsExport.getName() + " already exists.";				
+			}
+			if (current === null || current === undefined) {
+				current = scope[token];
+				if (current === null || current === undefined) {
+					current = {};
+				} else if (typeof current === "object") {
+					_Wrapper.prototype = current;
+					current = new _Wrapper();
+				} else
+					throw "Resolve error: " + jsExport.getName() + "-" + token + " already exists.";
+				scope[token] = current;
+			}
+			scope = current;
+		}
+	},
+	unresolve : function (bundle) {
+		delete this._bundleScopes[bundle.getName + "_" + bundle.getVersion().toString()];
+	},
+	load : function(bundle, name) {
+		var value = this._bundleScopes[bundle.getName + "_" + bundle.getVersion().toString()];
+		if (value === null || value === undefined) {
+			return undefined;
+		}
+		var names = name.split(".");
+		for ( var i = 0; i < names.length; i++) {
+			if (value === null || value === undefined) {
+				return undefined;
+			}
+			value = value[names[i]];
+		}
+		return value;
+	}
+};
\ No newline at end of file
diff --git a/tests/org.eclipse.e4.languages.javascript.framework.test/scripts/FrameworkTest.js b/tests/org.eclipse.e4.languages.javascript.framework.test/scripts/FrameworkTest.js
index fd98793..deea049 100644
--- a/tests/org.eclipse.e4.languages.javascript.framework.test/scripts/FrameworkTest.js
+++ b/tests/org.eclipse.e4.languages.javascript.framework.test/scripts/FrameworkTest.js
@@ -212,7 +212,6 @@
 	var framework = new orion.Framework();
 	var a = framework.installBundle("cde", {name:"cde", exports:["abc"], script:"var abc = {hi:7};"});
 	framework.resolve();
-	assertEquals(7, a._scope.abc.hi);
 	assertEquals(7, a.load("abc").hi);
 	var b = framework.installBundle("xyz", {name:"xyz", imports:["abc"], exports:["def"], script:"var def = abc;"});
 	framework.resolve();
@@ -225,7 +224,6 @@
 	var framework = new orion.Framework();
 	var a = framework.installBundle("cde", {name:"cde", exports:["abc","xyz"], script:"var abc = {hi:7};\nvar xyz = {bye:9};"});
 	framework.resolve();
-	assertEquals(7, a._scope.abc.hi);
 	assertEquals(7, a.load("abc").hi);
 	assertEquals(9, a.load("xyz").bye);
 	var b = framework.installBundle("xyz", {name:"xyz", imports:["abc","xyz"], exports:["def","ghi"], script:"var def = abc;\nvar ghi = xyz;"});