create project
This commit is contained in:
500
kitabcitab/node_modules/enhanced-resolve/lib/Resolver.js
generated
vendored
Normal file
500
kitabcitab/node_modules/enhanced-resolve/lib/Resolver.js
generated
vendored
Normal file
@@ -0,0 +1,500 @@
|
||||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const { AsyncSeriesBailHook, AsyncSeriesHook, SyncHook } = require("tapable");
|
||||
const createInnerContext = require("./createInnerContext");
|
||||
const { parseIdentifier } = require("./util/identifier");
|
||||
const {
|
||||
normalize,
|
||||
cachedJoin: join,
|
||||
getType,
|
||||
PathType
|
||||
} = require("./util/path");
|
||||
|
||||
/** @typedef {import("./ResolverFactory").ResolveOptions} ResolveOptions */
|
||||
|
||||
/**
|
||||
* @typedef {Object} FileSystemStats
|
||||
* @property {function(): boolean} isDirectory
|
||||
* @property {function(): boolean} isFile
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} FileSystemDirent
|
||||
* @property {Buffer | string} name
|
||||
* @property {function(): boolean} isDirectory
|
||||
* @property {function(): boolean} isFile
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} PossibleFileSystemError
|
||||
* @property {string=} code
|
||||
* @property {number=} errno
|
||||
* @property {string=} path
|
||||
* @property {string=} syscall
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @callback FileSystemCallback
|
||||
* @param {PossibleFileSystemError & Error | null | undefined} err
|
||||
* @param {T=} result
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} FileSystem
|
||||
* @property {(function(string, FileSystemCallback<Buffer | string>): void) & function(string, object, FileSystemCallback<Buffer | string>): void} readFile
|
||||
* @property {(function(string, FileSystemCallback<(Buffer | string)[] | FileSystemDirent[]>): void) & function(string, object, FileSystemCallback<(Buffer | string)[] | FileSystemDirent[]>): void} readdir
|
||||
* @property {((function(string, FileSystemCallback<object>): void) & function(string, object, FileSystemCallback<object>): void)=} readJson
|
||||
* @property {(function(string, FileSystemCallback<Buffer | string>): void) & function(string, object, FileSystemCallback<Buffer | string>): void} readlink
|
||||
* @property {(function(string, FileSystemCallback<FileSystemStats>): void) & function(string, object, FileSystemCallback<Buffer | string>): void=} lstat
|
||||
* @property {(function(string, FileSystemCallback<FileSystemStats>): void) & function(string, object, FileSystemCallback<Buffer | string>): void} stat
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SyncFileSystem
|
||||
* @property {function(string, object=): Buffer | string} readFileSync
|
||||
* @property {function(string, object=): (Buffer | string)[] | FileSystemDirent[]} readdirSync
|
||||
* @property {(function(string, object=): object)=} readJsonSync
|
||||
* @property {function(string, object=): Buffer | string} readlinkSync
|
||||
* @property {function(string, object=): FileSystemStats=} lstatSync
|
||||
* @property {function(string, object=): FileSystemStats} statSync
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} ParsedIdentifier
|
||||
* @property {string} request
|
||||
* @property {string} query
|
||||
* @property {string} fragment
|
||||
* @property {boolean} directory
|
||||
* @property {boolean} module
|
||||
* @property {boolean} file
|
||||
* @property {boolean} internal
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} BaseResolveRequest
|
||||
* @property {string | false} path
|
||||
* @property {string=} descriptionFilePath
|
||||
* @property {string=} descriptionFileRoot
|
||||
* @property {object=} descriptionFileData
|
||||
* @property {string=} relativePath
|
||||
* @property {boolean=} ignoreSymlinks
|
||||
* @property {boolean=} fullySpecified
|
||||
*/
|
||||
|
||||
/** @typedef {BaseResolveRequest & Partial<ParsedIdentifier>} ResolveRequest */
|
||||
|
||||
/**
|
||||
* String with special formatting
|
||||
* @typedef {string} StackEntry
|
||||
*/
|
||||
|
||||
/** @template T @typedef {{ add: (T) => void }} WriteOnlySet */
|
||||
|
||||
/**
|
||||
* Resolve context
|
||||
* @typedef {Object} ResolveContext
|
||||
* @property {WriteOnlySet<string>=} contextDependencies
|
||||
* @property {WriteOnlySet<string>=} fileDependencies files that was found on file system
|
||||
* @property {WriteOnlySet<string>=} missingDependencies dependencies that was not found on file system
|
||||
* @property {Set<StackEntry>=} stack set of hooks' calls. For instance, `resolve → parsedResolve → describedResolve`,
|
||||
* @property {(function(string): void)=} log log function
|
||||
* @property {(function (ResolveRequest): void)=} yield yield result, if provided plugins can return several results
|
||||
*/
|
||||
|
||||
/** @typedef {AsyncSeriesBailHook<[ResolveRequest, ResolveContext], ResolveRequest | null>} ResolveStepHook */
|
||||
|
||||
/**
|
||||
* @param {string} str input string
|
||||
* @returns {string} in camel case
|
||||
*/
|
||||
function toCamelCase(str) {
|
||||
return str.replace(/-([a-z])/g, str => str.substr(1).toUpperCase());
|
||||
}
|
||||
|
||||
class Resolver {
|
||||
/**
|
||||
* @param {ResolveStepHook} hook hook
|
||||
* @param {ResolveRequest} request request
|
||||
* @returns {StackEntry} stack entry
|
||||
*/
|
||||
static createStackEntry(hook, request) {
|
||||
return (
|
||||
hook.name +
|
||||
": (" +
|
||||
request.path +
|
||||
") " +
|
||||
(request.request || "") +
|
||||
(request.query || "") +
|
||||
(request.fragment || "") +
|
||||
(request.directory ? " directory" : "") +
|
||||
(request.module ? " module" : "")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {FileSystem} fileSystem a filesystem
|
||||
* @param {ResolveOptions} options options
|
||||
*/
|
||||
constructor(fileSystem, options) {
|
||||
this.fileSystem = fileSystem;
|
||||
this.options = options;
|
||||
this.hooks = {
|
||||
/** @type {SyncHook<[ResolveStepHook, ResolveRequest], void>} */
|
||||
resolveStep: new SyncHook(["hook", "request"], "resolveStep"),
|
||||
/** @type {SyncHook<[ResolveRequest, Error]>} */
|
||||
noResolve: new SyncHook(["request", "error"], "noResolve"),
|
||||
/** @type {ResolveStepHook} */
|
||||
resolve: new AsyncSeriesBailHook(
|
||||
["request", "resolveContext"],
|
||||
"resolve"
|
||||
),
|
||||
/** @type {AsyncSeriesHook<[ResolveRequest, ResolveContext]>} */
|
||||
result: new AsyncSeriesHook(["result", "resolveContext"], "result")
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string | ResolveStepHook} name hook name or hook itself
|
||||
* @returns {ResolveStepHook} the hook
|
||||
*/
|
||||
ensureHook(name) {
|
||||
if (typeof name !== "string") {
|
||||
return name;
|
||||
}
|
||||
name = toCamelCase(name);
|
||||
if (/^before/.test(name)) {
|
||||
return /** @type {ResolveStepHook} */ (this.ensureHook(
|
||||
name[6].toLowerCase() + name.substr(7)
|
||||
).withOptions({
|
||||
stage: -10
|
||||
}));
|
||||
}
|
||||
if (/^after/.test(name)) {
|
||||
return /** @type {ResolveStepHook} */ (this.ensureHook(
|
||||
name[5].toLowerCase() + name.substr(6)
|
||||
).withOptions({
|
||||
stage: 10
|
||||
}));
|
||||
}
|
||||
const hook = this.hooks[name];
|
||||
if (!hook) {
|
||||
return (this.hooks[name] = new AsyncSeriesBailHook(
|
||||
["request", "resolveContext"],
|
||||
name
|
||||
));
|
||||
}
|
||||
return hook;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string | ResolveStepHook} name hook name or hook itself
|
||||
* @returns {ResolveStepHook} the hook
|
||||
*/
|
||||
getHook(name) {
|
||||
if (typeof name !== "string") {
|
||||
return name;
|
||||
}
|
||||
name = toCamelCase(name);
|
||||
if (/^before/.test(name)) {
|
||||
return /** @type {ResolveStepHook} */ (this.getHook(
|
||||
name[6].toLowerCase() + name.substr(7)
|
||||
).withOptions({
|
||||
stage: -10
|
||||
}));
|
||||
}
|
||||
if (/^after/.test(name)) {
|
||||
return /** @type {ResolveStepHook} */ (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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} context context information object
|
||||
* @param {string} path context path
|
||||
* @param {string} request request string
|
||||
* @returns {string | false} result
|
||||
*/
|
||||
resolveSync(context, path, request) {
|
||||
/** @type {Error | null | undefined} */
|
||||
let err = undefined;
|
||||
/** @type {string | false | undefined} */
|
||||
let result = undefined;
|
||||
let 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;
|
||||
if (result === undefined) throw new Error("No result");
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} context context information object
|
||||
* @param {string} path context path
|
||||
* @param {string} request request string
|
||||
* @param {ResolveContext} resolveContext resolve context
|
||||
* @param {function(Error | null, (string|false)=, ResolveRequest=): void} callback callback function
|
||||
* @returns {void}
|
||||
*/
|
||||
resolve(context, path, request, resolveContext, callback) {
|
||||
if (!context || typeof context !== "object")
|
||||
return callback(new Error("context argument is not an object"));
|
||||
if (typeof path !== "string")
|
||||
return callback(new Error("path argument is not a string"));
|
||||
if (typeof request !== "string")
|
||||
return callback(new Error("request argument is not a string"));
|
||||
if (!resolveContext)
|
||||
return callback(new Error("resolveContext argument is not set"));
|
||||
|
||||
const obj = {
|
||||
context: context,
|
||||
path: path,
|
||||
request: request
|
||||
};
|
||||
|
||||
let yield_;
|
||||
let yieldCalled = false;
|
||||
let finishYield;
|
||||
if (typeof resolveContext.yield === "function") {
|
||||
const old = resolveContext.yield;
|
||||
yield_ = obj => {
|
||||
old(obj);
|
||||
yieldCalled = true;
|
||||
};
|
||||
finishYield = result => {
|
||||
if (result) yield_(result);
|
||||
callback(null);
|
||||
};
|
||||
}
|
||||
|
||||
const message = `resolve '${request}' in '${path}'`;
|
||||
|
||||
const finishResolved = result => {
|
||||
return callback(
|
||||
null,
|
||||
result.path === false
|
||||
? false
|
||||
: `${result.path.replace(/#/g, "\0#")}${
|
||||
result.query ? result.query.replace(/#/g, "\0#") : ""
|
||||
}${result.fragment || ""}`,
|
||||
result
|
||||
);
|
||||
};
|
||||
|
||||
const finishWithoutResolve = log => {
|
||||
/**
|
||||
* @type {Error & {details?: string}}
|
||||
*/
|
||||
const error = new Error("Can't " + message);
|
||||
error.details = log.join("\n");
|
||||
this.hooks.noResolve.call(obj, error);
|
||||
return callback(error);
|
||||
};
|
||||
|
||||
if (resolveContext.log) {
|
||||
// We need log anyway to capture it in case of an error
|
||||
const parentLog = resolveContext.log;
|
||||
const log = [];
|
||||
return this.doResolve(
|
||||
this.hooks.resolve,
|
||||
obj,
|
||||
message,
|
||||
{
|
||||
log: msg => {
|
||||
parentLog(msg);
|
||||
log.push(msg);
|
||||
},
|
||||
yield: yield_,
|
||||
fileDependencies: resolveContext.fileDependencies,
|
||||
contextDependencies: resolveContext.contextDependencies,
|
||||
missingDependencies: resolveContext.missingDependencies,
|
||||
stack: resolveContext.stack
|
||||
},
|
||||
(err, result) => {
|
||||
if (err) return callback(err);
|
||||
|
||||
if (yieldCalled || (result && yield_)) return finishYield(result);
|
||||
if (result) return finishResolved(result);
|
||||
|
||||
return finishWithoutResolve(log);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
// Try to resolve assuming there is no error
|
||||
// We don't log stuff in this case
|
||||
return this.doResolve(
|
||||
this.hooks.resolve,
|
||||
obj,
|
||||
message,
|
||||
{
|
||||
log: undefined,
|
||||
yield: yield_,
|
||||
fileDependencies: resolveContext.fileDependencies,
|
||||
contextDependencies: resolveContext.contextDependencies,
|
||||
missingDependencies: resolveContext.missingDependencies,
|
||||
stack: resolveContext.stack
|
||||
},
|
||||
(err, result) => {
|
||||
if (err) return callback(err);
|
||||
|
||||
if (yieldCalled || (result && yield_)) return finishYield(result);
|
||||
if (result) return finishResolved(result);
|
||||
|
||||
// log is missing for the error details
|
||||
// so we redo the resolving for the log info
|
||||
// this is more expensive to the success case
|
||||
// is assumed by default
|
||||
|
||||
const log = [];
|
||||
|
||||
return this.doResolve(
|
||||
this.hooks.resolve,
|
||||
obj,
|
||||
message,
|
||||
{
|
||||
log: msg => log.push(msg),
|
||||
yield: yield_,
|
||||
stack: resolveContext.stack
|
||||
},
|
||||
(err, result) => {
|
||||
if (err) return callback(err);
|
||||
|
||||
// In a case that there is a race condition and yield will be called
|
||||
if (yieldCalled || (result && yield_)) return finishYield(result);
|
||||
|
||||
return finishWithoutResolve(log);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
doResolve(hook, request, message, resolveContext, callback) {
|
||||
const stackEntry = Resolver.createStackEntry(hook, request);
|
||||
|
||||
let newStack;
|
||||
if (resolveContext.stack) {
|
||||
newStack = new Set(resolveContext.stack);
|
||||
if (resolveContext.stack.has(stackEntry)) {
|
||||
/**
|
||||
* Prevent recursion
|
||||
* @type {Error & {recursion?: boolean}}
|
||||
*/
|
||||
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(stackEntry);
|
||||
} else {
|
||||
newStack = new Set([stackEntry]);
|
||||
}
|
||||
this.hooks.resolveStep.call(hook, request);
|
||||
|
||||
if (hook.isUsed()) {
|
||||
const innerContext = createInnerContext(
|
||||
{
|
||||
log: resolveContext.log,
|
||||
yield: resolveContext.yield,
|
||||
fileDependencies: resolveContext.fileDependencies,
|
||||
contextDependencies: resolveContext.contextDependencies,
|
||||
missingDependencies: resolveContext.missingDependencies,
|
||||
stack: newStack
|
||||
},
|
||||
message
|
||||
);
|
||||
return hook.callAsync(request, innerContext, (err, result) => {
|
||||
if (err) return callback(err);
|
||||
if (result) return callback(null, result);
|
||||
callback();
|
||||
});
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} identifier identifier
|
||||
* @returns {ParsedIdentifier} parsed identifier
|
||||
*/
|
||||
parse(identifier) {
|
||||
const part = {
|
||||
request: "",
|
||||
query: "",
|
||||
fragment: "",
|
||||
module: false,
|
||||
directory: false,
|
||||
file: false,
|
||||
internal: false
|
||||
};
|
||||
|
||||
const parsedIdentifier = parseIdentifier(identifier);
|
||||
|
||||
if (!parsedIdentifier) return part;
|
||||
|
||||
[part.request, part.query, part.fragment] = parsedIdentifier;
|
||||
|
||||
if (part.request.length > 0) {
|
||||
part.internal = this.isPrivate(identifier);
|
||||
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 getType(path) === PathType.Normal;
|
||||
}
|
||||
|
||||
isPrivate(path) {
|
||||
return getType(path) === PathType.Internal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} path a path
|
||||
* @returns {boolean} true, if the path is a directory path
|
||||
*/
|
||||
isDirectory(path) {
|
||||
return path.endsWith("/");
|
||||
}
|
||||
|
||||
join(path, request) {
|
||||
return join(path, request);
|
||||
}
|
||||
|
||||
normalize(path) {
|
||||
return normalize(path);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Resolver;
|
||||
Reference in New Issue
Block a user