| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347 | 
							- /*
 
- 	MIT License http://www.opensource.org/licenses/mit-license.php
 
- 	Author Tobias Koppers @sokra
 
- */
 
- "use strict";
 
- const util = require("util");
 
- const Tapable = require("tapable/lib/Tapable");
 
- const SyncHook = require("tapable/lib/SyncHook");
 
- const AsyncSeriesBailHook = require("tapable/lib/AsyncSeriesBailHook");
 
- const AsyncSeriesHook = require("tapable/lib/AsyncSeriesHook");
 
- const createInnerContext = require("./createInnerContext");
 
- const REGEXP_NOT_MODULE = /^\.$|^\.[\\/]|^\.\.$|^\.\.[\\/]|^\/|^[A-Z]:[\\/]/i;
 
- const REGEXP_DIRECTORY = /[\\/]$/i;
 
- const memoryFsJoin = require("memory-fs/lib/join");
 
- const memoizedJoin = new Map();
 
- const memoryFsNormalize = require("memory-fs/lib/normalize");
 
- function withName(name, hook) {
 
- 	hook.name = name;
 
- 	return hook;
 
- }
 
- function toCamelCase(str) {
 
- 	return str.replace(/-([a-z])/g, str => str.substr(1).toUpperCase());
 
- }
 
- const deprecatedPushToMissing = util.deprecate((set, item) => {
 
- 	set.add(item);
 
- }, "Resolver: 'missing' is now a Set. Use add instead of push.");
 
- const deprecatedResolveContextInCallback = util.deprecate(x => {
 
- 	return x;
 
- }, "Resolver: The callback argument was splitted into resolveContext and callback.");
 
- const deprecatedHookAsString = util.deprecate(x => {
 
- 	return x;
 
- }, "Resolver#doResolve: The type arguments (string) is now a hook argument (Hook). Pass a reference to the hook instead.");
 
- class Resolver extends Tapable {
 
- 	constructor(fileSystem) {
 
- 		super();
 
- 		this.fileSystem = fileSystem;
 
- 		this.hooks = {
 
- 			resolveStep: withName("resolveStep", new SyncHook(["hook", "request"])),
 
- 			noResolve: withName("noResolve", new SyncHook(["request", "error"])),
 
- 			resolve: withName(
 
- 				"resolve",
 
- 				new AsyncSeriesBailHook(["request", "resolveContext"])
 
- 			),
 
- 			result: new AsyncSeriesHook(["result", "resolveContext"])
 
- 		};
 
- 		this._pluginCompat.tap("Resolver: before/after", options => {
 
- 			if (/^before-/.test(options.name)) {
 
- 				options.name = options.name.substr(7);
 
- 				options.stage = -10;
 
- 			} else if (/^after-/.test(options.name)) {
 
- 				options.name = options.name.substr(6);
 
- 				options.stage = 10;
 
- 			}
 
- 		});
 
- 		this._pluginCompat.tap("Resolver: step hooks", options => {
 
- 			const name = options.name;
 
- 			const stepHook = !/^resolve(-s|S)tep$|^no(-r|R)esolve$/.test(name);
 
- 			if (stepHook) {
 
- 				options.async = true;
 
- 				this.ensureHook(name);
 
- 				const fn = options.fn;
 
- 				options.fn = (request, resolverContext, callback) => {
 
- 					const innerCallback = (err, result) => {
 
- 						if (err) return callback(err);
 
- 						if (result !== undefined) return callback(null, result);
 
- 						callback();
 
- 					};
 
- 					for (const key in resolverContext) {
 
- 						innerCallback[key] = resolverContext[key];
 
- 					}
 
- 					fn.call(this, request, innerCallback);
 
- 				};
 
- 			}
 
- 		});
 
- 	}
 
- 	ensureHook(name) {
 
- 		if (typeof name !== "string") return name;
 
- 		name = toCamelCase(name);
 
- 		if (/^before/.test(name)) {
 
- 			return this.ensureHook(
 
- 				name[6].toLowerCase() + name.substr(7)
 
- 			).withOptions({
 
- 				stage: -10
 
- 			});
 
- 		}
 
- 		if (/^after/.test(name)) {
 
- 			return this.ensureHook(
 
- 				name[5].toLowerCase() + name.substr(6)
 
- 			).withOptions({
 
- 				stage: 10
 
- 			});
 
- 		}
 
- 		const hook = this.hooks[name];
 
- 		if (!hook) {
 
- 			return (this.hooks[name] = withName(
 
- 				name,
 
- 				new AsyncSeriesBailHook(["request", "resolveContext"])
 
- 			));
 
- 		}
 
- 		return hook;
 
- 	}
 
- 	getHook(name) {
 
- 		if (typeof name !== "string") return name;
 
- 		name = toCamelCase(name);
 
- 		if (/^before/.test(name)) {
 
- 			return this.getHook(name[6].toLowerCase() + name.substr(7)).withOptions({
 
- 				stage: -10
 
- 			});
 
- 		}
 
- 		if (/^after/.test(name)) {
 
- 			return this.getHook(name[5].toLowerCase() + name.substr(6)).withOptions({
 
- 				stage: 10
 
- 			});
 
- 		}
 
- 		const hook = this.hooks[name];
 
- 		if (!hook) {
 
- 			throw new Error(`Hook ${name} doesn't exist`);
 
- 		}
 
- 		return hook;
 
- 	}
 
- 	resolveSync(context, path, request) {
 
- 		let err,
 
- 			result,
 
- 			sync = false;
 
- 		this.resolve(context, path, request, {}, (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;
 
- 	}
 
- 	resolve(context, path, request, resolveContext, callback) {
 
- 		// TODO remove in enhanced-resolve 5
 
- 		// For backward compatiblity START
 
- 		if (typeof callback !== "function") {
 
- 			callback = deprecatedResolveContextInCallback(resolveContext);
 
- 			// resolveContext is a function containing additional properties
 
- 			// It's now used for resolveContext and callback
 
- 		}
 
- 		// END
 
- 		const obj = {
 
- 			context: context,
 
- 			path: path,
 
- 			request: request
 
- 		};
 
- 		const message = "resolve '" + request + "' in '" + path + "'";
 
- 		// Try to resolve assuming there is no error
 
- 		// We don't log stuff in this case
 
- 		return this.doResolve(
 
- 			this.hooks.resolve,
 
- 			obj,
 
- 			message,
 
- 			{
 
- 				missing: resolveContext.missing,
 
- 				stack: resolveContext.stack
 
- 			},
 
- 			(err, result) => {
 
- 				if (!err && result) {
 
- 					return callback(
 
- 						null,
 
- 						result.path === false ? false : result.path + (result.query || ""),
 
- 						result
 
- 					);
 
- 				}
 
- 				const localMissing = new Set();
 
- 				// TODO remove in enhanced-resolve 5
 
- 				localMissing.push = item => deprecatedPushToMissing(localMissing, item);
 
- 				const log = [];
 
- 				return this.doResolve(
 
- 					this.hooks.resolve,
 
- 					obj,
 
- 					message,
 
- 					{
 
- 						log: msg => {
 
- 							if (resolveContext.log) {
 
- 								resolveContext.log(msg);
 
- 							}
 
- 							log.push(msg);
 
- 						},
 
- 						missing: localMissing,
 
- 						stack: resolveContext.stack
 
- 					},
 
- 					(err, result) => {
 
- 						if (err) return callback(err);
 
- 						const error = new Error("Can't " + message);
 
- 						error.details = log.join("\n");
 
- 						error.missing = Array.from(localMissing);
 
- 						this.hooks.noResolve.call(obj, error);
 
- 						return callback(error);
 
- 					}
 
- 				);
 
- 			}
 
- 		);
 
- 	}
 
- 	doResolve(hook, request, message, resolveContext, callback) {
 
- 		// TODO remove in enhanced-resolve 5
 
- 		// For backward compatiblity START
 
- 		if (typeof callback !== "function") {
 
- 			callback = deprecatedResolveContextInCallback(resolveContext);
 
- 			// resolveContext is a function containing additional properties
 
- 			// It's now used for resolveContext and callback
 
- 		}
 
- 		if (typeof hook === "string") {
 
- 			const name = toCamelCase(hook);
 
- 			hook = deprecatedHookAsString(this.hooks[name]);
 
- 			if (!hook) {
 
- 				throw new Error(`Hook "${name}" doesn't exist`);
 
- 			}
 
- 		}
 
- 		// END
 
- 		if (typeof callback !== "function")
 
- 			throw new Error("callback is not a function " + Array.from(arguments));
 
- 		if (!resolveContext)
 
- 			throw new Error(
 
- 				"resolveContext is not an object " + Array.from(arguments)
 
- 			);
 
- 		const stackLine =
 
- 			hook.name +
 
- 			": (" +
 
- 			request.path +
 
- 			") " +
 
- 			(request.request || "") +
 
- 			(request.query || "") +
 
- 			(request.directory ? " directory" : "") +
 
- 			(request.module ? " module" : "");
 
- 		let newStack;
 
- 		if (resolveContext.stack) {
 
- 			newStack = new Set(resolveContext.stack);
 
- 			if (resolveContext.stack.has(stackLine)) {
 
- 				// Prevent recursion
 
- 				const recursionError = new Error(
 
- 					"Recursion in resolving\nStack:\n  " +
 
- 						Array.from(newStack).join("\n  ")
 
- 				);
 
- 				recursionError.recursion = true;
 
- 				if (resolveContext.log)
 
- 					resolveContext.log("abort resolving because of recursion");
 
- 				return callback(recursionError);
 
- 			}
 
- 			newStack.add(stackLine);
 
- 		} else {
 
- 			newStack = new Set([stackLine]);
 
- 		}
 
- 		this.hooks.resolveStep.call(hook, request);
 
- 		if (hook.isUsed()) {
 
- 			const innerContext = createInnerContext(
 
- 				{
 
- 					log: resolveContext.log,
 
- 					missing: resolveContext.missing,
 
- 					stack: newStack
 
- 				},
 
- 				message
 
- 			);
 
- 			return hook.callAsync(request, innerContext, (err, result) => {
 
- 				if (err) return callback(err);
 
- 				if (result) return callback(null, result);
 
- 				callback();
 
- 			});
 
- 		} else {
 
- 			callback();
 
- 		}
 
- 	}
 
- 	parse(identifier) {
 
- 		if (identifier === "") return null;
 
- 		const part = {
 
- 			request: "",
 
- 			query: "",
 
- 			module: false,
 
- 			directory: false,
 
- 			file: false
 
- 		};
 
- 		const 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;
 
- 	}
 
- 	isModule(path) {
 
- 		return !REGEXP_NOT_MODULE.test(path);
 
- 	}
 
- 	isDirectory(path) {
 
- 		return REGEXP_DIRECTORY.test(path);
 
- 	}
 
- 	join(path, request) {
 
- 		let cacheEntry;
 
- 		let 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;
 
- 	}
 
- 	normalize(path) {
 
- 		return memoryFsNormalize(path);
 
- 	}
 
- }
 
- module.exports = Resolver;
 
 
  |