You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			1167 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			JavaScript
		
	
		
		
			
		
	
	
			1167 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			JavaScript
		
	
| 
											9 months ago
										 | /* | ||
|  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | ||
|  | 	Author Tobias Koppers @sokra | ||
|  | */ | ||
|  | 
 | ||
|  | "use strict"; | ||
|  | 
 | ||
|  | const { getContext } = require("loader-runner"); | ||
|  | const asyncLib = require("neo-async"); | ||
|  | const { | ||
|  | 	AsyncSeriesBailHook, | ||
|  | 	SyncWaterfallHook, | ||
|  | 	SyncBailHook, | ||
|  | 	SyncHook, | ||
|  | 	HookMap | ||
|  | } = require("tapable"); | ||
|  | const ChunkGraph = require("./ChunkGraph"); | ||
|  | const Module = require("./Module"); | ||
|  | const ModuleFactory = require("./ModuleFactory"); | ||
|  | const ModuleGraph = require("./ModuleGraph"); | ||
|  | const { JAVASCRIPT_MODULE_TYPE_AUTO } = require("./ModuleTypeConstants"); | ||
|  | const NormalModule = require("./NormalModule"); | ||
|  | const BasicEffectRulePlugin = require("./rules/BasicEffectRulePlugin"); | ||
|  | const BasicMatcherRulePlugin = require("./rules/BasicMatcherRulePlugin"); | ||
|  | const ObjectMatcherRulePlugin = require("./rules/ObjectMatcherRulePlugin"); | ||
|  | const RuleSetCompiler = require("./rules/RuleSetCompiler"); | ||
|  | const UseEffectRulePlugin = require("./rules/UseEffectRulePlugin"); | ||
|  | const LazySet = require("./util/LazySet"); | ||
|  | const { getScheme } = require("./util/URLAbsoluteSpecifier"); | ||
|  | const { cachedCleverMerge, cachedSetProperty } = require("./util/cleverMerge"); | ||
|  | const { join } = require("./util/fs"); | ||
|  | const { | ||
|  | 	parseResource, | ||
|  | 	parseResourceWithoutFragment | ||
|  | } = require("./util/identifier"); | ||
|  | 
 | ||
|  | /** @typedef {import("../declarations/WebpackOptions").ModuleOptionsNormalized} ModuleOptions */ | ||
|  | /** @typedef {import("../declarations/WebpackOptions").RuleSetRule} RuleSetRule */ | ||
|  | /** @typedef {import("./Generator")} Generator */ | ||
|  | /** @typedef {import("./ModuleFactory").ModuleFactoryCreateData} ModuleFactoryCreateData */ | ||
|  | /** @typedef {import("./ModuleFactory").ModuleFactoryResult} ModuleFactoryResult */ | ||
|  | /** @typedef {import("./NormalModule").NormalModuleCreateData} NormalModuleCreateData */ | ||
|  | /** @typedef {import("./Parser")} Parser */ | ||
|  | /** @typedef {import("./ResolverFactory")} ResolverFactory */ | ||
|  | /** @typedef {import("./dependencies/ModuleDependency")} ModuleDependency */ | ||
|  | /** @typedef {import("./util/fs").InputFileSystem} InputFileSystem */ | ||
|  | 
 | ||
|  | /** @typedef {Pick<RuleSetRule, 'type'|'sideEffects'|'parser'|'generator'|'resolve'|'layer'>} ModuleSettings */ | ||
|  | /** @typedef {Partial<NormalModuleCreateData & {settings: ModuleSettings}>} CreateData */ | ||
|  | 
 | ||
|  | /** | ||
|  |  * @typedef {Object} ResolveData | ||
|  |  * @property {ModuleFactoryCreateData["contextInfo"]} contextInfo | ||
|  |  * @property {ModuleFactoryCreateData["resolveOptions"]} resolveOptions | ||
|  |  * @property {string} context | ||
|  |  * @property {string} request | ||
|  |  * @property {Record<string, any> | undefined} assertions | ||
|  |  * @property {ModuleDependency[]} dependencies | ||
|  |  * @property {string} dependencyType | ||
|  |  * @property {CreateData} createData | ||
|  |  * @property {LazySet<string>} fileDependencies | ||
|  |  * @property {LazySet<string>} missingDependencies | ||
|  |  * @property {LazySet<string>} contextDependencies | ||
|  |  * @property {boolean} cacheable allow to use the unsafe cache | ||
|  |  */ | ||
|  | 
 | ||
|  | /** | ||
|  |  * @typedef {Object} ResourceData | ||
|  |  * @property {string} resource | ||
|  |  * @property {string} path | ||
|  |  * @property {string} query | ||
|  |  * @property {string} fragment | ||
|  |  * @property {string=} context | ||
|  |  */ | ||
|  | 
 | ||
|  | /** @typedef {ResourceData & { data: Record<string, any> }} ResourceDataWithData */ | ||
|  | 
 | ||
|  | /** @typedef {Object} ParsedLoaderRequest | ||
|  |  * @property {string} loader loader | ||
|  |  * @property {string|undefined} options options | ||
|  |  */ | ||
|  | 
 | ||
|  | const EMPTY_RESOLVE_OPTIONS = {}; | ||
|  | const EMPTY_PARSER_OPTIONS = {}; | ||
|  | const EMPTY_GENERATOR_OPTIONS = {}; | ||
|  | const EMPTY_ELEMENTS = []; | ||
|  | 
 | ||
|  | const MATCH_RESOURCE_REGEX = /^([^!]+)!=!/; | ||
|  | const LEADING_DOT_EXTENSION_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 stringifyLoadersAndResource = (loaders, resource) => { | ||
|  | 	let str = ""; | ||
|  | 	for (const loader of loaders) { | ||
|  | 		str += loaderToIdent(loader) + "!"; | ||
|  | 	} | ||
|  | 	return str + resource; | ||
|  | }; | ||
|  | 
 | ||
|  | const needCalls = (times, callback) => { | ||
|  | 	return err => { | ||
|  | 		if (--times === 0) { | ||
|  | 			return callback(err); | ||
|  | 		} | ||
|  | 		if (err && times > 0) { | ||
|  | 			times = NaN; | ||
|  | 			return callback(err); | ||
|  | 		} | ||
|  | 	}; | ||
|  | }; | ||
|  | 
 | ||
|  | const mergeGlobalOptions = (globalOptions, type, localOptions) => { | ||
|  | 	const parts = type.split("/"); | ||
|  | 	let result; | ||
|  | 	let current = ""; | ||
|  | 	for (const part of parts) { | ||
|  | 		current = current ? `${current}/${part}` : part; | ||
|  | 		const options = globalOptions[current]; | ||
|  | 		if (typeof options === "object") { | ||
|  | 			if (result === undefined) { | ||
|  | 				result = options; | ||
|  | 			} else { | ||
|  | 				result = cachedCleverMerge(result, options); | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | 	if (result === undefined) { | ||
|  | 		return localOptions; | ||
|  | 	} else { | ||
|  | 		return cachedCleverMerge(result, localOptions); | ||
|  | 	} | ||
|  | }; | ||
|  | 
 | ||
|  | // TODO webpack 6 remove
 | ||
|  | const deprecationChangedHookMessage = (name, hook) => { | ||
|  | 	const names = hook.taps | ||
|  | 		.map(tapped => { | ||
|  | 			return tapped.name; | ||
|  | 		}) | ||
|  | 		.join(", "); | ||
|  | 
 | ||
|  | 	return ( | ||
|  | 		`NormalModuleFactory.${name} (${names}) is no longer a waterfall hook, but a bailing hook instead. ` + | ||
|  | 		"Do not return the passed object, but modify it instead. " + | ||
|  | 		"Returning false will ignore the request and results in no module created." | ||
|  | 	); | ||
|  | }; | ||
|  | 
 | ||
|  | const ruleSetCompiler = new RuleSetCompiler([ | ||
|  | 	new BasicMatcherRulePlugin("test", "resource"), | ||
|  | 	new BasicMatcherRulePlugin("scheme"), | ||
|  | 	new BasicMatcherRulePlugin("mimetype"), | ||
|  | 	new BasicMatcherRulePlugin("dependency"), | ||
|  | 	new BasicMatcherRulePlugin("include", "resource"), | ||
|  | 	new BasicMatcherRulePlugin("exclude", "resource", true), | ||
|  | 	new BasicMatcherRulePlugin("resource"), | ||
|  | 	new BasicMatcherRulePlugin("resourceQuery"), | ||
|  | 	new BasicMatcherRulePlugin("resourceFragment"), | ||
|  | 	new BasicMatcherRulePlugin("realResource"), | ||
|  | 	new BasicMatcherRulePlugin("issuer"), | ||
|  | 	new BasicMatcherRulePlugin("compiler"), | ||
|  | 	new BasicMatcherRulePlugin("issuerLayer"), | ||
|  | 	new ObjectMatcherRulePlugin("assert", "assertions"), | ||
|  | 	new ObjectMatcherRulePlugin("descriptionData"), | ||
|  | 	new BasicEffectRulePlugin("type"), | ||
|  | 	new BasicEffectRulePlugin("sideEffects"), | ||
|  | 	new BasicEffectRulePlugin("parser"), | ||
|  | 	new BasicEffectRulePlugin("resolve"), | ||
|  | 	new BasicEffectRulePlugin("generator"), | ||
|  | 	new BasicEffectRulePlugin("layer"), | ||
|  | 	new UseEffectRulePlugin() | ||
|  | ]); | ||
|  | 
 | ||
|  | class NormalModuleFactory extends ModuleFactory { | ||
|  | 	/** | ||
|  | 	 * @param {Object} param params | ||
|  | 	 * @param {string=} param.context context | ||
|  | 	 * @param {InputFileSystem} param.fs file system | ||
|  | 	 * @param {ResolverFactory} param.resolverFactory resolverFactory | ||
|  | 	 * @param {ModuleOptions} param.options options | ||
|  | 	 * @param {Object=} param.associatedObjectForCache an object to which the cache will be attached | ||
|  | 	 * @param {boolean=} param.layers enable layers | ||
|  | 	 */ | ||
|  | 	constructor({ | ||
|  | 		context, | ||
|  | 		fs, | ||
|  | 		resolverFactory, | ||
|  | 		options, | ||
|  | 		associatedObjectForCache, | ||
|  | 		layers = false | ||
|  | 	}) { | ||
|  | 		super(); | ||
|  | 		this.hooks = Object.freeze({ | ||
|  | 			/** @type {AsyncSeriesBailHook<[ResolveData], Module | false | void>} */ | ||
|  | 			resolve: new AsyncSeriesBailHook(["resolveData"]), | ||
|  | 			/** @type {HookMap<AsyncSeriesBailHook<[ResourceDataWithData, ResolveData], true | void>>} */ | ||
|  | 			resolveForScheme: new HookMap( | ||
|  | 				() => new AsyncSeriesBailHook(["resourceData", "resolveData"]) | ||
|  | 			), | ||
|  | 			/** @type {HookMap<AsyncSeriesBailHook<[ResourceDataWithData, ResolveData], true | void>>} */ | ||
|  | 			resolveInScheme: new HookMap( | ||
|  | 				() => new AsyncSeriesBailHook(["resourceData", "resolveData"]) | ||
|  | 			), | ||
|  | 			/** @type {AsyncSeriesBailHook<[ResolveData], Module>} */ | ||
|  | 			factorize: new AsyncSeriesBailHook(["resolveData"]), | ||
|  | 			/** @type {AsyncSeriesBailHook<[ResolveData], false | void>} */ | ||
|  | 			beforeResolve: new AsyncSeriesBailHook(["resolveData"]), | ||
|  | 			/** @type {AsyncSeriesBailHook<[ResolveData], false | void>} */ | ||
|  | 			afterResolve: new AsyncSeriesBailHook(["resolveData"]), | ||
|  | 			/** @type {AsyncSeriesBailHook<[ResolveData["createData"], ResolveData], Module | void>} */ | ||
|  | 			createModule: new AsyncSeriesBailHook(["createData", "resolveData"]), | ||
|  | 			/** @type {SyncWaterfallHook<[Module, ResolveData["createData"], ResolveData], Module>} */ | ||
|  | 			module: new SyncWaterfallHook(["module", "createData", "resolveData"]), | ||
|  | 			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"]) | ||
|  | 			), | ||
|  | 			createModuleClass: new HookMap( | ||
|  | 				() => new SyncBailHook(["createData", "resolveData"]) | ||
|  | 			) | ||
|  | 		}); | ||
|  | 		this.resolverFactory = resolverFactory; | ||
|  | 		this.ruleSet = ruleSetCompiler.compile([ | ||
|  | 			{ | ||
|  | 				rules: options.defaultRules | ||
|  | 			}, | ||
|  | 			{ | ||
|  | 				rules: options.rules | ||
|  | 			} | ||
|  | 		]); | ||
|  | 		this.context = context || ""; | ||
|  | 		this.fs = fs; | ||
|  | 		this._globalParserOptions = options.parser; | ||
|  | 		this._globalGeneratorOptions = options.generator; | ||
|  | 		/** @type {Map<string, WeakMap<Object, TODO>>} */ | ||
|  | 		this.parserCache = new Map(); | ||
|  | 		/** @type {Map<string, WeakMap<Object, Generator>>} */ | ||
|  | 		this.generatorCache = new Map(); | ||
|  | 		/** @type {Set<Module>} */ | ||
|  | 		this._restoredUnsafeCacheEntries = new Set(); | ||
|  | 
 | ||
|  | 		const cacheParseResource = parseResource.bindCache( | ||
|  | 			associatedObjectForCache | ||
|  | 		); | ||
|  | 		const cachedParseResourceWithoutFragment = | ||
|  | 			parseResourceWithoutFragment.bindCache(associatedObjectForCache); | ||
|  | 		this._parseResourceWithoutFragment = cachedParseResourceWithoutFragment; | ||
|  | 
 | ||
|  | 		this.hooks.factorize.tapAsync( | ||
|  | 			{ | ||
|  | 				name: "NormalModuleFactory", | ||
|  | 				stage: 100 | ||
|  | 			}, | ||
|  | 			(resolveData, callback) => { | ||
|  | 				this.hooks.resolve.callAsync(resolveData, (err, result) => { | ||
|  | 					if (err) return callback(err); | ||
|  | 
 | ||
|  | 					// Ignored
 | ||
|  | 					if (result === false) return callback(); | ||
|  | 
 | ||
|  | 					// direct module
 | ||
|  | 					if (result instanceof Module) return callback(null, result); | ||
|  | 
 | ||
|  | 					if (typeof result === "object") | ||
|  | 						throw new Error( | ||
|  | 							deprecationChangedHookMessage("resolve", this.hooks.resolve) + | ||
|  | 								" Returning a Module object will result in this module used as result." | ||
|  | 						); | ||
|  | 
 | ||
|  | 					this.hooks.afterResolve.callAsync(resolveData, (err, result) => { | ||
|  | 						if (err) return callback(err); | ||
|  | 
 | ||
|  | 						if (typeof result === "object") | ||
|  | 							throw new Error( | ||
|  | 								deprecationChangedHookMessage( | ||
|  | 									"afterResolve", | ||
|  | 									this.hooks.afterResolve | ||
|  | 								) | ||
|  | 							); | ||
|  | 
 | ||
|  | 						// Ignored
 | ||
|  | 						if (result === false) return callback(); | ||
|  | 
 | ||
|  | 						const createData = resolveData.createData; | ||
|  | 
 | ||
|  | 						this.hooks.createModule.callAsync( | ||
|  | 							createData, | ||
|  | 							resolveData, | ||
|  | 							(err, createdModule) => { | ||
|  | 								if (!createdModule) { | ||
|  | 									if (!resolveData.request) { | ||
|  | 										return callback(new Error("Empty dependency (no request)")); | ||
|  | 									} | ||
|  | 
 | ||
|  | 									// TODO webpack 6 make it required and move javascript/wasm/asset properties to own module
 | ||
|  | 									createdModule = this.hooks.createModuleClass | ||
|  | 										.for(createData.settings.type) | ||
|  | 										.call(createData, resolveData); | ||
|  | 
 | ||
|  | 									if (!createdModule) { | ||
|  | 										createdModule = /** @type {Module} */ ( | ||
|  | 											new NormalModule( | ||
|  | 												/** @type {NormalModuleCreateData} */ (createData) | ||
|  | 											) | ||
|  | 										); | ||
|  | 									} | ||
|  | 								} | ||
|  | 
 | ||
|  | 								createdModule = this.hooks.module.call( | ||
|  | 									createdModule, | ||
|  | 									createData, | ||
|  | 									resolveData | ||
|  | 								); | ||
|  | 
 | ||
|  | 								return callback(null, createdModule); | ||
|  | 							} | ||
|  | 						); | ||
|  | 					}); | ||
|  | 				}); | ||
|  | 			} | ||
|  | 		); | ||
|  | 		this.hooks.resolve.tapAsync( | ||
|  | 			{ | ||
|  | 				name: "NormalModuleFactory", | ||
|  | 				stage: 100 | ||
|  | 			}, | ||
|  | 			(data, callback) => { | ||
|  | 				const { | ||
|  | 					contextInfo, | ||
|  | 					context, | ||
|  | 					dependencies, | ||
|  | 					dependencyType, | ||
|  | 					request, | ||
|  | 					assertions, | ||
|  | 					resolveOptions, | ||
|  | 					fileDependencies, | ||
|  | 					missingDependencies, | ||
|  | 					contextDependencies | ||
|  | 				} = data; | ||
|  | 				const loaderResolver = this.getResolver("loader"); | ||
|  | 
 | ||
|  | 				/** @type {ResourceData | undefined} */ | ||
|  | 				let matchResourceData = undefined; | ||
|  | 				/** @type {string} */ | ||
|  | 				let unresolvedResource; | ||
|  | 				/** @type {ParsedLoaderRequest[]} */ | ||
|  | 				let elements; | ||
|  | 				let noPreAutoLoaders = false; | ||
|  | 				let noAutoLoaders = false; | ||
|  | 				let noPrePostAutoLoaders = false; | ||
|  | 
 | ||
|  | 				const contextScheme = getScheme(context); | ||
|  | 				/** @type {string | undefined} */ | ||
|  | 				let scheme = getScheme(request); | ||
|  | 
 | ||
|  | 				if (!scheme) { | ||
|  | 					/** @type {string} */ | ||
|  | 					let requestWithoutMatchResource = request; | ||
|  | 					const matchResourceMatch = MATCH_RESOURCE_REGEX.exec(request); | ||
|  | 					if (matchResourceMatch) { | ||
|  | 						let matchResource = matchResourceMatch[1]; | ||
|  | 						if (matchResource.charCodeAt(0) === 46) { | ||
|  | 							// 46 === ".", 47 === "/"
 | ||
|  | 							const secondChar = matchResource.charCodeAt(1); | ||
|  | 							if ( | ||
|  | 								secondChar === 47 || | ||
|  | 								(secondChar === 46 && matchResource.charCodeAt(2) === 47) | ||
|  | 							) { | ||
|  | 								// if matchResources startsWith ../ or ./
 | ||
|  | 								matchResource = join(this.fs, context, matchResource); | ||
|  | 							} | ||
|  | 						} | ||
|  | 						matchResourceData = { | ||
|  | 							resource: matchResource, | ||
|  | 							...cacheParseResource(matchResource) | ||
|  | 						}; | ||
|  | 						requestWithoutMatchResource = request.slice( | ||
|  | 							matchResourceMatch[0].length | ||
|  | 						); | ||
|  | 					} | ||
|  | 
 | ||
|  | 					scheme = getScheme(requestWithoutMatchResource); | ||
|  | 
 | ||
|  | 					if (!scheme && !contextScheme) { | ||
|  | 						const firstChar = requestWithoutMatchResource.charCodeAt(0); | ||
|  | 						const secondChar = requestWithoutMatchResource.charCodeAt(1); | ||
|  | 						noPreAutoLoaders = firstChar === 45 && secondChar === 33; // startsWith "-!"
 | ||
|  | 						noAutoLoaders = noPreAutoLoaders || firstChar === 33; // startsWith "!"
 | ||
|  | 						noPrePostAutoLoaders = firstChar === 33 && secondChar === 33; // startsWith "!!";
 | ||
|  | 						const rawElements = requestWithoutMatchResource | ||
|  | 							.slice( | ||
|  | 								noPreAutoLoaders || noPrePostAutoLoaders | ||
|  | 									? 2 | ||
|  | 									: noAutoLoaders | ||
|  | 									? 1 | ||
|  | 									: 0 | ||
|  | 							) | ||
|  | 							.split(/!+/); | ||
|  | 						unresolvedResource = rawElements.pop(); | ||
|  | 						elements = rawElements.map(el => { | ||
|  | 							const { path, query } = cachedParseResourceWithoutFragment(el); | ||
|  | 							return { | ||
|  | 								loader: path, | ||
|  | 								options: query ? query.slice(1) : undefined | ||
|  | 							}; | ||
|  | 						}); | ||
|  | 						scheme = getScheme(unresolvedResource); | ||
|  | 					} else { | ||
|  | 						unresolvedResource = requestWithoutMatchResource; | ||
|  | 						elements = EMPTY_ELEMENTS; | ||
|  | 					} | ||
|  | 				} else { | ||
|  | 					unresolvedResource = request; | ||
|  | 					elements = EMPTY_ELEMENTS; | ||
|  | 				} | ||
|  | 
 | ||
|  | 				const resolveContext = { | ||
|  | 					fileDependencies, | ||
|  | 					missingDependencies, | ||
|  | 					contextDependencies | ||
|  | 				}; | ||
|  | 
 | ||
|  | 				/** @type {ResourceDataWithData} */ | ||
|  | 				let resourceData; | ||
|  | 
 | ||
|  | 				let loaders; | ||
|  | 
 | ||
|  | 				const continueCallback = needCalls(2, err => { | ||
|  | 					if (err) return callback(err); | ||
|  | 
 | ||
|  | 					// translate option idents
 | ||
|  | 					try { | ||
|  | 						for (const item of loaders) { | ||
|  | 							if (typeof item.options === "string" && item.options[0] === "?") { | ||
|  | 								const ident = item.options.slice(1); | ||
|  | 								if (ident === "[[missing ident]]") { | ||
|  | 									throw new Error( | ||
|  | 										"No ident is provided by referenced loader. " + | ||
|  | 											"When using a function for Rule.use in config you need to " + | ||
|  | 											"provide an 'ident' property for referenced loader options." | ||
|  | 									); | ||
|  | 								} | ||
|  | 								item.options = this.ruleSet.references.get(ident); | ||
|  | 								if (item.options === undefined) { | ||
|  | 									throw new Error( | ||
|  | 										"Invalid ident is provided by referenced loader" | ||
|  | 									); | ||
|  | 								} | ||
|  | 								item.ident = ident; | ||
|  | 							} | ||
|  | 						} | ||
|  | 					} catch (e) { | ||
|  | 						return callback(e); | ||
|  | 					} | ||
|  | 
 | ||
|  | 					if (!resourceData) { | ||
|  | 						// ignored
 | ||
|  | 						return callback(null, dependencies[0].createIgnoredModule(context)); | ||
|  | 					} | ||
|  | 
 | ||
|  | 					const userRequest = | ||
|  | 						(matchResourceData !== undefined | ||
|  | 							? `${matchResourceData.resource}!=!` | ||
|  | 							: "") + | ||
|  | 						stringifyLoadersAndResource(loaders, resourceData.resource); | ||
|  | 
 | ||
|  | 					const settings = {}; | ||
|  | 					const useLoadersPost = []; | ||
|  | 					const useLoaders = []; | ||
|  | 					const useLoadersPre = []; | ||
|  | 
 | ||
|  | 					// handle .webpack[] suffix
 | ||
|  | 					let resource; | ||
|  | 					let match; | ||
|  | 					if ( | ||
|  | 						matchResourceData && | ||
|  | 						typeof (resource = matchResourceData.resource) === "string" && | ||
|  | 						(match = /\.webpack\[([^\]]+)\]$/.exec(resource)) | ||
|  | 					) { | ||
|  | 						settings.type = match[1]; | ||
|  | 						matchResourceData.resource = matchResourceData.resource.slice( | ||
|  | 							0, | ||
|  | 							-settings.type.length - 10 | ||
|  | 						); | ||
|  | 					} else { | ||
|  | 						settings.type = JAVASCRIPT_MODULE_TYPE_AUTO; | ||
|  | 						const resourceDataForRules = matchResourceData || resourceData; | ||
|  | 						const result = this.ruleSet.exec({ | ||
|  | 							resource: resourceDataForRules.path, | ||
|  | 							realResource: resourceData.path, | ||
|  | 							resourceQuery: resourceDataForRules.query, | ||
|  | 							resourceFragment: resourceDataForRules.fragment, | ||
|  | 							scheme, | ||
|  | 							assertions, | ||
|  | 							mimetype: matchResourceData | ||
|  | 								? "" | ||
|  | 								: resourceData.data.mimetype || "", | ||
|  | 							dependency: dependencyType, | ||
|  | 							descriptionData: matchResourceData | ||
|  | 								? undefined | ||
|  | 								: resourceData.data.descriptionFileData, | ||
|  | 							issuer: contextInfo.issuer, | ||
|  | 							compiler: contextInfo.compiler, | ||
|  | 							issuerLayer: contextInfo.issuerLayer || "" | ||
|  | 						}); | ||
|  | 						for (const r of result) { | ||
|  | 							// https://github.com/webpack/webpack/issues/16466
 | ||
|  | 							// if a request exists PrePostAutoLoaders, should disable modifying Rule.type
 | ||
|  | 							if (r.type === "type" && noPrePostAutoLoaders) { | ||
|  | 								continue; | ||
|  | 							} | ||
|  | 							if (r.type === "use") { | ||
|  | 								if (!noAutoLoaders && !noPrePostAutoLoaders) { | ||
|  | 									useLoaders.push(r.value); | ||
|  | 								} | ||
|  | 							} else if (r.type === "use-post") { | ||
|  | 								if (!noPrePostAutoLoaders) { | ||
|  | 									useLoadersPost.push(r.value); | ||
|  | 								} | ||
|  | 							} else if (r.type === "use-pre") { | ||
|  | 								if (!noPreAutoLoaders && !noPrePostAutoLoaders) { | ||
|  | 									useLoadersPre.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; | ||
|  | 							} | ||
|  | 						} | ||
|  | 					} | ||
|  | 
 | ||
|  | 					let postLoaders, normalLoaders, preLoaders; | ||
|  | 
 | ||
|  | 					const continueCallback = needCalls(3, err => { | ||
|  | 						if (err) { | ||
|  | 							return callback(err); | ||
|  | 						} | ||
|  | 						const allLoaders = postLoaders; | ||
|  | 						if (matchResourceData === undefined) { | ||
|  | 							for (const loader of loaders) allLoaders.push(loader); | ||
|  | 							for (const loader of normalLoaders) allLoaders.push(loader); | ||
|  | 						} else { | ||
|  | 							for (const loader of normalLoaders) allLoaders.push(loader); | ||
|  | 							for (const loader of loaders) allLoaders.push(loader); | ||
|  | 						} | ||
|  | 						for (const loader of preLoaders) allLoaders.push(loader); | ||
|  | 						let type = settings.type; | ||
|  | 						const resolveOptions = settings.resolve; | ||
|  | 						const layer = settings.layer; | ||
|  | 						if (layer !== undefined && !layers) { | ||
|  | 							return callback( | ||
|  | 								new Error( | ||
|  | 									"'Rule.layer' is only allowed when 'experiments.layers' is enabled" | ||
|  | 								) | ||
|  | 							); | ||
|  | 						} | ||
|  | 						try { | ||
|  | 							Object.assign(data.createData, { | ||
|  | 								layer: | ||
|  | 									layer === undefined ? contextInfo.issuerLayer || null : layer, | ||
|  | 								request: stringifyLoadersAndResource( | ||
|  | 									allLoaders, | ||
|  | 									resourceData.resource | ||
|  | 								), | ||
|  | 								userRequest, | ||
|  | 								rawRequest: request, | ||
|  | 								loaders: allLoaders, | ||
|  | 								resource: resourceData.resource, | ||
|  | 								context: | ||
|  | 									resourceData.context || getContext(resourceData.resource), | ||
|  | 								matchResource: matchResourceData | ||
|  | 									? matchResourceData.resource | ||
|  | 									: undefined, | ||
|  | 								resourceResolveData: resourceData.data, | ||
|  | 								settings, | ||
|  | 								type, | ||
|  | 								parser: this.getParser(type, settings.parser), | ||
|  | 								parserOptions: settings.parser, | ||
|  | 								generator: this.getGenerator(type, settings.generator), | ||
|  | 								generatorOptions: settings.generator, | ||
|  | 								resolveOptions | ||
|  | 							}); | ||
|  | 						} catch (e) { | ||
|  | 							return callback(e); | ||
|  | 						} | ||
|  | 						callback(); | ||
|  | 					}); | ||
|  | 					this.resolveRequestArray( | ||
|  | 						contextInfo, | ||
|  | 						this.context, | ||
|  | 						useLoadersPost, | ||
|  | 						loaderResolver, | ||
|  | 						resolveContext, | ||
|  | 						(err, result) => { | ||
|  | 							postLoaders = result; | ||
|  | 							continueCallback(err); | ||
|  | 						} | ||
|  | 					); | ||
|  | 					this.resolveRequestArray( | ||
|  | 						contextInfo, | ||
|  | 						this.context, | ||
|  | 						useLoaders, | ||
|  | 						loaderResolver, | ||
|  | 						resolveContext, | ||
|  | 						(err, result) => { | ||
|  | 							normalLoaders = result; | ||
|  | 							continueCallback(err); | ||
|  | 						} | ||
|  | 					); | ||
|  | 					this.resolveRequestArray( | ||
|  | 						contextInfo, | ||
|  | 						this.context, | ||
|  | 						useLoadersPre, | ||
|  | 						loaderResolver, | ||
|  | 						resolveContext, | ||
|  | 						(err, result) => { | ||
|  | 							preLoaders = result; | ||
|  | 							continueCallback(err); | ||
|  | 						} | ||
|  | 					); | ||
|  | 				}); | ||
|  | 
 | ||
|  | 				this.resolveRequestArray( | ||
|  | 					contextInfo, | ||
|  | 					contextScheme ? this.context : context, | ||
|  | 					elements, | ||
|  | 					loaderResolver, | ||
|  | 					resolveContext, | ||
|  | 					(err, result) => { | ||
|  | 						if (err) return continueCallback(err); | ||
|  | 						loaders = result; | ||
|  | 						continueCallback(); | ||
|  | 					} | ||
|  | 				); | ||
|  | 
 | ||
|  | 				const defaultResolve = context => { | ||
|  | 					if (/^($|\?)/.test(unresolvedResource)) { | ||
|  | 						resourceData = { | ||
|  | 							resource: unresolvedResource, | ||
|  | 							data: {}, | ||
|  | 							...cacheParseResource(unresolvedResource) | ||
|  | 						}; | ||
|  | 						continueCallback(); | ||
|  | 					} | ||
|  | 
 | ||
|  | 					// resource without scheme and with path
 | ||
|  | 					else { | ||
|  | 						const normalResolver = this.getResolver( | ||
|  | 							"normal", | ||
|  | 							dependencyType | ||
|  | 								? cachedSetProperty( | ||
|  | 										resolveOptions || EMPTY_RESOLVE_OPTIONS, | ||
|  | 										"dependencyType", | ||
|  | 										dependencyType | ||
|  | 								  ) | ||
|  | 								: resolveOptions | ||
|  | 						); | ||
|  | 						this.resolveResource( | ||
|  | 							contextInfo, | ||
|  | 							context, | ||
|  | 							unresolvedResource, | ||
|  | 							normalResolver, | ||
|  | 							resolveContext, | ||
|  | 							(err, resolvedResource, resolvedResourceResolveData) => { | ||
|  | 								if (err) return continueCallback(err); | ||
|  | 								if (resolvedResource !== false) { | ||
|  | 									resourceData = { | ||
|  | 										resource: resolvedResource, | ||
|  | 										data: resolvedResourceResolveData, | ||
|  | 										...cacheParseResource(resolvedResource) | ||
|  | 									}; | ||
|  | 								} | ||
|  | 								continueCallback(); | ||
|  | 							} | ||
|  | 						); | ||
|  | 					} | ||
|  | 				}; | ||
|  | 
 | ||
|  | 				// resource with scheme
 | ||
|  | 				if (scheme) { | ||
|  | 					resourceData = { | ||
|  | 						resource: unresolvedResource, | ||
|  | 						data: {}, | ||
|  | 						path: undefined, | ||
|  | 						query: undefined, | ||
|  | 						fragment: undefined, | ||
|  | 						context: undefined | ||
|  | 					}; | ||
|  | 					this.hooks.resolveForScheme | ||
|  | 						.for(scheme) | ||
|  | 						.callAsync(resourceData, data, err => { | ||
|  | 							if (err) return continueCallback(err); | ||
|  | 							continueCallback(); | ||
|  | 						}); | ||
|  | 				} | ||
|  | 
 | ||
|  | 				// resource within scheme
 | ||
|  | 				else if (contextScheme) { | ||
|  | 					resourceData = { | ||
|  | 						resource: unresolvedResource, | ||
|  | 						data: {}, | ||
|  | 						path: undefined, | ||
|  | 						query: undefined, | ||
|  | 						fragment: undefined, | ||
|  | 						context: undefined | ||
|  | 					}; | ||
|  | 					this.hooks.resolveInScheme | ||
|  | 						.for(contextScheme) | ||
|  | 						.callAsync(resourceData, data, (err, handled) => { | ||
|  | 							if (err) return continueCallback(err); | ||
|  | 							if (!handled) return defaultResolve(this.context); | ||
|  | 							continueCallback(); | ||
|  | 						}); | ||
|  | 				} | ||
|  | 
 | ||
|  | 				// resource without scheme and without path
 | ||
|  | 				else defaultResolve(context); | ||
|  | 			} | ||
|  | 		); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	cleanupForCache() { | ||
|  | 		for (const module of this._restoredUnsafeCacheEntries) { | ||
|  | 			ChunkGraph.clearChunkGraphForModule(module); | ||
|  | 			ModuleGraph.clearModuleGraphForModule(module); | ||
|  | 			module.cleanupForCache(); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * @param {ModuleFactoryCreateData} data data object | ||
|  | 	 * @param {function((Error | null)=, ModuleFactoryResult=): void} callback callback | ||
|  | 	 * @returns {void} | ||
|  | 	 */ | ||
|  | 	create(data, callback) { | ||
|  | 		const dependencies = /** @type {ModuleDependency[]} */ (data.dependencies); | ||
|  | 		const context = data.context || this.context; | ||
|  | 		const resolveOptions = data.resolveOptions || EMPTY_RESOLVE_OPTIONS; | ||
|  | 		const dependency = dependencies[0]; | ||
|  | 		const request = dependency.request; | ||
|  | 		const assertions = dependency.assertions; | ||
|  | 		const contextInfo = data.contextInfo; | ||
|  | 		const fileDependencies = new LazySet(); | ||
|  | 		const missingDependencies = new LazySet(); | ||
|  | 		const contextDependencies = new LazySet(); | ||
|  | 		const dependencyType = | ||
|  | 			(dependencies.length > 0 && dependencies[0].category) || ""; | ||
|  | 		/** @type {ResolveData} */ | ||
|  | 		const resolveData = { | ||
|  | 			contextInfo, | ||
|  | 			resolveOptions, | ||
|  | 			context, | ||
|  | 			request, | ||
|  | 			assertions, | ||
|  | 			dependencies, | ||
|  | 			dependencyType, | ||
|  | 			fileDependencies, | ||
|  | 			missingDependencies, | ||
|  | 			contextDependencies, | ||
|  | 			createData: {}, | ||
|  | 			cacheable: true | ||
|  | 		}; | ||
|  | 		this.hooks.beforeResolve.callAsync(resolveData, (err, result) => { | ||
|  | 			if (err) { | ||
|  | 				return callback(err, { | ||
|  | 					fileDependencies, | ||
|  | 					missingDependencies, | ||
|  | 					contextDependencies, | ||
|  | 					cacheable: false | ||
|  | 				}); | ||
|  | 			} | ||
|  | 
 | ||
|  | 			// Ignored
 | ||
|  | 			if (result === false) { | ||
|  | 				return callback(null, { | ||
|  | 					fileDependencies, | ||
|  | 					missingDependencies, | ||
|  | 					contextDependencies, | ||
|  | 					cacheable: resolveData.cacheable | ||
|  | 				}); | ||
|  | 			} | ||
|  | 
 | ||
|  | 			if (typeof result === "object") | ||
|  | 				throw new Error( | ||
|  | 					deprecationChangedHookMessage( | ||
|  | 						"beforeResolve", | ||
|  | 						this.hooks.beforeResolve | ||
|  | 					) | ||
|  | 				); | ||
|  | 
 | ||
|  | 			this.hooks.factorize.callAsync(resolveData, (err, module) => { | ||
|  | 				if (err) { | ||
|  | 					return callback(err, { | ||
|  | 						fileDependencies, | ||
|  | 						missingDependencies, | ||
|  | 						contextDependencies, | ||
|  | 						cacheable: false | ||
|  | 					}); | ||
|  | 				} | ||
|  | 
 | ||
|  | 				const factoryResult = { | ||
|  | 					module, | ||
|  | 					fileDependencies, | ||
|  | 					missingDependencies, | ||
|  | 					contextDependencies, | ||
|  | 					cacheable: resolveData.cacheable | ||
|  | 				}; | ||
|  | 
 | ||
|  | 				callback(null, factoryResult); | ||
|  | 			}); | ||
|  | 		}); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	resolveResource( | ||
|  | 		contextInfo, | ||
|  | 		context, | ||
|  | 		unresolvedResource, | ||
|  | 		resolver, | ||
|  | 		resolveContext, | ||
|  | 		callback | ||
|  | 	) { | ||
|  | 		resolver.resolve( | ||
|  | 			contextInfo, | ||
|  | 			context, | ||
|  | 			unresolvedResource, | ||
|  | 			resolveContext, | ||
|  | 			(err, resolvedResource, resolvedResourceResolveData) => { | ||
|  | 				if (err) { | ||
|  | 					return this._resolveResourceErrorHints( | ||
|  | 						err, | ||
|  | 						contextInfo, | ||
|  | 						context, | ||
|  | 						unresolvedResource, | ||
|  | 						resolver, | ||
|  | 						resolveContext, | ||
|  | 						(err2, hints) => { | ||
|  | 							if (err2) { | ||
|  | 								err.message += `
 | ||
|  | A fatal error happened during resolving additional hints for this error: ${err2.message}`;
 | ||
|  | 								err.stack += `
 | ||
|  | 
 | ||
|  | A fatal error happened during resolving additional hints for this error: | ||
|  | ${err2.stack}`;
 | ||
|  | 								return callback(err); | ||
|  | 							} | ||
|  | 							if (hints && hints.length > 0) { | ||
|  | 								err.message += `
 | ||
|  | ${hints.join("\n\n")}`;
 | ||
|  | 							} | ||
|  | 
 | ||
|  | 							// Check if the extension is missing a leading dot (e.g. "js" instead of ".js")
 | ||
|  | 							let appendResolveExtensionsHint = false; | ||
|  | 							const specifiedExtensions = Array.from( | ||
|  | 								resolver.options.extensions | ||
|  | 							); | ||
|  | 							const expectedExtensions = specifiedExtensions.map(extension => { | ||
|  | 								if (LEADING_DOT_EXTENSION_REGEX.test(extension)) { | ||
|  | 									appendResolveExtensionsHint = true; | ||
|  | 									return `.${extension}`; | ||
|  | 								} | ||
|  | 								return extension; | ||
|  | 							}); | ||
|  | 							if (appendResolveExtensionsHint) { | ||
|  | 								err.message += `\nDid you miss the leading dot in 'resolve.extensions'? Did you mean '${JSON.stringify( | ||
|  | 									expectedExtensions | ||
|  | 								)}' instead of '${JSON.stringify(specifiedExtensions)}'?`;
 | ||
|  | 							} | ||
|  | 
 | ||
|  | 							callback(err); | ||
|  | 						} | ||
|  | 					); | ||
|  | 				} | ||
|  | 				callback(err, resolvedResource, resolvedResourceResolveData); | ||
|  | 			} | ||
|  | 		); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	_resolveResourceErrorHints( | ||
|  | 		error, | ||
|  | 		contextInfo, | ||
|  | 		context, | ||
|  | 		unresolvedResource, | ||
|  | 		resolver, | ||
|  | 		resolveContext, | ||
|  | 		callback | ||
|  | 	) { | ||
|  | 		asyncLib.parallel( | ||
|  | 			[ | ||
|  | 				callback => { | ||
|  | 					if (!resolver.options.fullySpecified) return callback(); | ||
|  | 					resolver | ||
|  | 						.withOptions({ | ||
|  | 							fullySpecified: false | ||
|  | 						}) | ||
|  | 						.resolve( | ||
|  | 							contextInfo, | ||
|  | 							context, | ||
|  | 							unresolvedResource, | ||
|  | 							resolveContext, | ||
|  | 							(err, resolvedResource) => { | ||
|  | 								if (!err && resolvedResource) { | ||
|  | 									const resource = parseResource(resolvedResource).path.replace( | ||
|  | 										/^.*[\\/]/, | ||
|  | 										"" | ||
|  | 									); | ||
|  | 									return callback( | ||
|  | 										null, | ||
|  | 										`Did you mean '${resource}'?
 | ||
|  | BREAKING CHANGE: The request '${unresolvedResource}' failed to resolve only because it was resolved as fully specified | ||
|  | (probably because the origin is strict EcmaScript Module, e. g. a module with javascript mimetype, a '*.mjs' file, or a '*.js' file where the package.json contains '"type": "module"'). | ||
|  | The extension in the request is mandatory for it to be fully specified. | ||
|  | Add the extension to the request.`
 | ||
|  | 									); | ||
|  | 								} | ||
|  | 								callback(); | ||
|  | 							} | ||
|  | 						); | ||
|  | 				}, | ||
|  | 				callback => { | ||
|  | 					if (!resolver.options.enforceExtension) return callback(); | ||
|  | 					resolver | ||
|  | 						.withOptions({ | ||
|  | 							enforceExtension: false, | ||
|  | 							extensions: [] | ||
|  | 						}) | ||
|  | 						.resolve( | ||
|  | 							contextInfo, | ||
|  | 							context, | ||
|  | 							unresolvedResource, | ||
|  | 							resolveContext, | ||
|  | 							(err, resolvedResource) => { | ||
|  | 								if (!err && resolvedResource) { | ||
|  | 									let hint = ""; | ||
|  | 									const match = /(\.[^.]+)(\?|$)/.exec(unresolvedResource); | ||
|  | 									if (match) { | ||
|  | 										const fixedRequest = unresolvedResource.replace( | ||
|  | 											/(\.[^.]+)(\?|$)/, | ||
|  | 											"$2" | ||
|  | 										); | ||
|  | 										if (resolver.options.extensions.has(match[1])) { | ||
|  | 											hint = `Did you mean '${fixedRequest}'?`; | ||
|  | 										} else { | ||
|  | 											hint = `Did you mean '${fixedRequest}'? Also note that '${match[1]}' is not in 'resolve.extensions' yet and need to be added for this to work?`; | ||
|  | 										} | ||
|  | 									} else { | ||
|  | 										hint = `Did you mean to omit the extension or to remove 'resolve.enforceExtension'?`; | ||
|  | 									} | ||
|  | 									return callback( | ||
|  | 										null, | ||
|  | 										`The request '${unresolvedResource}' failed to resolve only because 'resolve.enforceExtension' was specified.
 | ||
|  | ${hint} | ||
|  | Including the extension in the request is no longer possible. Did you mean to enforce including the extension in requests with 'resolve.extensions: []' instead?`
 | ||
|  | 									); | ||
|  | 								} | ||
|  | 								callback(); | ||
|  | 							} | ||
|  | 						); | ||
|  | 				}, | ||
|  | 				callback => { | ||
|  | 					if ( | ||
|  | 						/^\.\.?\//.test(unresolvedResource) || | ||
|  | 						resolver.options.preferRelative | ||
|  | 					) { | ||
|  | 						return callback(); | ||
|  | 					} | ||
|  | 					resolver.resolve( | ||
|  | 						contextInfo, | ||
|  | 						context, | ||
|  | 						`./${unresolvedResource}`, | ||
|  | 						resolveContext, | ||
|  | 						(err, resolvedResource) => { | ||
|  | 							if (err || !resolvedResource) return callback(); | ||
|  | 							const moduleDirectories = resolver.options.modules | ||
|  | 								.map(m => (Array.isArray(m) ? m.join(", ") : m)) | ||
|  | 								.join(", "); | ||
|  | 							callback( | ||
|  | 								null, | ||
|  | 								`Did you mean './${unresolvedResource}'?
 | ||
|  | Requests that should resolve in the current directory need to start with './'. | ||
|  | Requests that start with a name are treated as module requests and resolve within module directories (${moduleDirectories}). | ||
|  | If changing the source code is not an option there is also a resolve options called 'preferRelative' which tries to resolve these kind of requests in the current directory too.`
 | ||
|  | 							); | ||
|  | 						} | ||
|  | 					); | ||
|  | 				} | ||
|  | 			], | ||
|  | 			(err, hints) => { | ||
|  | 				if (err) return callback(err); | ||
|  | 				callback(null, hints.filter(Boolean)); | ||
|  | 			} | ||
|  | 		); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	resolveRequestArray( | ||
|  | 		contextInfo, | ||
|  | 		context, | ||
|  | 		array, | ||
|  | 		resolver, | ||
|  | 		resolveContext, | ||
|  | 		callback | ||
|  | 	) { | ||
|  | 		if (array.length === 0) return callback(null, array); | ||
|  | 		asyncLib.map( | ||
|  | 			array, | ||
|  | 			(item, callback) => { | ||
|  | 				resolver.resolve( | ||
|  | 					contextInfo, | ||
|  | 					context, | ||
|  | 					item.loader, | ||
|  | 					resolveContext, | ||
|  | 					(err, result, resolveRequest) => { | ||
|  | 						if ( | ||
|  | 							err && | ||
|  | 							/^[^/]*$/.test(item.loader) && | ||
|  | 							!/-loader$/.test(item.loader) | ||
|  | 						) { | ||
|  | 							return resolver.resolve( | ||
|  | 								contextInfo, | ||
|  | 								context, | ||
|  | 								item.loader + "-loader", | ||
|  | 								resolveContext, | ||
|  | 								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 parsedResult = this._parseResourceWithoutFragment(result); | ||
|  | 
 | ||
|  | 						const type = /\.mjs$/i.test(parsedResult.path) | ||
|  | 							? "module" | ||
|  | 							: /\.cjs$/i.test(parsedResult.path) | ||
|  | 							? "commonjs" | ||
|  | 							: resolveRequest.descriptionFileData === undefined | ||
|  | 							? undefined | ||
|  | 							: resolveRequest.descriptionFileData.type; | ||
|  | 
 | ||
|  | 						const resolved = { | ||
|  | 							loader: parsedResult.path, | ||
|  | 							type, | ||
|  | 							options: | ||
|  | 								item.options === undefined | ||
|  | 									? parsedResult.query | ||
|  | 										? parsedResult.query.slice(1) | ||
|  | 										: undefined | ||
|  | 									: item.options, | ||
|  | 							ident: item.options === undefined ? undefined : item.ident | ||
|  | 						}; | ||
|  | 						return callback(null, resolved); | ||
|  | 					} | ||
|  | 				); | ||
|  | 			}, | ||
|  | 			callback | ||
|  | 		); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	getParser(type, parserOptions = EMPTY_PARSER_OPTIONS) { | ||
|  | 		let cache = this.parserCache.get(type); | ||
|  | 
 | ||
|  | 		if (cache === undefined) { | ||
|  | 			cache = new WeakMap(); | ||
|  | 			this.parserCache.set(type, cache); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		let parser = cache.get(parserOptions); | ||
|  | 
 | ||
|  | 		if (parser === undefined) { | ||
|  | 			parser = this.createParser(type, parserOptions); | ||
|  | 			cache.set(parserOptions, parser); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		return parser; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * @param {string} type type | ||
|  | 	 * @param {{[k: string]: any}} parserOptions parser options | ||
|  | 	 * @returns {Parser} parser | ||
|  | 	 */ | ||
|  | 	createParser(type, parserOptions = {}) { | ||
|  | 		parserOptions = mergeGlobalOptions( | ||
|  | 			this._globalParserOptions, | ||
|  | 			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 = EMPTY_GENERATOR_OPTIONS) { | ||
|  | 		let cache = this.generatorCache.get(type); | ||
|  | 
 | ||
|  | 		if (cache === undefined) { | ||
|  | 			cache = new WeakMap(); | ||
|  | 			this.generatorCache.set(type, cache); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		let generator = cache.get(generatorOptions); | ||
|  | 
 | ||
|  | 		if (generator === undefined) { | ||
|  | 			generator = this.createGenerator(type, generatorOptions); | ||
|  | 			cache.set(generatorOptions, generator); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		return generator; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	createGenerator(type, generatorOptions = {}) { | ||
|  | 		generatorOptions = mergeGlobalOptions( | ||
|  | 			this._globalGeneratorOptions, | ||
|  | 			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); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | module.exports = NormalModuleFactory; |