| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370 | /*	MIT License http://www.opensource.org/licenses/mit-license.php	Author Tobias Koppers @sokra*/"use strict";const Resolver = require("./Resolver");const SyncAsyncFileSystemDecorator = require("./SyncAsyncFileSystemDecorator");const ParsePlugin = require("./ParsePlugin");const DescriptionFilePlugin = require("./DescriptionFilePlugin");const NextPlugin = require("./NextPlugin");const TryNextPlugin = require("./TryNextPlugin");const ModuleKindPlugin = require("./ModuleKindPlugin");const FileKindPlugin = require("./FileKindPlugin");const JoinRequestPlugin = require("./JoinRequestPlugin");const ModulesInHierachicDirectoriesPlugin = require("./ModulesInHierachicDirectoriesPlugin");const ModulesInRootPlugin = require("./ModulesInRootPlugin");const AliasPlugin = require("./AliasPlugin");const AliasFieldPlugin = require("./AliasFieldPlugin");const ConcordExtensionsPlugin = require("./ConcordExtensionsPlugin");const ConcordMainPlugin = require("./ConcordMainPlugin");const ConcordModulesPlugin = require("./ConcordModulesPlugin");const DirectoryExistsPlugin = require("./DirectoryExistsPlugin");const FileExistsPlugin = require("./FileExistsPlugin");const SymlinkPlugin = require("./SymlinkPlugin");const MainFieldPlugin = require("./MainFieldPlugin");const UseFilePlugin = require("./UseFilePlugin");const AppendPlugin = require("./AppendPlugin");const RootPlugin = require("./RootPlugin");const RestrictionsPlugin = require("./RestrictionsPlugin");const ResultPlugin = require("./ResultPlugin");const ModuleAppendPlugin = require("./ModuleAppendPlugin");const UnsafeCachePlugin = require("./UnsafeCachePlugin");exports.createResolver = function(options) {	//// OPTIONS ////	// A list of directories to resolve modules from, can be absolute path or folder name	let modules = options.modules || ["node_modules"];	// A list of description files to read from	const descriptionFiles = options.descriptionFiles || ["package.json"];	// A list of additional resolve plugins which should be applied	// The slice is there to create a copy, because otherwise pushing into plugins	// changes the original options.plugins array, causing duplicate plugins	const plugins = (options.plugins && options.plugins.slice()) || [];	// A list of main fields in description files	let mainFields = options.mainFields || ["main"];	// A list of alias fields in description files	const aliasFields = options.aliasFields || [];	// A list of main files in directories	const mainFiles = options.mainFiles || ["index"];	// A list of extensions which should be tried for files	let extensions = options.extensions || [".js", ".json", ".node"];	// Enforce that a extension from extensions must be used	const enforceExtension = options.enforceExtension || false;	// A list of module extensions which should be tried for modules	let moduleExtensions = options.moduleExtensions || [];	// Enforce that a extension from moduleExtensions must be used	const enforceModuleExtension = options.enforceModuleExtension || false;	// A list of module alias configurations or an object which maps key to value	let alias = options.alias || [];	// Resolve symlinks to their symlinked location	const symlinks =		typeof options.symlinks !== "undefined" ? options.symlinks : true;	// Resolve to a context instead of a file	const resolveToContext = options.resolveToContext || false;	// A list of root paths	const roots = options.roots || [];	// Ignore errors happening when resolving roots	const ignoreRootsErrors = options.ignoreRootsErrors || false;	// Prefer to resolve server-relative urls as absolute paths before falling back to resolve in roots	const preferAbsolute = options.preferAbsolute || false;	const restrictions = options.restrictions || [];	// Use this cache object to unsafely cache the successful requests	let unsafeCache = options.unsafeCache || false;	// Whether or not the unsafeCache should include request context as part of the cache key.	const cacheWithContext =		typeof options.cacheWithContext !== "undefined"			? options.cacheWithContext			: true;	// Enable concord description file instructions	const enableConcord = options.concord || false;	// A function which decides whether a request should be cached or not.	// an object is passed with `path` and `request` properties.	const cachePredicate =		options.cachePredicate ||		function() {			return true;		};	// The file system which should be used	const fileSystem = options.fileSystem;	// Use only the sync constiants of the file system calls	const useSyncFileSystemCalls = options.useSyncFileSystemCalls;	// A prepared Resolver to which the plugins are attached	let resolver = options.resolver;	//// options processing ////	if (!resolver) {		resolver = new Resolver(			useSyncFileSystemCalls				? new SyncAsyncFileSystemDecorator(fileSystem)				: fileSystem		);	}	extensions = [].concat(extensions);	moduleExtensions = [].concat(moduleExtensions);	modules = mergeFilteredToArray([].concat(modules), item => {		return !isAbsolutePath(item);	});	mainFields = mainFields.map(item => {		if (typeof item === "string" || Array.isArray(item)) {			item = {				name: item,				forceRelative: true			};		}		return item;	});	if (typeof alias === "object" && !Array.isArray(alias)) {		alias = Object.keys(alias).map(key => {			let onlyModule = false;			let obj = alias[key];			if (/\$$/.test(key)) {				onlyModule = true;				key = key.substr(0, key.length - 1);			}			if (typeof obj === "string") {				obj = {					alias: obj				};			}			obj = Object.assign(				{					name: key,					onlyModule: onlyModule				},				obj			);			return obj;		});	}	if (unsafeCache && typeof unsafeCache !== "object") {		unsafeCache = {};	}	//// pipeline ////	resolver.ensureHook("resolve");	resolver.ensureHook("parsedResolve");	resolver.ensureHook("describedResolve");	resolver.ensureHook("rawModule");	resolver.ensureHook("module");	resolver.ensureHook("relative");	resolver.ensureHook("describedRelative");	resolver.ensureHook("directory");	resolver.ensureHook("existingDirectory");	resolver.ensureHook("undescribedRawFile");	resolver.ensureHook("rawFile");	resolver.ensureHook("file");	resolver.ensureHook("existingFile");	resolver.ensureHook("resolved");	// resolve	if (unsafeCache) {		plugins.push(			new UnsafeCachePlugin(				"resolve",				cachePredicate,				unsafeCache,				cacheWithContext,				"new-resolve"			)		);		plugins.push(new ParsePlugin("new-resolve", "parsed-resolve"));	} else {		plugins.push(new ParsePlugin("resolve", "parsed-resolve"));	}	// parsed-resolve	plugins.push(		new DescriptionFilePlugin(			"parsed-resolve",			descriptionFiles,			"described-resolve"		)	);	plugins.push(new NextPlugin("after-parsed-resolve", "described-resolve"));	// described-resolve	if (alias.length > 0)		plugins.push(new AliasPlugin("described-resolve", alias, "resolve"));	if (enableConcord) {		plugins.push(new ConcordModulesPlugin("described-resolve", {}, "resolve"));	}	aliasFields.forEach(item => {		plugins.push(new AliasFieldPlugin("described-resolve", item, "resolve"));	});	plugins.push(new ModuleKindPlugin("after-described-resolve", "raw-module"));	if (preferAbsolute) {		plugins.push(new JoinRequestPlugin("after-described-resolve", "relative"));	}	roots.forEach(root => {		plugins.push(			new RootPlugin(				"after-described-resolve",				root,				"relative",				ignoreRootsErrors			)		);	});	if (!preferAbsolute) {		plugins.push(new JoinRequestPlugin("after-described-resolve", "relative"));	}	// raw-module	moduleExtensions.forEach(item => {		plugins.push(new ModuleAppendPlugin("raw-module", item, "module"));	});	if (!enforceModuleExtension)		plugins.push(new TryNextPlugin("raw-module", null, "module"));	// module	modules.forEach(item => {		if (Array.isArray(item))			plugins.push(				new ModulesInHierachicDirectoriesPlugin("module", item, "resolve")			);		else plugins.push(new ModulesInRootPlugin("module", item, "resolve"));	});	// relative	plugins.push(		new DescriptionFilePlugin(			"relative",			descriptionFiles,			"described-relative"		)	);	plugins.push(new NextPlugin("after-relative", "described-relative"));	// described-relative	plugins.push(new FileKindPlugin("described-relative", "raw-file"));	plugins.push(		new TryNextPlugin("described-relative", "as directory", "directory")	);	// directory	plugins.push(new DirectoryExistsPlugin("directory", "existing-directory"));	if (resolveToContext) {		// existing-directory		plugins.push(new NextPlugin("existing-directory", "resolved"));	} else {		// existing-directory		if (enableConcord) {			plugins.push(new ConcordMainPlugin("existing-directory", {}, "resolve"));		}		mainFields.forEach(item => {			plugins.push(new MainFieldPlugin("existing-directory", item, "resolve"));		});		mainFiles.forEach(item => {			plugins.push(				new UseFilePlugin("existing-directory", item, "undescribed-raw-file")			);		});		// undescribed-raw-file		plugins.push(			new DescriptionFilePlugin(				"undescribed-raw-file",				descriptionFiles,				"raw-file"			)		);		plugins.push(new NextPlugin("after-undescribed-raw-file", "raw-file"));		// raw-file		if (!enforceExtension) {			plugins.push(new TryNextPlugin("raw-file", "no extension", "file"));		}		if (enableConcord) {			plugins.push(new ConcordExtensionsPlugin("raw-file", {}, "file"));		}		extensions.forEach(item => {			plugins.push(new AppendPlugin("raw-file", item, "file"));		});		// file		if (alias.length > 0)			plugins.push(new AliasPlugin("file", alias, "resolve"));		if (enableConcord) {			plugins.push(new ConcordModulesPlugin("file", {}, "resolve"));		}		aliasFields.forEach(item => {			plugins.push(new AliasFieldPlugin("file", item, "resolve"));		});		if (symlinks) plugins.push(new SymlinkPlugin("file", "relative"));		plugins.push(new FileExistsPlugin("file", "existing-file"));		// existing-file		plugins.push(new NextPlugin("existing-file", "resolved"));	}	// resolved	if (restrictions.length > 0) {		plugins.push(new RestrictionsPlugin(resolver.hooks.resolved, restrictions));	}	plugins.push(new ResultPlugin(resolver.hooks.resolved));	//// RESOLVER ////	plugins.forEach(plugin => {		plugin.apply(resolver);	});	return resolver;};function mergeFilteredToArray(array, filter) {	return array.reduce((array, item) => {		if (filter(item)) {			const lastElement = array[array.length - 1];			if (Array.isArray(lastElement)) {				lastElement.push(item);			} else {				array.push([item]);			}			return array;		} else {			array.push(item);			return array;		}	}, []);}function isAbsolutePath(path) {	return /^[A-Z]:|^\//.test(path);}
 |