Adding pure JavaScript implementation
diff --git a/bundles/org.eclipse.e4.languages.javascript.framework/.classpath b/bundles/org.eclipse.e4.languages.javascript.framework/.classpath
new file mode 100644
index 0000000..ad32c83
--- /dev/null
+++ b/bundles/org.eclipse.e4.languages.javascript.framework/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/bundles/org.eclipse.e4.languages.javascript.framework/.project b/bundles/org.eclipse.e4.languages.javascript.framework/.project
new file mode 100644
index 0000000..1fa88b8
--- /dev/null
+++ b/bundles/org.eclipse.e4.languages.javascript.framework/.project
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.e4.languages.javascript.framework</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.wst.jsdt.core.javascriptValidator</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
+	</natures>
+</projectDescription>
diff --git a/bundles/org.eclipse.e4.languages.javascript.framework/.settings/.jsdtscope b/bundles/org.eclipse.e4.languages.javascript.framework/.settings/.jsdtscope
new file mode 100644
index 0000000..8e0b886
--- /dev/null
+++ b/bundles/org.eclipse.e4.languages.javascript.framework/.settings/.jsdtscope
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="scripts"/>
+	<classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.JRE_CONTAINER"/>
+	<classpathentry exported="true" kind="con" path="org.eclipse.wst.jsdt.launching.baseBrowserLibrary"/>
+	<classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.WebProject">
+		<attributes>
+			<attribute name="hide" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="output" path=""/>
+</classpath>
diff --git a/bundles/org.eclipse.e4.languages.javascript.framework/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.e4.languages.javascript.framework/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..9d55ece
--- /dev/null
+++ b/bundles/org.eclipse.e4.languages.javascript.framework/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,8 @@
+#Fri May 14 15:54:58 EDT 2010
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/bundles/org.eclipse.e4.languages.javascript.framework/.settings/org.eclipse.pde.core.prefs b/bundles/org.eclipse.e4.languages.javascript.framework/.settings/org.eclipse.pde.core.prefs
new file mode 100644
index 0000000..8b0b8e1
--- /dev/null
+++ b/bundles/org.eclipse.e4.languages.javascript.framework/.settings/org.eclipse.pde.core.prefs
@@ -0,0 +1,4 @@
+#Fri May 14 15:54:59 EDT 2010
+eclipse.preferences.version=1
+pluginProject.extensions=false
+resolve.requirebundle=false
diff --git a/bundles/org.eclipse.e4.languages.javascript.framework/.settings/org.eclipse.wst.jsdt.ui.superType.container b/bundles/org.eclipse.e4.languages.javascript.framework/.settings/org.eclipse.wst.jsdt.ui.superType.container
new file mode 100644
index 0000000..3bd5d0a
--- /dev/null
+++ b/bundles/org.eclipse.e4.languages.javascript.framework/.settings/org.eclipse.wst.jsdt.ui.superType.container
@@ -0,0 +1 @@
+org.eclipse.wst.jsdt.launching.baseBrowserLibrary
\ No newline at end of file
diff --git a/bundles/org.eclipse.e4.languages.javascript.framework/.settings/org.eclipse.wst.jsdt.ui.superType.name b/bundles/org.eclipse.e4.languages.javascript.framework/.settings/org.eclipse.wst.jsdt.ui.superType.name
new file mode 100644
index 0000000..05bd71b
--- /dev/null
+++ b/bundles/org.eclipse.e4.languages.javascript.framework/.settings/org.eclipse.wst.jsdt.ui.superType.name
@@ -0,0 +1 @@
+Window
\ No newline at end of file
diff --git a/bundles/org.eclipse.e4.languages.javascript.framework/META-INF/MANIFEST.MF b/bundles/org.eclipse.e4.languages.javascript.framework/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..931919e
--- /dev/null
+++ b/bundles/org.eclipse.e4.languages.javascript.framework/META-INF/MANIFEST.MF
@@ -0,0 +1,6 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Framework
+Bundle-SymbolicName: org.eclipse.e4.languages.javascript.framework
+Bundle-Version: 1.0.0.qualifier
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
diff --git a/bundles/org.eclipse.e4.languages.javascript.framework/build.properties b/bundles/org.eclipse.e4.languages.javascript.framework/build.properties
new file mode 100644
index 0000000..f38581b
--- /dev/null
+++ b/bundles/org.eclipse.e4.languages.javascript.framework/build.properties
@@ -0,0 +1,5 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .,\
+               scripts/
diff --git a/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Bundle.js b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Bundle.js
new file mode 100644
index 0000000..4d960d4
--- /dev/null
+++ b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Bundle.js
@@ -0,0 +1,364 @@
+function Bundle(framework, bundleData) {
+	this._framework = framework;
+	this._bundleData = bundleData;
+	this._name = null;
+	this._version = null;
+	this._imports = [];
+	this._requires = [];
+	this._exports = [];
+	this._resources = {};
+	this._singleton = false;
+	this._markedStarted = false;
+	this._state = Bundle.INSTALLED;
+	this._scope = {};
+	this._bundleContext = null;
+	this._activator = null;
+
+	var headers = bundleData.getHeaders();
+	this._parseName(headers[Constants.BUNDLE_NAME]);
+	this._parseVersion(headers[Constants.BUNDLE_VERSION]);
+	this._parseImports(headers[Constants.BUNDLE_IMPORTS]);
+	this._parseExports(headers[Constants.BUNDLE_EXPORTS]);
+	this._parseRequires(headers[Constants.BUNDLE_REQUIRES]);
+	this._parseResources(headers[Constants.BUNDLE_RESOURCES]);
+}
+
+Bundle.UNINSTALLED = 1;
+Bundle.INSTALLED = 2;
+Bundle.RESOLVED = 4;
+Bundle.STARTING = 8;
+Bundle.STOPPING = 16;
+Bundle.ACTIVE = 32;
+
+Bundle.prototype = {
+	getName : function() {
+		return this._name;
+	},
+	getVersion : function() {
+		return this._version;
+	},
+	getBundleId : function() {
+		return this._bundleData.getBundleId();
+	},
+	getLocation : function() {
+		return this._bundleData.getLocation();
+	},
+	getHeaders : function() {
+		return this._bundleData.getHeaders();
+	},
+	getState : function() {
+		return this._state;
+	},
+	getEntry : function(path) {
+		if (!path || !path instanceof String || !this._resources[path])
+			return null;
+		
+		return this.getLocation() + path;
+	},
+	getResource : function(path) {
+		if (!path || !path instanceof String)
+			return null;
+		
+		var i = 0;
+		var resource;
+		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; // not a resource
+			if (path.indexOf(name)==0) {
+				resource = jsExport.getExportingBundle().getEntry(path);
+				if (resource)
+					return resource;
+			}
+		}
+
+		// process requires
+		for (i = 0; i < this._requires.length; i++) {
+			var jsRequire = this._requires[i];
+			var wiredBundle = jsRequire.getWiredBundle();
+			if (!wiredBundle) {
+				continue; //optional
+			}
+			var wiredBundleExports = wiredBundle._getExports();
+			for (var j=0; j < wiredBundleExports.length; j++) {
+				jsExport = wiredBundleExports[j];
+				var name = jsExport.getName();
+				if (name.charAt(0) != "/")
+					continue; // not a resource
+				if (path.indexOf(name)==0) {
+					resource = jsExport.getExportingBundle().getEntry(path);
+					if (resource)
+						return resource;
+				}
+			}
+		}		
+		return this.getEntry(path);	
+	},
+	equals : function(other) {
+		if (this === other)
+			return true;
+
+		if (!other instanceof Bundle)
+			return false;
+
+		if (this._name !== other._name)
+			return false;
+		if (this._version === null) {
+			if (other._version !== null)
+				return false;
+		} else if (!this._version.equals(other._version))
+			return false;
+		return true;
+	},
+	uninstall : function() {
+		this._state = Bundle.UNINSTALLED;
+	},
+	start : function() {
+		this._markedStarted = true;
+		if (this._state !== Bundle.RESOLVED)
+			return;
+
+		this._state = Bundle.STARTING;
+		this._bundleContext = this._framework._getBundleContext(this);
+		this._activator = this._createActivatorInstance();
+		if (this._activator) {
+			this._activator.start(this._bundleContext);
+		}
+		this._state = Bundle.ACTIVE;
+	},
+	stop : function() {
+		markedStarted = false;
+		if (this._state !== Bundle.ACTIVE)
+			return;
+
+		this._state = Bundle.STOPPING;
+		if (this._activator) {
+			this._activator.stop(this._bundleContext);
+		}
+		this._state = Bundle.RESOLVED;
+	},
+	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;
+	},
+	_isSingleton : function() {
+		return this._singleton;
+	},
+	_isMarkedStarted : function() {
+		return this._markedStarted;
+	},
+	_getImports : function() {
+		return this._imports;
+	},
+	_getExports : function() {
+		return this._exports;
+	},
+	_getRequires : function() {
+		return this._requires;
+	},
+	_createActivatorInstance : function() {
+		var activatorName = this.getHeaders()[Constants.BUNDLE_ACTIVATOR];
+		if (activatorName === null || activatorName === undefined)
+			return null;
+
+		var activatorFunction = this.load(activatorName);
+		if (typeof activatorFunction !== "function")
+			throw "" + activatorName + " is not a function.";
+		return new activatorFunction();
+	},
+	_resolve : function() {
+		if (this._state != 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();
+		}
+
+		// process requires
+		for (i = 0; i < this._requires.length; i++) {
+			var jsRequire = this._requires[i];
+			var wiredBundle = jsRequire.getWiredBundle();
+			if (!wiredBundle) {
+				continue; //optional
+			}
+			var wiredBundleExports = wiredBundle._getExports();
+			for (var j=0; j < wiredBundleExports.length; j++) {
+				jsExport = wiredBundleExports[j];
+				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._state = Bundle.RESOLVED;
+	},
+	_evalScript : function(importScope) {
+		var parameterNames = [];
+		var parameterValues = [];
+		var parameterName = null;
+		for (parameterName in importScope) {
+			if (importScope.hasOwnProperty(parameterName)) {
+				parameterNames.push(parameterName);
+				parameterValues.push(importScope[parameterName]);
+			}
+			
+		}
+		
+		var exportNames = [];
+		for (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 script = this._bundleData.getHeaders()[Constants.BUNDLE_SCRIPT] || "";
+		var returnStatement = "\n\nreturn {" + exportNames.join(",") + "};";
+
+		var that = this;
+		var loader = {
+			getResources: function(path) {
+				return that.getResources(path);
+			}
+		};
+		
+		var finalScript = script + returnStatement;
+		var load = new Function(parameterStatement, finalScript);
+		this._scope = load.apply(loader, parameterValues);
+	},
+	_unresolve : function() {
+		if (this._state == Bundle.ACTIVE) {
+			this.stop();
+			markedStarted = true;
+		}
+		this._scope = null;
+
+		if (this._state == Bundle.RESOLVED)
+			this._state = Bundle.INSTALLED;
+	},
+	_parseName : function(header) {
+		var tokens = header.split(Constants.PARAMETER_DELIMITER);
+		this._name = tokens[0].replace(/^\s+|\s+$/g, '');
+		for ( var i = 1; i < tokens.length; i++) {
+			var token = tokens[i];
+			if (token.indexOf(Constants.DIRECTIVE_EQUALS) != -1) {
+				var index = token.indexOf(Constants.DIRECTIVE_EQUALS);
+				var directiveName = token.substring(0, index).replace(/^\s+|\s+$/g, '');
+				if (directiveName.length === 0)
+					throw "bad syntax: " + token + " in " + header;
+
+				if (directiveName !== Constants.SINGLETON_DIRECTIVE)
+					continue;
+				var value = token.substring(index + Constants.DIRECTIVE_EQUALS.length).replace(/^\s+|\s+$/g, '');
+				if (value.toLowerCase() === "true")
+					this._singleton = true;
+			} else
+				throw "bad syntax: " + token + " in " + header;
+		}
+	},
+	_parseVersion : function(header) {
+		this._version = Version.parseVersion(header);
+	},
+	_parseResources : function(header) {
+		if (!header)
+			return;
+
+		var tokens = header.split(Constants.CLAUSE_DELIMITER);
+		for ( var i = 0; i < tokens.length; i++) {
+			if (tokens[i]) {
+				var path = tokens[i].replace(/^\s+|\s+$/g, '');
+				this._resources[path] = true;
+			}
+		}
+	},
+	_parseRequires : function(header) {
+		if (!header)
+			return;
+
+		var tokens = header.split(Constants.CLAUSE_DELIMITER);
+		for ( var i = 0; i < tokens.length; i++) {
+			var token = tokens[i];
+			var jsRequire = new _Require(token);
+			if (jsRequire !== null)
+				this._requires.push(jsRequire);
+		}
+	},
+	_parseExports : function(header) {
+		if (!header)
+			return;
+		var tokens = header.split(Constants.CLAUSE_DELIMITER);
+		for ( var i = 0; i < tokens.length; i++) {
+			var token = tokens[i];
+			var jsExport = new _Export(token, this);
+			if (jsExport !== null)
+				this._exports.push(jsExport);
+		}
+	},
+	_parseImports : function(header) {
+		if (!header)
+			return;
+
+		var tokens = header.split(Constants.CLAUSE_DELIMITER);
+		for ( var i = 0; i < tokens.length; i++) {
+			var token = tokens[i];
+			var jsImport = new _Import(token);
+			if (jsImport !== null)
+				this._imports.push(jsImport);
+		}
+	}
+};
diff --git a/bundles/org.eclipse.e4.languages.javascript.framework/scripts/BundleContext.js b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/BundleContext.js
new file mode 100644
index 0000000..2685312
--- /dev/null
+++ b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/BundleContext.js
@@ -0,0 +1,19 @@
+function BundleContext(bundle, framework) {
+	this._bundle = bundle;
+	this._framework = framework;
+}
+
+BundleContext.prototype = {
+	getBundle : function() {
+		return this._bundle;
+	},
+	getBundles : function() {
+		return this._framework.getBundles();
+	},
+	getProperty : function(name) {
+		return this._framework.getProperty(name);
+	},
+	installBundle : function(location, headers) {
+		return this._framework.installBundle(location, headers);
+	}
+};
\ No newline at end of file
diff --git a/bundles/org.eclipse.e4.languages.javascript.framework/scripts/BundleData.js b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/BundleData.js
new file mode 100644
index 0000000..21f57ce
--- /dev/null
+++ b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/BundleData.js
@@ -0,0 +1,17 @@
+function BundleData(bundleId, location, headers) {
+	this._bundleId = bundleId;
+	this._location = location;
+	this._headers = headers;
+}
+
+BundleData.prototype = {
+	getBundleId : function() {
+		return this._bundleId;
+	},
+	getLocation : function() {
+		return this._location;
+	},
+	getHeaders : function() {
+		return this._headers;
+	}
+};
diff --git a/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Constants.js b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Constants.js
new file mode 100644
index 0000000..89f5f08
--- /dev/null
+++ b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Constants.js
@@ -0,0 +1,26 @@
+var Constants = {
+	ATTRIBUTE_EQUALS : "=",
+	DIRECTIVE_EQUALS : ":=",
+	PARAMETER_DELIMITER : ";",
+	MANDATORY_DELIMITER : ",",
+	SCRIPT_PATH_DELIMITER : ",",
+	CLAUSE_DELIMITER : ",",
+	BUNDLE_NAME : "name",
+	BUNDLE_VERSION : "version",
+	BUNDLE_IMPORTS : "imports",
+	BUNDLE_EXPORTS : "exports",
+	BUNDLE_REQUIRES : "requires",
+	BUNDLE_SCRIPT : "script",
+	BUNDLE_PATH : "path",
+	BUNDLE_ACTIVATOR : "activator",
+	BUNDLE_RESOURCES : "resources",
+	SCRIPT_PATH_DOT : ".",
+	BUNDLE_NAME_ATTRIBUTE : "bundle-name",
+	BUNDLE_VERSION_ATTRIBUTE : "bundle-version",
+	VERSION_ATTRIBUTE : "version",
+	RESOLUTION_DIRECTIVE : "resolution",
+	RESOLUTION_OPTIONAL : "optional",
+	RESOLUTION_MANDATORY : "mandatory",
+	MANDATORY_DIRECTIVE : "mandatory",
+	SINGLETON_DIRECTIVE : "singleton"
+};
\ No newline at end of file
diff --git a/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Framework.js b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Framework.js
new file mode 100644
index 0000000..d56f4fc
--- /dev/null
+++ b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Framework.js
@@ -0,0 +1,280 @@
+function Framework() {
+	this._installOrderBundles = [];
+	this._resolveOrderBundles = [];
+	this._exports = {};
+	this._requiredBundles = {};
+	this._properties = {};
+	this._currentBundleId = 0;
+}
+
+Framework.prototype = {
+	getBundles : function() {
+		return this._installOrderBundles.slice();
+	},
+	getProperty : function(name) {
+		return this._properties[name];
+	},
+	setProperty : function(name, value) {
+		this._properties[name] = value;
+	},
+	installBundle : function(location, headers) {
+		if (location === undefined)
+			throw "location cannot be undefined";
+		
+		if (location === null)
+			throw "location cannot be null";
+
+		var bundleData = new BundleData(this._currentBundleId, location, headers);
+		var bundle = new Bundle(this, bundleData);
+
+		for ( var i = 0; i < this._installOrderBundles.length; i++) {
+			if (bundle.equals(this._installOrderBundles[i]))
+				return this._installOrderBundles[i];
+		}
+		this._installOrderBundles[this._currentBundleId] = bundle;
+		this._currentBundleId++;
+
+		return bundle;
+	},
+	refresh : function() {
+		var uninstalledBundleFound = false;
+		var resolvedBundles = this._resolveOrderBundles.slice();
+		var i = 0;
+		var bundle = null;
+		
+		var newInstallOrderBundles = [];
+		for (i = 0; i < this._installOrderBundles.length; i++) {
+			bundle = this._installOrderBundles[i];
+			if (bundle.getState() !== Bundle.UNINSTALLED) {
+				newInstallOrderBundles.push(bundle);
+			}
+		}
+		this._installOrderBundles = newInstallOrderBundles;
+		
+		for (i = 0; i < resolvedBundles.length; i++) {
+			bundle = resolvedBundles[i];
+			if (bundle.getState() === Bundle.UNINSTALLED) {
+				uninstalledBundleFound = true;
+			}
+
+			if (uninstalledBundleFound) {
+				this._unresolveBundle(bundle);
+			}
+		}
+		if (uninstalledBundleFound) {
+			var newResolveOrderBundles = [];
+			for (i = 0; i < this._resolveOrderBundles.length; i++) {
+				bundle = this._resolveOrderBundles[i];
+				if (bundle.getState() === Bundle.RESOLVED || bundle.getState() === Bundle.ACTIVE) {
+					newResolveOrderBundles.push(bundle);
+				}
+			}
+			this._resolveOrderBundles = newResolveOrderBundles;
+
+			this.resolve();
+		}
+	},
+	resolve : function() {
+		var unresolvedBundles = [];
+		var i = 0;
+		for (i = 0; i < this._installOrderBundles.length; i++) {
+			var bundle = this._installOrderBundles[i];
+			if (bundle.getState() === Bundle.INSTALLED)
+				unresolvedBundles.push(bundle);
+		}
+
+		var resolvedBundles = [];
+		var resolvedBundle = null;
+		while (unresolvedBundles.length !== 0) {
+			resolvedBundle = this._stepResolver(unresolvedBundles);
+			if (resolvedBundle !== null)
+				resolvedBundles.push(resolvedBundle);
+			else
+				break;
+		}
+		for (i = 0; i < resolvedBundles; i++) {
+			resolvedBundle = resolvedBundles[i];
+			if (resolvedBundle.isMarkedStarted())
+				resolvedBundle.start();
+		}
+	},
+	shutdown : function() {
+		var reversed = this._installOrderBundles.slice().reverse();
+		for ( var i = 0; i < reversed.length; i++) {
+			var bundle = reversed[i];
+			bundle.stop();
+			bundle.uninstall();
+		}
+		this.refresh();
+	},
+	_getBundleContext : function(bundle) {
+		return new BundleContext(bundle, this);
+	},
+	_stepResolver : function(unresolvedBundles) {
+		for (var i = 0; i < unresolvedBundles.length; i++) {
+			var bundle = unresolvedBundles[i];
+			if (this._resolveBundle(bundle)) {
+				this._resolveOrderBundles.push(bundle);
+				unresolvedBundles.splice(i,1);
+				return bundle;
+			}
+		}
+		return null;
+	},
+	_resolveBundle: function(bundle) {
+		if (bundle._isSingleton() && this._requiredBundles[bundle.getName()])
+			return false;
+
+		if (this._wire(bundle)) {
+			bundle._resolve();
+			this._addExports(bundle);
+			this._addRequiredBundle(bundle);
+			return true;
+		}
+		this._unwire(bundle);
+		return false;
+	},
+	_wire : function(bundle) {
+		return this._wireRequires(bundle) && this._wireImports(bundle);
+	},
+	_wireRequires : function(bundle) {
+		var requires = bundle._getRequires();
+		for (var i = 0; i < requires.length; i++) {
+			var jsRequire = requires[i];
+			var name = jsRequire.getName();
+			var candidates = this._requiredBundles[name];
+			var satisfied = false;
+			if (candidates) {
+				for (var j = 0; j < candidates.length; j++) {
+					var candidate = candidates[j];
+					satisfied = jsRequire.wire(candidate);
+					if (satisfied)
+						break;
+				}
+			}
+			if (!satisfied && !jsRequire.isOptional())
+				return false;
+		}
+		return true;
+	},
+	_wireImports : function(bundle) {
+		var imports = bundle._getImports();
+		for (var i = 0; i < imports.length; i++) {
+			var jsImport = imports[i];
+			var name = jsImport.getName();
+			var candidates = this._exports[name];
+			var satisfied = false;
+			if (candidates) {
+				for (var j = 0; j < candidates.length; j++) {
+					var candidate = candidates[j];
+					satisfied = jsImport.wire(candidate);
+					if (satisfied)
+						break;
+				}
+			}
+			if (!satisfied && !jsImport.isOptional())
+				return false;
+		}
+		return true;
+	},
+	_addExports : function(bundle) {
+		var exports = bundle._getExports();
+		for (var i = 0; i < exports.length; i++) {
+			var jsExport = exports[i];
+			var name = jsExport.getName();
+			var namedExports = this._exports[name];
+			if (!namedExports) {
+				namedExports = [];
+				this._exports[name] = namedExports;
+			}
+			namedExports.push(jsExport);
+			namedExports.sort(Framework._exportsComparator);
+		}
+	},
+	_addRequiredBundle : function(bundle) {
+		var name = bundle.getName();
+		var namedBundles = this._requiredBundles[name];
+		if (! namedBundles) {
+			namedBundles = [];
+			this._requiredBundles[name]= namedBundles;
+		}
+		namedBundles.push(bundle);
+		namedBundles.sort(Framework._requireBundlesComparator);
+	},
+	_unresolveBundle : function(bundle) {
+		this._removeExports(bundle);
+		this._removeRequiredBunde(bundle);
+		bundle._unresolve();
+		this._unwire(bundle);
+	},
+	_removeExports : function(bundle) {
+		var exports = bundle._getExports();
+		for ( var i = 0; i < exports.length; i++) {
+			var jsExport = exports[i];
+			var name = jsExport.getName();
+			var namedExports = this._exports[name];
+			if (!namedExports)
+				continue;
+
+			for ( var j = 0; j < namedExports.length; j++) {
+				if (namedExports[j] === jsExport) {
+					namedExports.splice(j, 1);
+					break;
+				}
+			}
+			if (namedExports.length === 0)
+				delete this._exports[name];
+		}
+	},
+	_removeRequiredBunde : function(bundle) {
+		var name = bundle.getName();
+		var namedBundles = this._requiredBundles[name];
+		if (!namedBundles)
+			return;
+
+		for ( var i = 0; i < namedBundles.length; i++) {
+			if (namedBundles[i] === bundle) {
+				namedBundles.splice(i, 1);
+				break;
+			}
+		}
+		if (namedBundles.length === 0)
+			delete this._requiredBundles[name];
+	},
+	_unwire : function(bundle) {
+		this._unwireImports(bundle);
+		this._unwireRequires(bundle);
+	},
+	_unwireImports : function(bundle) {
+		var imports = bundle._getImports();
+		for ( var i = 0; i < imports.length; i++) {
+			var jsImport = imports[i];
+			jsImport.unwire();
+		}
+	},
+	_unwireRequires : function(bundle) {
+		var requires = bundle._getRequires();
+		for ( var i = 0; i < requires.length; i++) {
+			var jsRequires = requires[i];
+			jsRequires.unwire();
+		}
+	}
+};
+
+Framework._exportsComparator = function(export0, export1) {
+	// order switched for descending order
+	var result = export1.getVersion().compareTo(export0.getVersion());
+	if (result == 0)
+		result = export0.getBundleId() - export1.getBundleId();
+
+	return result;
+};
+
+Framework._requireBundlesComparator = function(bundle0, bundle1) {
+	// order switched for descending order
+	var result = bundle1.getVersion().compareTo(bundle0.getVersion());
+	if (result == 0)
+		result = bundle0.getBundleId() - bundle1.getBundleId();
+
+	return result;
+};
diff --git a/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Version.js b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Version.js
new file mode 100644
index 0000000..9909e66
--- /dev/null
+++ b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/Version.js
@@ -0,0 +1,114 @@
+function Version(major, minor, micro, qualifier) {
+	if (!Version._isInteger(major) || major < 0)
+		throw "invalid major:" + major;
+
+	if (!Version._isInteger(minor) || minor < 0)
+		throw "invalid minor:" + minor;
+
+	if (!Version._isInteger(micro) || micro < 0)
+		throw "invalid micro:" + micro;
+
+	if (qualifier === null || qualifier === undefined)
+		qualifier = "";
+	else if (typeof qualifier !== "string" || !qualifier.match(/[\w\-]*/))
+		throw "invalid qualifier: " + qualifier;
+
+	this._major = (major > Version.MAX_VALUE) ? Version.MAX_VALUE : major;
+	this._minor = (minor > Version.MAX_VALUE) ? Version.MAX_VALUE : minor;
+	this._micro = (micro > Version.MAX_VALUE) ? Version.MAX_VALUE : micro;
+
+	if (this._major == Version.MAX_VALUE && this._minor == Version.MAX_VALUE && this._micro == Version.MAX_VALUE)
+		this._qualifier = "";
+	else
+		this._qualifier = qualifier;
+};
+
+Version.prototype = {
+	getMajor : function() {
+		return this._major;
+	},
+	getMinor : function() {
+		return this._minor;
+	},
+	getMicro : function() {
+		return this._micro;
+	},
+	getQualifier : function() {
+		return this._qualifier;
+	},
+	toString : function() {
+		var result = "" + this._major + "." + this._minor + "." + this._micro;
+		if (this._qualifier.length > 0)
+			result += "." + this._qualifier;
+		return result;
+	},
+	equals : function(other) {
+		return other instanceof Version && this._major === other._major && this._minor === other._minor && this._micro === other._micro && this._qualifier === other._qualifier;
+	},
+	compareTo : function(other) {
+		if (this === other)
+			return 0;
+
+		var result = this._major - other._major;
+		if (result !== 0)
+			return result;
+
+		result = this._minor - other._minor;
+		if (result !== 0)
+			return result;
+
+		result = this._micro - other._micro;
+		if (result !== 0)
+			return result;
+
+		if (this._qualifier === other._qualifier)
+			return 0;
+
+		return this._qualifier > other._qualifier ? 1 : -1;
+	}
+};
+Version._isInteger = function(number) {
+	return (typeof number == "number" && !isNaN(number) && isFinite(number) && Math.floor(number) == number);
+};
+Version.MAX_VALUE = Math.pow(2, 32);
+Version.EMPTY_VERSION = new Version(0, 0, 0);
+Version.MAX_VERSION = new Version(Version.MAX_VALUE, Version.MAX_VALUE, Version.MAX_VALUE);
+Version.parseVersion = function(text) {
+	if (text === null || text === undefined)
+		return Version.EMPTY_VERSION;
+
+	if (typeof text !== "string")
+		throw "invalid text:" + text;
+
+	text = text.replace(/^\s+|\s+$/g, '');
+	if (text.length === 0 || text === "0.0.0")
+		return Version.EMPTY_VERSION;
+
+	var tokens = text.split(".");
+	if (tokens.length > 4)
+		throw "invalid format: " + text;
+
+	if (!tokens[0].match(/[\d]+/))
+		throw "invalid format: " + text;
+
+	var major = parseInt(tokens[0]);
+	var minor = 0;
+	var micro = 0;
+	var qualifier = "";
+
+	if (tokens.length > 1) {
+		if (!tokens[1].match(/[\d]+/))
+			throw "invalid format: " + text;
+		minor = parseInt(tokens[1]);
+
+		if (tokens.length > 2) {
+			if (!tokens[2].match(/[\d]+/))
+				throw "invalid format: " + text;
+			micro = parseInt(tokens[2]);
+
+			if (tokens.length > 3)
+				qualifier = tokens[3];
+		}
+	}
+	return new Version(major, minor, micro, qualifier);
+};
diff --git a/bundles/org.eclipse.e4.languages.javascript.framework/scripts/VersionRange.js b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/VersionRange.js
new file mode 100644
index 0000000..b67c0d6
--- /dev/null
+++ b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/VersionRange.js
@@ -0,0 +1,107 @@
+function VersionRange(minVersion, includeMin, maxVersion, includeMax) {
+	if (minVersion != null && !(minVersion instanceof Version))
+		throw "invalid minVersion:" + minVersion;
+
+	if (typeof includeMin !== "boolean")
+		throw "invalid includeMin:" + includeMin;
+
+	if (maxVersion != null && !(maxVersion instanceof Version))
+		throw "invalid maxVersion:" + minVersion;
+
+	if (typeof includeMax !== "boolean")
+		throw "invalid includeMax:" + includeMax;
+
+	this._minVersion = minVersion || Version.EMPTY_VERSION;
+	this._includeMin = includeMin;
+	this._maxVersion = maxVersion || Version.MAX_VERSION;
+	this._includeMax = includeMax;
+}
+
+VersionRange.prototype = {
+	getMinimum : function() {
+		return this._minVersion;
+	},
+	getIncludeMinimum : function() {
+		return this._includeMin;
+	},
+	getMaximum : function() {
+		return this._maxVersion;
+	},
+	getIncludeMaximum : function() {
+		return this._includeMax;
+	},
+	equals : function(other) {
+		if (this === other)
+			return true;
+
+		if (!other instanceof VersionRange)
+			return false;
+
+		if (this._includeMin !== other._includeMin || this._includeMax !== other._includeMax)
+			return false;
+
+		if (!this._minVersion.equals(other._minVersion))
+			return false;
+
+		if (!this._maxVersion.equals(other._maxVersion))
+			return false;
+
+		return true;
+	},
+	isIncluded : function(version) {
+		if (version == null)
+			version = Version.MIN_VERSION;
+		
+		if (!version instanceof Version)
+			return false;
+		
+		var minCheck = this._includeMin ? 0 : 1;
+		var maxCheck = this._includeMax ? 0 : -1;
+		return version.compareTo(this._minVersion) >= minCheck && version.compareTo(this._maxVersion) <= maxCheck;
+	},
+	toString : function() {
+		if (this._includeMin && this._includeMax && Version.MAX_VERSION.equals(this._maxVersion))
+			return this._minVersion.toString();
+
+		return (this._includeMin ? '[' : '(') + this._minVersion + ',' + this._maxVersion + (this._includeMax ? ']' : ')');
+	}
+};
+
+VersionRange.EMPTY_RANGE = new VersionRange(Version.EMPTY_VERSION, true, Version.MAX_VERSION, true);
+
+VersionRange.parseVersionRange = function(text) {
+	if (text === null)
+		return VersionRange.EMPTY_RANGE;
+
+	if (typeof text !== "string")
+		throw "invalid text:" + text;
+
+	text = text.replace(/^\s+|\s+$/g, '');
+	if (text.length === 0)
+		return VersionRange.EMPTY_RANGE;
+
+	var minVersion = null;
+	var includeMin = false;
+	var maxVersion = null;
+	var includeMax = false;
+
+	if (text.charAt(0) === '[' || text.charAt(0) == '(') {
+		var comma = text.indexOf(',');
+		if (comma === -1)
+			throw "invalid text:" + text;
+		var last = text.charAt(text.length - 1);
+		if (last !== ']' && last !== ')')
+			throw "invalid text:" + text;
+
+		minVersion = Version.parseVersion(text.substring(1, comma).replace(/^\s+|\s+$/g, ''));
+		includeMin = text.charAt(0) == '[';
+		maxVersion = Version.parseVersion(text.substring(comma + 1, text.length() - 1).replace(/^\s+|\s+$/g, ''));
+		includeMax = last == ']';
+	} else {
+		minVersion = Version.parseVersion(text);
+		includeMin = true;
+		maxVersion = Version.MAX_VERSION;
+		includeMax = true;
+	}
+	return new VersionRange(minVersion, includeMin, maxVersion, includeMax);
+};
diff --git a/bundles/org.eclipse.e4.languages.javascript.framework/scripts/_Export.js b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/_Export.js
new file mode 100644
index 0000000..0cb404b
--- /dev/null
+++ b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/_Export.js
@@ -0,0 +1,128 @@
+function _Export(header, exportingBundle) {
+	if (header === null)
+		throw "header cannot be null";
+
+	if (exportingBundle === null)
+		throw "exportingBundle cannot be null";
+
+	this._name = null;
+	this._version = Version.EMPTY_VERSION;
+	this._attributes = {};
+	this._directives = {};
+	this._mandatory = [];
+	this._exportingBundle = exportingBundle;
+
+	this._parseExport(header);
+}
+
+_Export.prototype = {
+	_parseExport : function(header) {
+		var tokens = header.split(Constants.PARAMETER_DELIMITER);
+		this._name = tokens[0].replace(/^\s+|\s+$/g, '');
+		for ( var i = 1; i < tokens.length; i++) {
+			var token = tokens[i];
+			if (token.indexOf(Constants.DIRECTIVE_EQUALS) !== -1)
+				this._parseDirective(token);
+			else if (token.indexOf(Constants.ATTRIBUTE_EQUALS) !== -1)
+				this._parseAttribute(token);
+			else
+				throw "bad export syntax: " + token + " in " + header;
+		}
+	},
+	_parseAttribute : function(token) {
+		var index = token.indexOf(Constants.ATTRIBUTE_EQUALS);
+		var attributeName = token.substring(0, index).replace(/^\s+|\s+$/g, '');
+		if (attributeName.length === 0)
+			return;
+
+		var value = token.substring(index + Constants.ATTRIBUTE_EQUALS.length).replace(/^\s+|\s+$/g, '');
+
+		if (attributeName === Constants.VERSION_ATTRIBUTE)
+			this._version = Version.parseVersion(value);
+
+		this._attributes[attributeName] = value;
+	},
+	_parseDirective : function(token) {
+		var index = token.indexOf(Constants.DIRECTIVE_EQUALS);
+		var directiveName = token.substring(0, index).replace(/^\s+|\s+$/g, '');
+		if (directiveName.length === 0)
+			return;
+
+		var value = token.substring(index + Constants.DIRECTIVE_EQUALS.length).replace(/^\s+|\s+$/g, '');
+		if (directiveName === Constants.MANDATORY_DIRECTIVE)
+			this._parseMandatory(value);
+
+		this._directives[directiveName] = value;
+	},
+	_parseMandatory : function(value) {
+		var tokens = value.split(Constants.MANDATORY_DELIMITER);
+		for ( var i = 0; i < tokens.length; i++) {
+			var token = tokens[i].replace(/^\s+|\s+$/g, '');
+			if (token.length > 0)
+				this._mandatory.push(token);
+		}
+	},
+	getName : function() {
+		return this._name;
+	},
+	getVersion : function() {
+		return this._version;
+	},
+	getBundleId : function() {
+		return this._exportingBundle.getBundleId();
+	},
+	getBundleSymbolicName : function() {
+		return this._exportingBundle.getSymbolicName();
+	},
+	getBundleVersion : function() {
+		return this._exportingBundle.getVersion();
+	},
+	getAttributes : function() {
+		this._attributes;
+	},
+	getDirectives : function() {
+		return this._directives;
+	},
+	getExportingBundle : function() {
+		return this._exportingBundle;
+	},
+	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/_Import.js b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/_Import.js
new file mode 100644
index 0000000..78dbc25
--- /dev/null
+++ b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/_Import.js
@@ -0,0 +1,128 @@
+function _Import(header) {
+	if (header === null)
+		throw "header cannot be null";
+
+	this._name = null;
+	this._versionRange = VersionRange.EMPTY_RANGE;
+	this._bundleSymbolicName = null;
+	this._bundleVersionRange = VersionRange.EMPTY_RANGE;
+	this._optional = false;
+	this._attributes = {};
+	this._directives = {};
+	this._wiredExport = null;
+
+	this._parseImport(header);
+}
+
+_Import.prototype = {
+	_parseImport : function(header) {
+		var tokens = header.split(Constants.PARAMETER_DELIMITER);
+		this._name = tokens[0].replace(/^\s+|\s+$/g, '');
+		for ( var i = 1; i < tokens.length; i++) {
+			var token = tokens[i];
+			if (token.indexOf(Constants.DIRECTIVE_EQUALS) !== -1)
+				this._parseDirective(token);
+			else if (token.indexOf(Constants.ATTRIBUTE_EQUALS) !== -1)
+				this._parseAttribute(token);
+			else
+				throw "bad import syntax: " + token + " in " + header;
+		}
+	},
+	_parseAttribute : function(token) {
+		var index = token.indexOf(Constants.ATTRIBUTE_EQUALS);
+		var attributeName = token.substring(0, index).replace(/^\s+|\s+$/g, '');
+		if (attributeName.length === 0)
+			return;
+
+		var value = token.substring(index + Constants.ATTRIBUTE_EQUALS.length).replace(/^\s+|\s+$/g, '');
+
+		if (attributeName === Constants.VERSION_ATTRIBUTE)
+			this._versionRange = VersionRange.parseVersionRange(value);
+		else if (attributeName === Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE)
+			this._bundleSymbolicName = value;
+		else if (attributeName === Constants.BUNDLE_VERSION_ATTRIBUTE)
+			this._bundleVersionRange = VersionRange.parseVersionRange(value);
+		this._attributes[attributeName] = value;
+	},
+	_parseDirective : function(token) {
+		var index = token.indexOf(Constants.DIRECTIVE_EQUALS);
+		var directiveName = token.substring(0, index).replace(/^\s+|\s+$/g, '');
+		if (directiveName.length === 0)
+			return;
+
+		var value = token.substring(index + Constants.DIRECTIVE_EQUALS.length).replace(/^\s+|\s+$/g, '');
+		if (directiveName === Constants.RESOLUTION_DIRECTIVE && value === Constants.RESOLUTION_OPTIONAL)
+			this._optional = true;
+		this._directives[directiveName] = value;
+	},
+	getName : function() {
+		return this._name;
+	},
+	getVersionRange : function() {
+		return this._versionRange;
+	},
+	getBundleSymbolicName : function() {
+		return this._bundleSymbolicName;
+	},
+	getBundleVersionRange : function() {
+		return this._bundleVersionRange;
+	},
+	isOptional : function() {
+		return this._optional;
+	},
+	getAttributes : function() {
+		this._attributes;
+	},
+	getDirectives : function() {
+		return this._directives;
+	},
+	wire : function(candidate) {
+		if (this._name !== candidate.getName())
+			return false;
+
+		if (!this._checkAttributes(candidate))
+			return false;
+
+		if (!this._checkMandatory(candidate))
+			return false;
+
+		this._wiredExport = candidate;
+		return true;
+	},
+	_checkAttributes : function(candidate) {
+		for ( var key in this._attributes) {
+			if (key === Constants.VERSION_ATTRIBUTE) {
+				if (!this._versionRange.isIncluded(candidate.getVersion()))
+					return false;
+			} else if (key === Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE) {
+				if (!this._bundleSymbolicName === candidate.getBundleSymbolicName())
+					return false;
+			} else if (key === Constants.BUNDLE_VERSION_ATTRIBUTE) {
+				if (!this._bundleVersionRange.isIncluded(candidate.getBundleVersion()))
+					return false;
+			} else {
+				var value = this._attributes[key];
+				var attributeValue = candidate.getAttributes()[key];
+				if (attributeValue !== value)
+					return false;
+			}
+		}
+		return true;
+	},
+	_checkMandatory : function(candidate) {
+		for ( var i = 0; i < candidate.getMandatory().length; i++) {
+			var key = candidate.getMandatory()[i];
+			var mandatoryValue = candidate.getAttributes()[key];
+			var value = this._attributes[key];
+			if (value !== mandatoryValue)
+				return false;
+		}
+		return true;
+	},
+	getWiredExport : function() {
+		return this._wiredExport;
+	},
+	unwire : function() {
+		this._wiredExport = null;
+	}
+};
diff --git a/bundles/org.eclipse.e4.languages.javascript.framework/scripts/_Require.js b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/_Require.js
new file mode 100644
index 0000000..3663ee3
--- /dev/null
+++ b/bundles/org.eclipse.e4.languages.javascript.framework/scripts/_Require.js
@@ -0,0 +1,93 @@
+function _Require(header) {
+	if (header === null)
+		throw "header cannot be null";
+
+	this._name = null;
+	this._attributes = {};
+	this._directives = {};
+	this._optional = false;
+	this._bundleVersionRange = VersionRange.emptyRange;
+	this._wiredBundle = null;
+
+	this._parseRequire(header);
+}
+
+_Require.prototype = {
+	_parseRequire : function(header) {
+		var tokens = header.split(Constants.PARAMETER_DELIMITER);
+		this._name = tokens[0].replace(/^\s+|\s+$/g, '');
+		for ( var i = 1; i < tokens.length; i++) {
+			var token = tokens[i];
+			if (token.indexOf(Constants.DIRECTIVE_EQUALS) !== -1)
+				this._parseDirective(token);
+			else if (token.indexOf(Constants.ATTRIBUTE_EQUALS) !== -1)
+				this._parseAttribute(token);
+			else
+				throw "bad import syntax: " + token + " in " + header;
+		}
+	},
+	_parseAttribute : function(token) {
+		var index = token.indexOf(Constants.ATTRIBUTE_EQUALS);
+		var attributeName = token.substring(0, index).replace(/^\s+|\s+$/g, '');
+		if (attributeName.length === 0)
+			return;
+
+		var value = token.substring(index + Constants.ATTRIBUTE_EQUALS.length).replace(/^\s+|\s+$/g, '');
+
+		if (attributeName === Constants.BUNDLE_VERSION_ATTRIBUTE)
+			this._bundleVersionRange = VersionRange.parseVersionRange(value);
+
+		this._attributes[attributeName] = value;
+	},
+	_parseDirective : function(token) {
+		var index = token.indexOf(Constants.DIRECTIVE_EQUALS);
+		var directiveName = token.substring(0, index).replace(/^\s+|\s+$/g, '');
+		if (directiveName.length === 0)
+			return;
+
+		var value = token.substring(index + Constants.DIRECTIVE_EQUALS.length).replace(/^\s+|\s+$/g, '');
+		if (directiveName === Constants.RESOLUTION_DIRECTIVE && value === Constants.RESOLUTION_OPTIONAL)
+			this._optional = true;
+		this._directives[directiveName] = value;
+	},
+	getName : function() {
+		return this._name;
+	},
+	getBundleVersionRange : function() {
+		return this._bundleVersionRange;
+	},
+	isOptional : function() {
+		return this._optional;
+	},
+	getAttributes : function() {
+		this._attributes;
+	},
+	getDirectives : function() {
+		return this._directives;
+	},
+	wire : function(candidate) {
+		if (this._name !== candidate.getName())
+			return false;
+
+		if (!this._checkAttributes(candidate))
+			return false;
+
+		this._wiredBundle = candidate;
+		return true;
+	},
+	_checkAttributes : function(candidate) {
+		for ( var key in this._attributes) {
+			if (key === Constants.BUNDLE_VERSION_ATTRIBUTE) {
+				if (!this._bundleVersionRange.isIncluded(candidate.getVersion()))
+					return false;
+			}
+		}
+		return true;
+	},
+	getWiredBundle : function() {
+		return this._wiredBundle;
+	},
+	unwire : function() {
+		this._wiredBundle = null;
+	}
+};