summaryrefslogtreecommitdiffstats
path: root/node_modules/enhanced-resolve/lib/Resolver.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/enhanced-resolve/lib/Resolver.js')
-rw-r--r--node_modules/enhanced-resolve/lib/Resolver.js347
1 files changed, 347 insertions, 0 deletions
diff --git a/node_modules/enhanced-resolve/lib/Resolver.js b/node_modules/enhanced-resolve/lib/Resolver.js
new file mode 100644
index 0000000..442030d
--- /dev/null
+++ b/node_modules/enhanced-resolve/lib/Resolver.js
@@ -0,0 +1,347 @@
+/*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Tobias Koppers @sokra
+*/
+"use strict";
+
+const util = require("util");
+
+const Tapable = require("tapable/lib/Tapable");
+const SyncHook = require("tapable/lib/SyncHook");
+const AsyncSeriesBailHook = require("tapable/lib/AsyncSeriesBailHook");
+const AsyncSeriesHook = require("tapable/lib/AsyncSeriesHook");
+const createInnerContext = require("./createInnerContext");
+
+const REGEXP_NOT_MODULE = /^\.$|^\.[\\/]|^\.\.$|^\.\.[\\/]|^\/|^[A-Z]:[\\/]/i;
+const REGEXP_DIRECTORY = /[\\/]$/i;
+
+const memoryFsJoin = require("memory-fs/lib/join");
+const memoizedJoin = new Map();
+const memoryFsNormalize = require("memory-fs/lib/normalize");
+
+function withName(name, hook) {
+ hook.name = name;
+ return hook;
+}
+
+function toCamelCase(str) {
+ return str.replace(/-([a-z])/g, str => str.substr(1).toUpperCase());
+}
+
+const deprecatedPushToMissing = util.deprecate((set, item) => {
+ set.add(item);
+}, "Resolver: 'missing' is now a Set. Use add instead of push.");
+
+const deprecatedResolveContextInCallback = util.deprecate(x => {
+ return x;
+}, "Resolver: The callback argument was splitted into resolveContext and callback.");
+
+const deprecatedHookAsString = util.deprecate(x => {
+ return x;
+}, "Resolver#doResolve: The type arguments (string) is now a hook argument (Hook). Pass a reference to the hook instead.");
+
+class Resolver extends Tapable {
+ constructor(fileSystem) {
+ super();
+ this.fileSystem = fileSystem;
+ this.hooks = {
+ resolveStep: withName("resolveStep", new SyncHook(["hook", "request"])),
+ noResolve: withName("noResolve", new SyncHook(["request", "error"])),
+ resolve: withName(
+ "resolve",
+ new AsyncSeriesBailHook(["request", "resolveContext"])
+ ),
+ result: new AsyncSeriesHook(["result", "resolveContext"])
+ };
+ this._pluginCompat.tap("Resolver: before/after", options => {
+ if (/^before-/.test(options.name)) {
+ options.name = options.name.substr(7);
+ options.stage = -10;
+ } else if (/^after-/.test(options.name)) {
+ options.name = options.name.substr(6);
+ options.stage = 10;
+ }
+ });
+ this._pluginCompat.tap("Resolver: step hooks", options => {
+ const name = options.name;
+ const stepHook = !/^resolve(-s|S)tep$|^no(-r|R)esolve$/.test(name);
+ if (stepHook) {
+ options.async = true;
+ this.ensureHook(name);
+ const fn = options.fn;
+ options.fn = (request, resolverContext, callback) => {
+ const innerCallback = (err, result) => {
+ if (err) return callback(err);
+ if (result !== undefined) return callback(null, result);
+ callback();
+ };
+ for (const key in resolverContext) {
+ innerCallback[key] = resolverContext[key];
+ }
+ fn.call(this, request, innerCallback);
+ };
+ }
+ });
+ }
+
+ ensureHook(name) {
+ if (typeof name !== "string") return name;
+ name = toCamelCase(name);
+ if (/^before/.test(name)) {
+ return this.ensureHook(
+ name[6].toLowerCase() + name.substr(7)
+ ).withOptions({
+ stage: -10
+ });
+ }
+ if (/^after/.test(name)) {
+ return this.ensureHook(
+ name[5].toLowerCase() + name.substr(6)
+ ).withOptions({
+ stage: 10
+ });
+ }
+ const hook = this.hooks[name];
+ if (!hook) {
+ return (this.hooks[name] = withName(
+ name,
+ new AsyncSeriesBailHook(["request", "resolveContext"])
+ ));
+ }
+ return hook;
+ }
+
+ getHook(name) {
+ if (typeof name !== "string") return name;
+ name = toCamelCase(name);
+ if (/^before/.test(name)) {
+ return this.getHook(name[6].toLowerCase() + name.substr(7)).withOptions({
+ stage: -10
+ });
+ }
+ if (/^after/.test(name)) {
+ return this.getHook(name[5].toLowerCase() + name.substr(6)).withOptions({
+ stage: 10
+ });
+ }
+ const hook = this.hooks[name];
+ if (!hook) {
+ throw new Error(`Hook ${name} doesn't exist`);
+ }
+ return hook;
+ }
+
+ resolveSync(context, path, request) {
+ let err,
+ result,
+ sync = false;
+ this.resolve(context, path, request, {}, (e, r) => {
+ err = e;
+ result = r;
+ sync = true;
+ });
+ if (!sync)
+ throw new Error(
+ "Cannot 'resolveSync' because the fileSystem is not sync. Use 'resolve'!"
+ );
+ if (err) throw err;
+ return result;
+ }
+
+ resolve(context, path, request, resolveContext, callback) {
+ // TODO remove in enhanced-resolve 5
+ // For backward compatiblity START
+ if (typeof callback !== "function") {
+ callback = deprecatedResolveContextInCallback(resolveContext);
+ // resolveContext is a function containing additional properties
+ // It's now used for resolveContext and callback
+ }
+ // END
+ const obj = {
+ context: context,
+ path: path,
+ request: request
+ };
+
+ const message = "resolve '" + request + "' in '" + path + "'";
+
+ // Try to resolve assuming there is no error
+ // We don't log stuff in this case
+ return this.doResolve(
+ this.hooks.resolve,
+ obj,
+ message,
+ {
+ missing: resolveContext.missing,
+ stack: resolveContext.stack
+ },
+ (err, result) => {
+ if (!err && result) {
+ return callback(
+ null,
+ result.path === false ? false : result.path + (result.query || ""),
+ result
+ );
+ }
+
+ const localMissing = new Set();
+ // TODO remove in enhanced-resolve 5
+ localMissing.push = item => deprecatedPushToMissing(localMissing, item);
+ const log = [];
+
+ return this.doResolve(
+ this.hooks.resolve,
+ obj,
+ message,
+ {
+ log: msg => {
+ if (resolveContext.log) {
+ resolveContext.log(msg);
+ }
+ log.push(msg);
+ },
+ missing: localMissing,
+ stack: resolveContext.stack
+ },
+ (err, result) => {
+ if (err) return callback(err);
+
+ const error = new Error("Can't " + message);
+ error.details = log.join("\n");
+ error.missing = Array.from(localMissing);
+ this.hooks.noResolve.call(obj, error);
+ return callback(error);
+ }
+ );
+ }
+ );
+ }
+
+ doResolve(hook, request, message, resolveContext, callback) {
+ // TODO remove in enhanced-resolve 5
+ // For backward compatiblity START
+ if (typeof callback !== "function") {
+ callback = deprecatedResolveContextInCallback(resolveContext);
+ // resolveContext is a function containing additional properties
+ // It's now used for resolveContext and callback
+ }
+ if (typeof hook === "string") {
+ const name = toCamelCase(hook);
+ hook = deprecatedHookAsString(this.hooks[name]);
+ if (!hook) {
+ throw new Error(`Hook "${name}" doesn't exist`);
+ }
+ }
+ // END
+ if (typeof callback !== "function")
+ throw new Error("callback is not a function " + Array.from(arguments));
+ if (!resolveContext)
+ throw new Error(
+ "resolveContext is not an object " + Array.from(arguments)
+ );
+
+ const stackLine =
+ hook.name +
+ ": (" +
+ request.path +
+ ") " +
+ (request.request || "") +
+ (request.query || "") +
+ (request.directory ? " directory" : "") +
+ (request.module ? " module" : "");
+
+ let newStack;
+ if (resolveContext.stack) {
+ newStack = new Set(resolveContext.stack);
+ if (resolveContext.stack.has(stackLine)) {
+ // Prevent recursion
+ const recursionError = new Error(
+ "Recursion in resolving\nStack:\n " +
+ Array.from(newStack).join("\n ")
+ );
+ recursionError.recursion = true;
+ if (resolveContext.log)
+ resolveContext.log("abort resolving because of recursion");
+ return callback(recursionError);
+ }
+ newStack.add(stackLine);
+ } else {
+ newStack = new Set([stackLine]);
+ }
+ this.hooks.resolveStep.call(hook, request);
+
+ if (hook.isUsed()) {
+ const innerContext = createInnerContext(
+ {
+ log: resolveContext.log,
+ missing: resolveContext.missing,
+ stack: newStack
+ },
+ message
+ );
+ return hook.callAsync(request, innerContext, (err, result) => {
+ if (err) return callback(err);
+ if (result) return callback(null, result);
+ callback();
+ });
+ } else {
+ callback();
+ }
+ }
+
+ parse(identifier) {
+ if (identifier === "") return null;
+ const part = {
+ request: "",
+ query: "",
+ module: false,
+ directory: false,
+ file: false
+ };
+ const idxQuery = identifier.indexOf("?");
+ if (idxQuery === 0) {
+ part.query = identifier;
+ } else if (idxQuery > 0) {
+ part.request = identifier.slice(0, idxQuery);
+ part.query = identifier.slice(idxQuery);
+ } else {
+ part.request = identifier;
+ }
+ if (part.request) {
+ part.module = this.isModule(part.request);
+ part.directory = this.isDirectory(part.request);
+ if (part.directory) {
+ part.request = part.request.substr(0, part.request.length - 1);
+ }
+ }
+ return part;
+ }
+
+ isModule(path) {
+ return !REGEXP_NOT_MODULE.test(path);
+ }
+
+ isDirectory(path) {
+ return REGEXP_DIRECTORY.test(path);
+ }
+
+ join(path, request) {
+ let cacheEntry;
+ let pathCache = memoizedJoin.get(path);
+ if (typeof pathCache === "undefined") {
+ memoizedJoin.set(path, (pathCache = new Map()));
+ } else {
+ cacheEntry = pathCache.get(request);
+ if (typeof cacheEntry !== "undefined") return cacheEntry;
+ }
+ cacheEntry = memoryFsJoin(path, request);
+ pathCache.set(request, cacheEntry);
+ return cacheEntry;
+ }
+
+ normalize(path) {
+ return memoryFsNormalize(path);
+ }
+}
+
+module.exports = Resolver;