| /* | 
|     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); | 
| } |