| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528 | 
							- /*
 
-  MIT License http://www.opensource.org/licenses/mit-license.php
 
-  Author Tobias Koppers @sokra
 
-  */
 
- "use strict";
 
- const path = require("path");
 
- const asyncLib = require("neo-async");
 
- const {
 
- 	Tapable,
 
- 	AsyncSeriesWaterfallHook,
 
- 	SyncWaterfallHook,
 
- 	SyncBailHook,
 
- 	SyncHook,
 
- 	HookMap
 
- } = require("tapable");
 
- const NormalModule = require("./NormalModule");
 
- const RawModule = require("./RawModule");
 
- const RuleSet = require("./RuleSet");
 
- const { cachedCleverMerge } = require("./util/cleverMerge");
 
- const EMPTY_RESOLVE_OPTIONS = {};
 
- const MATCH_RESOURCE_REGEX = /^([^!]+)!=!/;
 
- const loaderToIdent = data => {
 
- 	if (!data.options) {
 
- 		return data.loader;
 
- 	}
 
- 	if (typeof data.options === "string") {
 
- 		return data.loader + "?" + data.options;
 
- 	}
 
- 	if (typeof data.options !== "object") {
 
- 		throw new Error("loader options must be string or object");
 
- 	}
 
- 	if (data.ident) {
 
- 		return data.loader + "??" + data.ident;
 
- 	}
 
- 	return data.loader + "?" + JSON.stringify(data.options);
 
- };
 
- const identToLoaderRequest = resultString => {
 
- 	const idx = resultString.indexOf("?");
 
- 	if (idx >= 0) {
 
- 		const loader = resultString.substr(0, idx);
 
- 		const options = resultString.substr(idx + 1);
 
- 		return {
 
- 			loader,
 
- 			options
 
- 		};
 
- 	} else {
 
- 		return {
 
- 			loader: resultString,
 
- 			options: undefined
 
- 		};
 
- 	}
 
- };
 
- const dependencyCache = new WeakMap();
 
- class NormalModuleFactory extends Tapable {
 
- 	constructor(context, resolverFactory, options) {
 
- 		super();
 
- 		this.hooks = {
 
- 			resolver: new SyncWaterfallHook(["resolver"]),
 
- 			factory: new SyncWaterfallHook(["factory"]),
 
- 			beforeResolve: new AsyncSeriesWaterfallHook(["data"]),
 
- 			afterResolve: new AsyncSeriesWaterfallHook(["data"]),
 
- 			createModule: new SyncBailHook(["data"]),
 
- 			module: new SyncWaterfallHook(["module", "data"]),
 
- 			createParser: new HookMap(() => new SyncBailHook(["parserOptions"])),
 
- 			parser: new HookMap(() => new SyncHook(["parser", "parserOptions"])),
 
- 			createGenerator: new HookMap(
 
- 				() => new SyncBailHook(["generatorOptions"])
 
- 			),
 
- 			generator: new HookMap(
 
- 				() => new SyncHook(["generator", "generatorOptions"])
 
- 			)
 
- 		};
 
- 		this._pluginCompat.tap("NormalModuleFactory", options => {
 
- 			switch (options.name) {
 
- 				case "before-resolve":
 
- 				case "after-resolve":
 
- 					options.async = true;
 
- 					break;
 
- 				case "parser":
 
- 					this.hooks.parser
 
- 						.for("javascript/auto")
 
- 						.tap(options.fn.name || "unnamed compat plugin", options.fn);
 
- 					return true;
 
- 			}
 
- 			let match;
 
- 			match = /^parser (.+)$/.exec(options.name);
 
- 			if (match) {
 
- 				this.hooks.parser
 
- 					.for(match[1])
 
- 					.tap(
 
- 						options.fn.name || "unnamed compat plugin",
 
- 						options.fn.bind(this)
 
- 					);
 
- 				return true;
 
- 			}
 
- 			match = /^create-parser (.+)$/.exec(options.name);
 
- 			if (match) {
 
- 				this.hooks.createParser
 
- 					.for(match[1])
 
- 					.tap(
 
- 						options.fn.name || "unnamed compat plugin",
 
- 						options.fn.bind(this)
 
- 					);
 
- 				return true;
 
- 			}
 
- 		});
 
- 		this.resolverFactory = resolverFactory;
 
- 		this.ruleSet = new RuleSet(options.defaultRules.concat(options.rules));
 
- 		this.cachePredicate =
 
- 			typeof options.unsafeCache === "function"
 
- 				? options.unsafeCache
 
- 				: Boolean.bind(null, options.unsafeCache);
 
- 		this.context = context || "";
 
- 		this.parserCache = Object.create(null);
 
- 		this.generatorCache = Object.create(null);
 
- 		this.hooks.factory.tap("NormalModuleFactory", () => (result, callback) => {
 
- 			let resolver = this.hooks.resolver.call(null);
 
- 			// Ignored
 
- 			if (!resolver) return callback();
 
- 			resolver(result, (err, data) => {
 
- 				if (err) return callback(err);
 
- 				// Ignored
 
- 				if (!data) return callback();
 
- 				// direct module
 
- 				if (typeof data.source === "function") return callback(null, data);
 
- 				this.hooks.afterResolve.callAsync(data, (err, result) => {
 
- 					if (err) return callback(err);
 
- 					// Ignored
 
- 					if (!result) return callback();
 
- 					let createdModule = this.hooks.createModule.call(result);
 
- 					if (!createdModule) {
 
- 						if (!result.request) {
 
- 							return callback(new Error("Empty dependency (no request)"));
 
- 						}
 
- 						createdModule = new NormalModule(result);
 
- 					}
 
- 					createdModule = this.hooks.module.call(createdModule, result);
 
- 					return callback(null, createdModule);
 
- 				});
 
- 			});
 
- 		});
 
- 		this.hooks.resolver.tap("NormalModuleFactory", () => (data, callback) => {
 
- 			const contextInfo = data.contextInfo;
 
- 			const context = data.context;
 
- 			const request = data.request;
 
- 			const loaderResolver = this.getResolver("loader");
 
- 			const normalResolver = this.getResolver("normal", data.resolveOptions);
 
- 			let matchResource = undefined;
 
- 			let requestWithoutMatchResource = request;
 
- 			const matchResourceMatch = MATCH_RESOURCE_REGEX.exec(request);
 
- 			if (matchResourceMatch) {
 
- 				matchResource = matchResourceMatch[1];
 
- 				if (/^\.\.?\//.test(matchResource)) {
 
- 					matchResource = path.join(context, matchResource);
 
- 				}
 
- 				requestWithoutMatchResource = request.substr(
 
- 					matchResourceMatch[0].length
 
- 				);
 
- 			}
 
- 			const noPreAutoLoaders = requestWithoutMatchResource.startsWith("-!");
 
- 			const noAutoLoaders =
 
- 				noPreAutoLoaders || requestWithoutMatchResource.startsWith("!");
 
- 			const noPrePostAutoLoaders = requestWithoutMatchResource.startsWith("!!");
 
- 			let elements = requestWithoutMatchResource
 
- 				.replace(/^-?!+/, "")
 
- 				.replace(/!!+/g, "!")
 
- 				.split("!");
 
- 			let resource = elements.pop();
 
- 			elements = elements.map(identToLoaderRequest);
 
- 			asyncLib.parallel(
 
- 				[
 
- 					callback =>
 
- 						this.resolveRequestArray(
 
- 							contextInfo,
 
- 							context,
 
- 							elements,
 
- 							loaderResolver,
 
- 							callback
 
- 						),
 
- 					callback => {
 
- 						if (resource === "" || resource[0] === "?") {
 
- 							return callback(null, {
 
- 								resource
 
- 							});
 
- 						}
 
- 						normalResolver.resolve(
 
- 							contextInfo,
 
- 							context,
 
- 							resource,
 
- 							{},
 
- 							(err, resource, resourceResolveData) => {
 
- 								if (err) return callback(err);
 
- 								callback(null, {
 
- 									resourceResolveData,
 
- 									resource
 
- 								});
 
- 							}
 
- 						);
 
- 					}
 
- 				],
 
- 				(err, results) => {
 
- 					if (err) return callback(err);
 
- 					let loaders = results[0];
 
- 					const resourceResolveData = results[1].resourceResolveData;
 
- 					resource = results[1].resource;
 
- 					// translate option idents
 
- 					try {
 
- 						for (const item of loaders) {
 
- 							if (typeof item.options === "string" && item.options[0] === "?") {
 
- 								const ident = item.options.substr(1);
 
- 								item.options = this.ruleSet.findOptionsByIdent(ident);
 
- 								item.ident = ident;
 
- 							}
 
- 						}
 
- 					} catch (e) {
 
- 						return callback(e);
 
- 					}
 
- 					if (resource === false) {
 
- 						// ignored
 
- 						return callback(
 
- 							null,
 
- 							new RawModule(
 
- 								"/* (ignored) */",
 
- 								`ignored ${context} ${request}`,
 
- 								`${request} (ignored)`
 
- 							)
 
- 						);
 
- 					}
 
- 					const userRequest =
 
- 						(matchResource !== undefined ? `${matchResource}!=!` : "") +
 
- 						loaders
 
- 							.map(loaderToIdent)
 
- 							.concat([resource])
 
- 							.join("!");
 
- 					let resourcePath =
 
- 						matchResource !== undefined ? matchResource : resource;
 
- 					let resourceQuery = "";
 
- 					const queryIndex = resourcePath.indexOf("?");
 
- 					if (queryIndex >= 0) {
 
- 						resourceQuery = resourcePath.substr(queryIndex);
 
- 						resourcePath = resourcePath.substr(0, queryIndex);
 
- 					}
 
- 					const result = this.ruleSet.exec({
 
- 						resource: resourcePath,
 
- 						realResource:
 
- 							matchResource !== undefined
 
- 								? resource.replace(/\?.*/, "")
 
- 								: resourcePath,
 
- 						resourceQuery,
 
- 						issuer: contextInfo.issuer,
 
- 						compiler: contextInfo.compiler
 
- 					});
 
- 					const settings = {};
 
- 					const useLoadersPost = [];
 
- 					const useLoaders = [];
 
- 					const useLoadersPre = [];
 
- 					for (const r of result) {
 
- 						if (r.type === "use") {
 
- 							if (r.enforce === "post" && !noPrePostAutoLoaders) {
 
- 								useLoadersPost.push(r.value);
 
- 							} else if (
 
- 								r.enforce === "pre" &&
 
- 								!noPreAutoLoaders &&
 
- 								!noPrePostAutoLoaders
 
- 							) {
 
- 								useLoadersPre.push(r.value);
 
- 							} else if (
 
- 								!r.enforce &&
 
- 								!noAutoLoaders &&
 
- 								!noPrePostAutoLoaders
 
- 							) {
 
- 								useLoaders.push(r.value);
 
- 							}
 
- 						} else if (
 
- 							typeof r.value === "object" &&
 
- 							r.value !== null &&
 
- 							typeof settings[r.type] === "object" &&
 
- 							settings[r.type] !== null
 
- 						) {
 
- 							settings[r.type] = cachedCleverMerge(settings[r.type], r.value);
 
- 						} else {
 
- 							settings[r.type] = r.value;
 
- 						}
 
- 					}
 
- 					asyncLib.parallel(
 
- 						[
 
- 							this.resolveRequestArray.bind(
 
- 								this,
 
- 								contextInfo,
 
- 								this.context,
 
- 								useLoadersPost,
 
- 								loaderResolver
 
- 							),
 
- 							this.resolveRequestArray.bind(
 
- 								this,
 
- 								contextInfo,
 
- 								this.context,
 
- 								useLoaders,
 
- 								loaderResolver
 
- 							),
 
- 							this.resolveRequestArray.bind(
 
- 								this,
 
- 								contextInfo,
 
- 								this.context,
 
- 								useLoadersPre,
 
- 								loaderResolver
 
- 							)
 
- 						],
 
- 						(err, results) => {
 
- 							if (err) return callback(err);
 
- 							if (matchResource === undefined) {
 
- 								loaders = results[0].concat(loaders, results[1], results[2]);
 
- 							} else {
 
- 								loaders = results[0].concat(results[1], loaders, results[2]);
 
- 							}
 
- 							process.nextTick(() => {
 
- 								const type = settings.type;
 
- 								const resolveOptions = settings.resolve;
 
- 								callback(null, {
 
- 									context: context,
 
- 									request: loaders
 
- 										.map(loaderToIdent)
 
- 										.concat([resource])
 
- 										.join("!"),
 
- 									dependencies: data.dependencies,
 
- 									userRequest,
 
- 									rawRequest: request,
 
- 									loaders,
 
- 									resource,
 
- 									matchResource,
 
- 									resourceResolveData,
 
- 									settings,
 
- 									type,
 
- 									parser: this.getParser(type, settings.parser),
 
- 									generator: this.getGenerator(type, settings.generator),
 
- 									resolveOptions
 
- 								});
 
- 							});
 
- 						}
 
- 					);
 
- 				}
 
- 			);
 
- 		});
 
- 	}
 
- 	create(data, callback) {
 
- 		const dependencies = data.dependencies;
 
- 		const cacheEntry = dependencyCache.get(dependencies[0]);
 
- 		if (cacheEntry) return callback(null, cacheEntry);
 
- 		const context = data.context || this.context;
 
- 		const resolveOptions = data.resolveOptions || EMPTY_RESOLVE_OPTIONS;
 
- 		const request = dependencies[0].request;
 
- 		const contextInfo = data.contextInfo || {};
 
- 		this.hooks.beforeResolve.callAsync(
 
- 			{
 
- 				contextInfo,
 
- 				resolveOptions,
 
- 				context,
 
- 				request,
 
- 				dependencies
 
- 			},
 
- 			(err, result) => {
 
- 				if (err) return callback(err);
 
- 				// Ignored
 
- 				if (!result) return callback();
 
- 				const factory = this.hooks.factory.call(null);
 
- 				// Ignored
 
- 				if (!factory) return callback();
 
- 				factory(result, (err, module) => {
 
- 					if (err) return callback(err);
 
- 					if (module && this.cachePredicate(module)) {
 
- 						for (const d of dependencies) {
 
- 							dependencyCache.set(d, module);
 
- 						}
 
- 					}
 
- 					callback(null, module);
 
- 				});
 
- 			}
 
- 		);
 
- 	}
 
- 	resolveRequestArray(contextInfo, context, array, resolver, callback) {
 
- 		if (array.length === 0) return callback(null, []);
 
- 		asyncLib.map(
 
- 			array,
 
- 			(item, callback) => {
 
- 				resolver.resolve(
 
- 					contextInfo,
 
- 					context,
 
- 					item.loader,
 
- 					{},
 
- 					(err, result) => {
 
- 						if (
 
- 							err &&
 
- 							/^[^/]*$/.test(item.loader) &&
 
- 							!/-loader$/.test(item.loader)
 
- 						) {
 
- 							return resolver.resolve(
 
- 								contextInfo,
 
- 								context,
 
- 								item.loader + "-loader",
 
- 								{},
 
- 								err2 => {
 
- 									if (!err2) {
 
- 										err.message =
 
- 											err.message +
 
- 											"\n" +
 
- 											"BREAKING CHANGE: It's no longer allowed to omit the '-loader' suffix when using loaders.\n" +
 
- 											`                 You need to specify '${item.loader}-loader' instead of '${item.loader}',\n` +
 
- 											"                 see https://webpack.js.org/migrate/3/#automatic-loader-module-name-extension-removed";
 
- 									}
 
- 									callback(err);
 
- 								}
 
- 							);
 
- 						}
 
- 						if (err) return callback(err);
 
- 						const optionsOnly = item.options
 
- 							? {
 
- 									options: item.options
 
- 							  }
 
- 							: undefined;
 
- 						return callback(
 
- 							null,
 
- 							Object.assign({}, item, identToLoaderRequest(result), optionsOnly)
 
- 						);
 
- 					}
 
- 				);
 
- 			},
 
- 			callback
 
- 		);
 
- 	}
 
- 	getParser(type, parserOptions) {
 
- 		let ident = type;
 
- 		if (parserOptions) {
 
- 			if (parserOptions.ident) {
 
- 				ident = `${type}|${parserOptions.ident}`;
 
- 			} else {
 
- 				ident = JSON.stringify([type, parserOptions]);
 
- 			}
 
- 		}
 
- 		if (ident in this.parserCache) {
 
- 			return this.parserCache[ident];
 
- 		}
 
- 		return (this.parserCache[ident] = this.createParser(type, parserOptions));
 
- 	}
 
- 	createParser(type, parserOptions = {}) {
 
- 		const parser = this.hooks.createParser.for(type).call(parserOptions);
 
- 		if (!parser) {
 
- 			throw new Error(`No parser registered for ${type}`);
 
- 		}
 
- 		this.hooks.parser.for(type).call(parser, parserOptions);
 
- 		return parser;
 
- 	}
 
- 	getGenerator(type, generatorOptions) {
 
- 		let ident = type;
 
- 		if (generatorOptions) {
 
- 			if (generatorOptions.ident) {
 
- 				ident = `${type}|${generatorOptions.ident}`;
 
- 			} else {
 
- 				ident = JSON.stringify([type, generatorOptions]);
 
- 			}
 
- 		}
 
- 		if (ident in this.generatorCache) {
 
- 			return this.generatorCache[ident];
 
- 		}
 
- 		return (this.generatorCache[ident] = this.createGenerator(
 
- 			type,
 
- 			generatorOptions
 
- 		));
 
- 	}
 
- 	createGenerator(type, generatorOptions = {}) {
 
- 		const generator = this.hooks.createGenerator
 
- 			.for(type)
 
- 			.call(generatorOptions);
 
- 		if (!generator) {
 
- 			throw new Error(`No generator registered for ${type}`);
 
- 		}
 
- 		this.hooks.generator.for(type).call(generator, generatorOptions);
 
- 		return generator;
 
- 	}
 
- 	getResolver(type, resolveOptions) {
 
- 		return this.resolverFactory.get(
 
- 			type,
 
- 			resolveOptions || EMPTY_RESOLVE_OPTIONS
 
- 		);
 
- 	}
 
- }
 
- module.exports = NormalModuleFactory;
 
 
  |