mirror of https://github.com/webpack/webpack.git
				
				
				
			
		
			
				
	
	
		
			1145 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			1145 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
/*
 | 
						|
	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"])
 | 
						|
			)
 | 
						|
		});
 | 
						|
		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)"));
 | 
						|
									}
 | 
						|
 | 
						|
									createdModule = 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=, 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) => {
 | 
						|
						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 resolved = {
 | 
						|
							loader: parsedResult.path,
 | 
						|
							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;
 |