/* MIT License http://www.opensource.org/licenses/mit-license.php Author Tobias Koppers @sokra */ var Tapable = require("tapable"); var createInnerCallback = require("./createInnerCallback"); function Resolver(fileSystem) { Tapable.call(this); this.fileSystem = fileSystem; } module.exports = Resolver; Resolver.prototype = Object.create(Tapable.prototype); Resolver.prototype.constructor = Resolver; Resolver.prototype.resolveSync = function resolveSync(context, path, request) { var err, result, sync = false; this.resolve(context, path, request, function(e, r) { err = e; result = r; sync = true; }); if(!sync) throw new Error("Cannot 'resolveSync' because the fileSystem is not sync. Use 'resolve'!"); if(err) throw err; return result; }; Resolver.prototype.resolve = function resolve(context, path, request, callback) { if(arguments.length === 3) { throw new Error("Signature changed: context parameter added"); } var resolver = this; var obj = { context: context, path: path, request: request }; var localMissing; var log; var message = "resolve '" + request + "' in '" + path + "'"; function writeLog(msg) { log.push(msg); } function logAsString() { return log.join("\n"); } function onError(err, result) { if(callback.log) { for(var i = 0; i < log.length; i++) callback.log(log[i]); } if(err) return callback(err); var error = new Error("Can't " + message); error.details = logAsString(); error.missing = localMissing; resolver.applyPlugins("no-resolve", obj, error); return callback(error); } function onResolve(err, result) { if(!err && result) { return callback(null, result.path === false ? false : result.path + (result.query || ""), result); } localMissing = []; log = []; return resolver.doResolve("resolve", obj, message, createInnerCallback(onError, { log: writeLog, missing: localMissing, stack: callback.stack })); } onResolve.missing = callback.missing; onResolve.stack = callback.stack; return this.doResolve("resolve", obj, message, onResolve); }; Resolver.prototype.doResolve = function doResolve(type, request, message, callback) { var resolver = this; var stackLine = type + ": (" + request.path + ") " + (request.request || "") + (request.query || "") + (request.directory ? " directory" : "") + (request.module ? " module" : ""); var newStack = [stackLine]; if(callback.stack) { newStack = callback.stack.concat(newStack); if(callback.stack.indexOf(stackLine) >= 0) { // Prevent recursion var recursionError = new Error("Recursion in resolving\nStack:\n " + newStack.join("\n ")); recursionError.recursion = true; if(callback.log) callback.log("abort resolving because of recursion"); return callback(recursionError); } } resolver.applyPlugins("resolve-step", type, request); var beforePluginName = "before-" + type; if(resolver.hasPlugins(beforePluginName)) { resolver.applyPluginsAsyncSeriesBailResult1(beforePluginName, request, createInnerCallback(beforeInnerCallback, { log: callback.log, missing: callback.missing, stack: newStack }, message && ("before " + message), true)); } else { runNormal(); } function beforeInnerCallback(err, result) { if(arguments.length > 0) { if(err) return callback(err); if(result) return callback(null, result); return callback(); } runNormal(); } function runNormal() { if(resolver.hasPlugins(type)) { return resolver.applyPluginsAsyncSeriesBailResult1(type, request, createInnerCallback(innerCallback, { log: callback.log, missing: callback.missing, stack: newStack }, message)); } else { runAfter(); } } function innerCallback(err, result) { if(arguments.length > 0) { if(err) return callback(err); if(result) return callback(null, result); return callback(); } runAfter(); } function runAfter() { var afterPluginName = "after-" + type; if(resolver.hasPlugins(afterPluginName)) { return resolver.applyPluginsAsyncSeriesBailResult1(afterPluginName, request, createInnerCallback(afterInnerCallback, { log: callback.log, missing: callback.missing, stack: newStack }, message && ("after " + message), true)); } else { callback(); } } function afterInnerCallback(err, result) { if(arguments.length > 0) { if(err) return callback(err); if(result) return callback(null, result); return callback(); } return callback(); } }; Resolver.prototype.parse = function parse(identifier) { if(identifier === "") return null; var part = { request: "", query: "", module: false, directory: false, file: false }; var idxQuery = identifier.indexOf("?"); if(idxQuery === 0) { part.query = identifier; } else if(idxQuery > 0) { part.request = identifier.slice(0, idxQuery); part.query = identifier.slice(idxQuery); } else { part.request = identifier; } if(part.request) { part.module = this.isModule(part.request); part.directory = this.isDirectory(part.request); if(part.directory) { part.request = part.request.substr(0, part.request.length - 1); } } return part; }; var notModuleRegExp = /^\.$|^\.[\\\/]|^\.\.$|^\.\.[\/\\]|^\/|^[A-Z]:[\\\/]/i; Resolver.prototype.isModule = function isModule(path) { return !notModuleRegExp.test(path); }; var directoryRegExp = /[\/\\]$/i; Resolver.prototype.isDirectory = function isDirectory(path) { return directoryRegExp.test(path); }; var memoryFsJoin = require("memory-fs/lib/join"); var memoizedJoin = new Map(); Resolver.prototype.join = function(path, request) { var cacheEntry; var pathCache = memoizedJoin.get(path); if(typeof pathCache === "undefined") { memoizedJoin.set(path, pathCache = new Map()); } else { cacheEntry = pathCache.get(request); if(typeof cacheEntry !== "undefined") return cacheEntry; } cacheEntry = memoryFsJoin(path, request); pathCache.set(request, cacheEntry); return cacheEntry; }; Resolver.prototype.normalize = require("memory-fs/lib/normalize");