| 
									
										
										
										
											2012-03-12 04:50:55 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Tobias Koppers @sokra | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											2012-03-10 20:11:23 +08:00
										 |  |  | var path = require("path"); | 
					
						
							|  |  |  | var fs = require("fs"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // http://nodejs.org/docs/v0.4.8/api/all.html#all_Together...
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-27 06:00:32 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | function resolve(context, identifier, options, type, callback) { | 
					
						
							| 
									
										
										
										
											2012-03-10 20:11:23 +08:00
										 |  |  | 	function finalResult(err, absoluteFilename) { | 
					
						
							|  |  |  | 		if(err) { | 
					
						
							| 
									
										
										
										
											2012-03-13 01:12:35 +08:00
										 |  |  | 			callback("Module \"" + identifier + "\" not found in context \"" + | 
					
						
							| 
									
										
										
										
											2012-03-20 02:59:38 +08:00
										 |  |  | 						context + "\"\n  " + err); | 
					
						
							| 
									
										
										
										
											2012-03-10 20:11:23 +08:00
										 |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		callback(null, absoluteFilename); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-03-15 21:38:55 +08:00
										 |  |  | 	var identArray = split(identifier); | 
					
						
							| 
									
										
										
										
											2012-03-10 20:11:23 +08:00
										 |  |  | 	var contextArray = split(context); | 
					
						
							| 
									
										
										
										
											2012-03-16 20:59:19 +08:00
										 |  |  | 	while(options.alias[identArray[0]]) { | 
					
						
							|  |  |  | 		var old = identArray[0]; | 
					
						
							|  |  |  | 		identArray[0] = options.alias[identArray[0]]; | 
					
						
							|  |  |  | 		identArray = split(path.join.apply(path, identArray)); | 
					
						
							|  |  |  | 		if(identArray[0] === old) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-03-15 21:38:55 +08:00
										 |  |  | 	if(identArray[0] === "." || identArray[0] === ".." || identArray[0] === "" || identArray[0].match(/^[A-Z]:$/i)) { | 
					
						
							|  |  |  | 		var pathname = identArray[0][0] === "." ? join(contextArray, identArray) : path.join.apply(path, identArray); | 
					
						
							| 
									
										
										
										
											2012-04-03 22:26:08 +08:00
										 |  |  | 		if(type === "context") { | 
					
						
							|  |  |  | 			fs.stat(pathname, function(err, stat) { | 
					
						
							|  |  |  | 				if(err) { | 
					
						
							|  |  |  | 					finalResult(err); | 
					
						
							|  |  |  | 					return; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if(!stat.isDirectory()) { | 
					
						
							|  |  |  | 					finalResult("Context \"" + identifier + "\" in not a directory"); | 
					
						
							|  |  |  | 					return; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				callback(null, pathname); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			loadAsFile(pathname, options, type, function(err, absoluteFilename) { | 
					
						
							|  |  |  | 				if(err) { | 
					
						
							|  |  |  | 					loadAsDirectory(pathname, options, type, finalResult); | 
					
						
							|  |  |  | 					return; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				callback(null, absoluteFilename); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-03-10 20:11:23 +08:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2012-03-27 06:00:32 +08:00
										 |  |  | 		loadNodeModules(contextArray, identArray, options, type, finalResult); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-03 22:26:08 +08:00
										 |  |  | function doResolve(context, identifier, options, type, callback) { | 
					
						
							| 
									
										
										
										
											2012-03-27 06:00:32 +08:00
										 |  |  | 	if(!callback) { | 
					
						
							|  |  |  | 		callback = options; | 
					
						
							|  |  |  | 		options = {}; | 
					
						
							| 
									
										
										
										
											2012-03-10 20:11:23 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-03-27 06:00:32 +08:00
										 |  |  | 	if(!options) | 
					
						
							|  |  |  | 		options = {}; | 
					
						
							|  |  |  | 	if(!options.extensions) | 
					
						
							|  |  |  | 		options.extensions = ["", ".webpack.js", ".web.js", ".js"]; | 
					
						
							|  |  |  | 	if(!options.loaders) | 
					
						
							|  |  |  | 		options.loaders = []; | 
					
						
							|  |  |  | 	if(!options.postfixes) | 
					
						
							|  |  |  | 		options.postfixes = ["", "-webpack", "-web"]; | 
					
						
							|  |  |  | 	if(!options.loaderExtensions) | 
					
						
							| 
									
										
										
										
											2012-03-27 06:34:53 +08:00
										 |  |  | 		options.loaderExtensions = [".webpack-web-loader.js", ".webpack-loader.js", ".web-loader.js", ".loader.js", "", ".js"]; | 
					
						
							| 
									
										
										
										
											2012-03-27 06:00:32 +08:00
										 |  |  | 	if(!options.loaderPostfixes) | 
					
						
							|  |  |  | 		options.loaderPostfixes = ["-webpack-web-loader", "-webpack-loader", "-web-loader", "-loader", ""]; | 
					
						
							|  |  |  | 	if(!options.paths) | 
					
						
							|  |  |  | 		options.paths = []; | 
					
						
							|  |  |  | 	if(!options.alias) | 
					
						
							|  |  |  | 		options.alias = {}; | 
					
						
							| 
									
										
										
										
											2012-04-07 09:20:45 +08:00
										 |  |  | 	var identifiers = identifier.replace(/^!|!$/g, "").replace(/!!/g, "!").split(/!/g); | 
					
						
							|  |  |  | 	if(identifier.indexOf("!") === -1) { | 
					
						
							| 
									
										
										
										
											2012-03-27 06:00:32 +08:00
										 |  |  | 		var resource = identifiers.pop(); | 
					
						
							|  |  |  | 		for(var i = 0; i < options.loaders.length; i++) { | 
					
						
							|  |  |  | 			var line = options.loaders[i]; | 
					
						
							|  |  |  | 			if(line.test.test(resource)) { | 
					
						
							| 
									
										
										
										
											2012-04-07 09:20:45 +08:00
										 |  |  | 				Array.prototype.push.apply(identifiers, line.loader.split(/!/g)); | 
					
						
							| 
									
										
										
										
											2012-03-27 06:00:32 +08:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		identifiers.push(resource); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	var errors = []; | 
					
						
							|  |  |  | 	var count = identifiers.length; | 
					
						
							|  |  |  | 	function endOne() { | 
					
						
							|  |  |  | 		count--; | 
					
						
							|  |  |  | 		if(count === 0) { | 
					
						
							|  |  |  | 			if(errors.length > 0) { | 
					
						
							|  |  |  | 				callback(errors.join("\n")); | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			callback(null, identifiers.join("!")); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	identifiers.forEach(function(ident, index) { | 
					
						
							| 
									
										
										
										
											2012-04-03 22:26:08 +08:00
										 |  |  | 		resolve(context, ident, options, index === identifiers.length - 1 ? type : "loader", function(err, filename) { | 
					
						
							| 
									
										
										
										
											2012-03-27 06:00:32 +08:00
										 |  |  | 			if(err) { | 
					
						
							|  |  |  | 				errors.push(err); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				if(!filename) { | 
					
						
							|  |  |  | 					throw new Error(JSON.stringify({identifiers: identifiers, from: ident, to: filename})); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				identifiers[index] = filename; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			endOne() | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2012-03-10 20:11:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-03 22:26:08 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * context: absolute filename of current file | 
					
						
							|  |  |  |  * identifier: module to find | 
					
						
							|  |  |  |  * options: | 
					
						
							|  |  |  |  *   paths: array of lookup paths | 
					
						
							|  |  |  |  * callback: function(err, absoluteFilename) | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | module.exports = function(context, identifier, options, callback) { | 
					
						
							|  |  |  | 	return doResolve(context, identifier, options, "normal", callback); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-12 04:37:18 +08:00
										 |  |  | module.exports.context = function(context, identifier, options, callback) { | 
					
						
							| 
									
										
										
										
											2012-04-03 22:26:08 +08:00
										 |  |  | 	return doResolve(context, identifier, options, "context", callback); | 
					
						
							| 
									
										
										
										
											2012-03-12 04:37:18 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-03 22:26:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-10 20:11:23 +08:00
										 |  |  | function split(a) { | 
					
						
							|  |  |  | 	return a.split(/[\/\\]/g); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function join(a, b) { | 
					
						
							|  |  |  | 	var c = []; | 
					
						
							|  |  |  | 	a.forEach(function(x) { c.push(x) }); | 
					
						
							|  |  |  | 	b.forEach(function(x) { c.push(x) }); | 
					
						
							| 
									
										
										
										
											2012-03-13 01:12:35 +08:00
										 |  |  | 	if(c[0] === "") | 
					
						
							|  |  |  | 		c[0] = "/"; | 
					
						
							| 
									
										
										
										
											2012-03-10 20:11:23 +08:00
										 |  |  | 	return path.join.apply(path, c); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-27 06:00:32 +08:00
										 |  |  | function loadAsFile(filename, options, type, callback) { | 
					
						
							|  |  |  | 	var pos = -1, result = "NOT SET"; | 
					
						
							|  |  |  | 	var extensions = type === "loader" ? options.loaderExtensions : options.extensions; | 
					
						
							| 
									
										
										
										
											2012-03-10 20:11:23 +08:00
										 |  |  | 	function tryCb(err, stats) { | 
					
						
							|  |  |  | 		if(err || !stats || !stats.isFile()) { | 
					
						
							|  |  |  | 			pos++; | 
					
						
							| 
									
										
										
										
											2012-03-27 06:00:32 +08:00
										 |  |  | 			if(pos >= extensions.length) { | 
					
						
							|  |  |  | 				callback(err || "Isn't a file"); | 
					
						
							| 
									
										
										
										
											2012-03-10 20:11:23 +08:00
										 |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2012-03-27 06:00:32 +08:00
										 |  |  | 			fs.stat(result = filename + extensions[pos], tryCb); | 
					
						
							| 
									
										
										
										
											2012-03-10 20:11:23 +08:00
										 |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-03-27 06:00:32 +08:00
										 |  |  | 		if(!result) throw new Error("no result"); | 
					
						
							| 
									
										
										
										
											2012-03-10 20:11:23 +08:00
										 |  |  | 		callback(null, result); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-03-27 06:00:32 +08:00
										 |  |  | 	tryCb(true); | 
					
						
							| 
									
										
										
										
											2012-03-10 20:11:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-27 06:00:32 +08:00
										 |  |  | function loadAsDirectory(dirname, options, type, callback) { | 
					
						
							| 
									
										
										
										
											2012-03-10 20:11:23 +08:00
										 |  |  | 	var packageJsonFile = join(split(dirname), ["package.json"]); | 
					
						
							|  |  |  | 	fs.stat(packageJsonFile, function(err, stats) { | 
					
						
							|  |  |  | 		var mainModule = "index"; | 
					
						
							|  |  |  | 		if(!err && stats.isFile()) { | 
					
						
							|  |  |  | 			fs.readFile(packageJsonFile, "utf-8", function(err, content) { | 
					
						
							| 
									
										
										
										
											2012-03-27 06:00:32 +08:00
										 |  |  | 				if(err) { | 
					
						
							|  |  |  | 					callback(err); | 
					
						
							|  |  |  | 					return; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2012-03-10 20:11:23 +08:00
										 |  |  | 				content = JSON.parse(content); | 
					
						
							| 
									
										
										
										
											2012-03-27 06:00:32 +08:00
										 |  |  | 				if(content.webpackLoader && type === "loader") | 
					
						
							|  |  |  | 					mainModule = content.webpackLoader; | 
					
						
							|  |  |  | 				else if(content.webpack) | 
					
						
							|  |  |  | 					mainModule = content.webpack; | 
					
						
							|  |  |  | 				else if(content.browserify) | 
					
						
							|  |  |  | 					mainModule = content.browserify; | 
					
						
							|  |  |  | 				else if(content.main) | 
					
						
							| 
									
										
										
										
											2012-03-10 20:11:23 +08:00
										 |  |  | 					mainModule = content.main; | 
					
						
							| 
									
										
										
										
											2012-03-27 06:00:32 +08:00
										 |  |  | 				loadAsFile(join(split(dirname), [mainModule]), options, type, callback); | 
					
						
							| 
									
										
										
										
											2012-03-10 20:11:23 +08:00
										 |  |  | 			}); | 
					
						
							|  |  |  | 		} else | 
					
						
							| 
									
										
										
										
											2012-03-27 06:00:32 +08:00
										 |  |  | 			loadAsFile(join(split(dirname), [mainModule]), options, type, callback); | 
					
						
							| 
									
										
										
										
											2012-03-10 20:11:23 +08:00
										 |  |  | 	}); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-27 06:00:32 +08:00
										 |  |  | function loadNodeModules(context, identifier, options, type, callback) { | 
					
						
							|  |  |  | 	var moduleName = identifier.shift(); | 
					
						
							|  |  |  | 	var postfixes = type === "loader" ? options.loaderPostfixes : options.postfixes; | 
					
						
							|  |  |  | 	nodeModulesPaths(context, options, function(err, paths) { | 
					
						
							|  |  |  | 		var dirs = []; | 
					
						
							|  |  |  | 		paths.forEach(function(path) { | 
					
						
							|  |  |  | 			postfixes.forEach(function(postfix) { | 
					
						
							|  |  |  | 				dirs.push(join(split(path), [moduleName+postfix])); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2012-03-10 20:11:23 +08:00
										 |  |  | 		function tryDir(dir) { | 
					
						
							|  |  |  | 			var pathname = join(split(dir), identifier); | 
					
						
							| 
									
										
										
										
											2012-04-03 22:26:08 +08:00
										 |  |  | 			if(type === "context") { | 
					
						
							|  |  |  | 				fs.stat(pathname, function(err, stat) { | 
					
						
							|  |  |  | 					if(err || !stat.isDirectory()) { | 
					
						
							|  |  |  | 						if(dirs.length === 0) { | 
					
						
							|  |  |  | 							callback("no directory in any path of paths"); | 
					
						
							| 
									
										
										
										
											2012-03-10 20:11:23 +08:00
										 |  |  | 							return; | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2012-04-03 22:26:08 +08:00
										 |  |  | 						tryDir(dirs.shift()); | 
					
						
							| 
									
										
										
										
											2012-03-12 04:37:18 +08:00
										 |  |  | 						return; | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2012-04-03 22:26:08 +08:00
										 |  |  | 					callback(null, pathname); | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				loadAsFile(pathname, options, type, function(err, absoluteFilename) { | 
					
						
							|  |  |  | 					if(err) { | 
					
						
							|  |  |  | 						loadAsDirectory(pathname, options, type, function(err, absoluteFilename) { | 
					
						
							|  |  |  | 							if(err) { | 
					
						
							|  |  |  | 								if(dirs.length === 0) { | 
					
						
							|  |  |  | 									callback("no module in any path of paths"); | 
					
						
							|  |  |  | 									return; | 
					
						
							|  |  |  | 								} | 
					
						
							|  |  |  | 								tryDir(dirs.shift()); | 
					
						
							|  |  |  | 								return; | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 							callback(null, absoluteFilename); | 
					
						
							|  |  |  | 						}); | 
					
						
							|  |  |  | 						return; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					callback(null, absoluteFilename); | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2012-03-12 04:37:18 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		tryDir(dirs.shift()); | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-10 20:11:23 +08:00
										 |  |  | function nodeModulesPaths(context, options, callback) { | 
					
						
							|  |  |  | 	var parts = context; | 
					
						
							|  |  |  | 	var rootNodeModules = parts.indexOf("node_modules"); | 
					
						
							|  |  |  | 	var rootWebModules = parts.indexOf("web_modules"); | 
					
						
							|  |  |  | 	var root = 0; | 
					
						
							|  |  |  | 	if(rootWebModules != -1 && rootNodeModules != -1) | 
					
						
							|  |  |  | 		root = Math.min(rootWebModules, rootNodeModules)-1; | 
					
						
							|  |  |  | 	else if(rootWebModules != -1 || rootNodeModules != -1) | 
					
						
							|  |  |  | 		root = Math.max(rootWebModules, rootNodeModules)-1; | 
					
						
							|  |  |  | 	var dirs = []; | 
					
						
							|  |  |  | 	options.paths.forEach(function(path) { dirs.push(path) }); | 
					
						
							|  |  |  | 	for(var i = parts.length; i > root; i--) { | 
					
						
							|  |  |  | 		if(parts[i-1] === "node_modules" || parts[i-1] === "web_modules") | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		var part = parts.slice(0, i); | 
					
						
							|  |  |  | 		dirs.push(join(part, ["web_modules"])); | 
					
						
							|  |  |  | 		dirs.push(join(part, ["node_modules"])); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	callback(null, dirs); | 
					
						
							|  |  |  | } |