enhanced-resolve
Advanced tools
Comparing version 5.0.0-beta.4 to 5.0.0-beta.5
@@ -5,2 +5,3 @@ /* | ||
*/ | ||
"use strict"; | ||
@@ -11,3 +12,12 @@ | ||
/** @typedef {import("./Resolver")} Resolver */ | ||
/** @typedef {import("./Resolver").ResolveRequest} ResolveRequest */ | ||
/** @typedef {import("./Resolver").ResolveStepHook} ResolveStepHook */ | ||
module.exports = class AliasFieldPlugin { | ||
/** | ||
* @param {string | ResolveStepHook} source source | ||
* @param {string | Array<string>} field field | ||
* @param {string | ResolveStepHook} target target | ||
*/ | ||
constructor(source, field, target) { | ||
@@ -19,2 +29,6 @@ this.source = source; | ||
/** | ||
* @param {Resolver} resolver the resolver | ||
* @returns {void} | ||
*/ | ||
apply(resolver) { | ||
@@ -32,3 +46,3 @@ const target = resolver.ensureHook(this.target); | ||
); | ||
if (typeof fieldData !== "object") { | ||
if (fieldData === null || typeof fieldData !== "object") { | ||
if (resolveContext.log) | ||
@@ -48,2 +62,3 @@ resolveContext.log( | ||
if (data === false) { | ||
/** @type {ResolveRequest} */ | ||
const ignoreObj = { | ||
@@ -50,0 +65,0 @@ ...request, |
@@ -5,2 +5,3 @@ /* | ||
*/ | ||
"use strict"; | ||
@@ -10,3 +11,12 @@ | ||
/** @typedef {import("./Resolver")} Resolver */ | ||
/** @typedef {import("./Resolver").ResolveStepHook} ResolveStepHook */ | ||
/** @typedef {{alias: string|Array<string>|false, name: string, onlyModule?: boolean}} AliasOption */ | ||
module.exports = class AliasPlugin { | ||
/** | ||
* @param {string | ResolveStepHook} source source | ||
* @param {AliasOption | Array<AliasOption>} options options | ||
* @param {string | ResolveStepHook} target target | ||
*/ | ||
constructor(source, options, target) { | ||
@@ -18,2 +28,6 @@ this.source = source; | ||
/** | ||
* @param {Resolver} resolver the resolver | ||
* @returns {void} | ||
*/ | ||
apply(resolver) { | ||
@@ -20,0 +34,0 @@ const target = resolver.ensureHook(this.target); |
@@ -5,5 +5,14 @@ /* | ||
*/ | ||
"use strict"; | ||
/** @typedef {import("./Resolver")} Resolver */ | ||
/** @typedef {import("./Resolver").ResolveStepHook} ResolveStepHook */ | ||
module.exports = class AppendPlugin { | ||
/** | ||
* @param {string | ResolveStepHook} source source | ||
* @param {string} appending appending | ||
* @param {string | ResolveStepHook} target target | ||
*/ | ||
constructor(source, appending, target) { | ||
@@ -15,2 +24,6 @@ this.source = source; | ||
/** | ||
* @param {Resolver} resolver the resolver | ||
* @returns {void} | ||
*/ | ||
apply(resolver) { | ||
@@ -17,0 +30,0 @@ const target = resolver.ensureHook(this.target); |
@@ -5,4 +5,7 @@ /* | ||
*/ | ||
"use strict"; | ||
const { clearInterval, setInterval } = require("timers"); | ||
const dirname = path => { | ||
@@ -41,2 +44,3 @@ let idx = path.length - 1; | ||
this.count = 0; | ||
/** @type {NodeJS.Timeout | null} */ | ||
this.interval = null; | ||
@@ -141,3 +145,6 @@ this.needTickCheck = false; | ||
if (this.count === 0) { | ||
clearInterval(this.interval); | ||
if (this.interval) { | ||
clearInterval(this.interval); | ||
} | ||
this.interval = null; | ||
@@ -158,3 +165,6 @@ this.nextTick = null; | ||
} else if (this.passive) { | ||
clearInterval(this.interval); | ||
if (this.interval) { | ||
clearInterval(this.interval); | ||
} | ||
this.interval = null; | ||
@@ -178,3 +188,6 @@ this.nextTick = | ||
this.count = 0; | ||
clearInterval(this.interval); | ||
if (this.interval) { | ||
clearInterval(this.interval); | ||
} | ||
this.nextTick = null; | ||
@@ -199,3 +212,5 @@ this.data.clear(); | ||
this.count = 0; | ||
clearInterval(this.interval); | ||
if (this.interval) { | ||
clearInterval(this.interval); | ||
} | ||
this.nextTick = null; | ||
@@ -231,3 +246,3 @@ this.data.clear(); | ||
: null; | ||
if (!this._stat) this.stat = null; | ||
if (!this._stat) this.stat = /** @type {any} */ (null); | ||
@@ -237,3 +252,3 @@ this._statSync = this.fileSystem.statSync | ||
: null; | ||
if (!this._statSync) this.statSync = null; | ||
if (!this._statSync) this.statSync = /** @type {any} */ (null); | ||
@@ -243,3 +258,3 @@ this._readdir = this.fileSystem.readdir | ||
: null; | ||
if (!this._readdir) this.readdir = null; | ||
if (!this._readdir) this.readdir = /** @type {any} */ (null); | ||
@@ -249,3 +264,3 @@ this._readdirSync = this.fileSystem.readdirSync | ||
: null; | ||
if (!this._readdirSync) this.readdirSync = null; | ||
if (!this._readdirSync) this.readdirSync = /** @type {any} */ (null); | ||
@@ -255,3 +270,3 @@ this._readFile = this.fileSystem.readFile | ||
: null; | ||
if (!this._readFile) this.readFile = null; | ||
if (!this._readFile) this.readFile = /** @type {any} */ (null); | ||
@@ -261,3 +276,3 @@ this._readFileSync = this.fileSystem.readFileSync | ||
: null; | ||
if (!this._readFileSync) this.readFileSync = null; | ||
if (!this._readFileSync) this.readFileSync = /** @type {any} */ (null); | ||
@@ -280,3 +295,3 @@ if (this.fileSystem.readJson) { | ||
} else { | ||
this.readJson = null; | ||
this.readJson = /** @type {any} */ (null); | ||
} | ||
@@ -292,3 +307,3 @@ if (this.fileSystem.readJsonSync) { | ||
} else { | ||
this.readJsonSync = null; | ||
this.readJsonSync = /** @type {any} */ (null); | ||
} | ||
@@ -299,3 +314,3 @@ | ||
: null; | ||
if (!this._readlink) this.readlink = null; | ||
if (!this._readlink) this.readlink = /** @type {any} */ (null); | ||
@@ -305,3 +320,3 @@ this._readlinkSync = this.fileSystem.readlinkSync | ||
: null; | ||
if (!this._readlinkSync) this.readlinkSync = null; | ||
if (!this._readlinkSync) this.readlinkSync = /** @type {any} */ (null); | ||
} | ||
@@ -308,0 +323,0 @@ |
@@ -5,2 +5,3 @@ /* | ||
*/ | ||
"use strict"; | ||
@@ -10,2 +11,4 @@ | ||
/** @typedef {import("./Resolver")} Resolver */ | ||
module.exports = class CloneBasenamePlugin { | ||
@@ -17,2 +20,6 @@ constructor(source, target) { | ||
/** | ||
* @param {Resolver} resolver the resolver | ||
* @returns {void} | ||
*/ | ||
apply(resolver) { | ||
@@ -19,0 +26,0 @@ const target = resolver.ensureHook(this.target); |
@@ -5,2 +5,3 @@ /* | ||
*/ | ||
"use strict"; | ||
@@ -7,0 +8,0 @@ |
/* | ||
MIT License http://www.opensource.org/licenses/mit-license.php | ||
Author Tobias Koppers @sokra | ||
MIT License http://www.opensource.org/licenses/mit-license.php | ||
Author Tobias Koppers @sokra | ||
*/ | ||
"use strict"; | ||
@@ -9,6 +10,15 @@ | ||
/** @typedef {import("./Resolver")} Resolver */ | ||
/** @typedef {import("./Resolver").ResolveStepHook} ResolveStepHook */ | ||
module.exports = class DescriptionFilePlugin { | ||
/** | ||
* @param {string | ResolveStepHook} source source | ||
* @param {string[]} filenames filenames | ||
* @param {boolean} pathIsFile pathIsFile | ||
* @param {string | ResolveStepHook} target target | ||
*/ | ||
constructor(source, filenames, pathIsFile, target) { | ||
this.source = source; | ||
this.filenames = [].concat(filenames); | ||
this.filenames = filenames; | ||
this.pathIsFile = pathIsFile; | ||
@@ -18,2 +28,6 @@ this.target = target; | ||
/** | ||
* @param {Resolver} resolver the resolver | ||
* @returns {void} | ||
*/ | ||
apply(resolver) { | ||
@@ -26,5 +40,7 @@ const target = resolver.ensureHook(this.target); | ||
(request, resolveContext, callback) => { | ||
const path = request.path; | ||
if (!path) return callback(); | ||
const directory = this.pathIsFile | ||
? DescriptionFileUtils.cdUp(request.path) | ||
: request.path; | ||
? DescriptionFileUtils.cdUp(path) | ||
: path; | ||
if (!directory) return callback(); | ||
@@ -35,7 +51,9 @@ DescriptionFileUtils.loadDescriptionFile( | ||
this.filenames, | ||
request.descriptionFilePath && { | ||
path: request.descriptionFilePath, | ||
content: request.descriptionFileData, | ||
directory: request.descriptionFileRoot | ||
}, | ||
request.descriptionFilePath | ||
? { | ||
path: request.descriptionFilePath, | ||
content: request.descriptionFileData, | ||
directory: /** @type {string} */ (request.descriptionFileRoot) | ||
} | ||
: undefined, | ||
resolveContext, | ||
@@ -52,6 +70,3 @@ (err, result) => { | ||
const relativePath = | ||
"." + | ||
request.path | ||
.substr(result.directory.length) | ||
.replace(/\\/g, "/"); | ||
"." + path.substr(result.directory.length).replace(/\\/g, "/"); | ||
const obj = { | ||
@@ -58,0 +73,0 @@ ...request, |
@@ -5,2 +5,3 @@ /* | ||
*/ | ||
"use strict"; | ||
@@ -10,2 +11,26 @@ | ||
/** @typedef {import("./Resolver")} Resolver */ | ||
/** @typedef {import("./Resolver").ResolveContext} ResolveContext */ | ||
/** | ||
* @typedef {Object} DescriptionFileInfo | ||
* @property {any=} content | ||
* @property {string} path | ||
* @property {string} directory | ||
*/ | ||
/** | ||
* @callback ErrorFirstCallback | ||
* @param {Error|null=} error | ||
* @param {DescriptionFileInfo=} result | ||
*/ | ||
/** | ||
* @param {Resolver} resolver resolver | ||
* @param {string} directory directory | ||
* @param {string[]} filenames filenames | ||
* @param {DescriptionFileInfo|undefined} oldInfo oldInfo | ||
* @param {ResolveContext} resolveContext resolveContext | ||
* @param {ErrorFirstCallback} callback callback | ||
*/ | ||
function loadDescriptionFile( | ||
@@ -59,7 +84,13 @@ resolver, | ||
let json; | ||
try { | ||
json = JSON.parse(content); | ||
} catch (e) { | ||
onJson(e); | ||
if (content) { | ||
try { | ||
json = JSON.parse(content.toString()); | ||
} catch (e) { | ||
return onJson(e); | ||
} | ||
} else { | ||
return onJson(new Error("No content in file")); | ||
} | ||
onJson(null, json); | ||
@@ -81,4 +112,4 @@ }); | ||
callback(null, { | ||
content: content, | ||
directory: directory, | ||
content, | ||
directory, | ||
path: descriptionFilePath | ||
@@ -93,6 +124,7 @@ }); | ||
} else { | ||
directory = cdUp(directory); | ||
if (!directory) { | ||
const dir = cdUp(directory); | ||
if (!dir) { | ||
return callback(); | ||
} else { | ||
directory = dir; | ||
return findDescriptionFile(); | ||
@@ -106,2 +138,7 @@ } | ||
/** | ||
* @param {any} content content | ||
* @param {string|string[]} field field | ||
* @returns {object|string|number|boolean|undefined} field data | ||
*/ | ||
function getField(content, field) { | ||
@@ -118,12 +155,12 @@ if (!content) return undefined; | ||
} | ||
if (typeof current === "object") { | ||
return current; | ||
} | ||
return current; | ||
} else { | ||
if (typeof content[field] === "object") { | ||
return content[field]; | ||
} | ||
return content[field]; | ||
} | ||
} | ||
/** | ||
* @param {string} directory directory | ||
* @returns {string|null} parent directory or null | ||
*/ | ||
function cdUp(directory) { | ||
@@ -130,0 +167,0 @@ if (directory === "/") return null; |
@@ -5,5 +5,13 @@ /* | ||
*/ | ||
"use strict"; | ||
/** @typedef {import("./Resolver")} Resolver */ | ||
/** @typedef {import("./Resolver").ResolveStepHook} ResolveStepHook */ | ||
module.exports = class DirectoryExistsPlugin { | ||
/** | ||
* @param {string | ResolveStepHook} source source | ||
* @param {string | ResolveStepHook} target target | ||
*/ | ||
constructor(source, target) { | ||
@@ -14,2 +22,6 @@ this.source = source; | ||
/** | ||
* @param {Resolver} resolver the resolver | ||
* @returns {void} | ||
*/ | ||
apply(resolver) { | ||
@@ -24,2 +36,3 @@ const target = resolver.ensureHook(this.target); | ||
const directory = request.path; | ||
if (!directory) return callback(); | ||
fs.stat(directory, (err, stat) => { | ||
@@ -26,0 +39,0 @@ if (err || !stat) { |
@@ -5,5 +5,13 @@ /* | ||
*/ | ||
"use strict"; | ||
/** @typedef {import("./Resolver")} Resolver */ | ||
/** @typedef {import("./Resolver").ResolveStepHook} ResolveStepHook */ | ||
module.exports = class FileExistsPlugin { | ||
/** | ||
* @param {string | ResolveStepHook} source source | ||
* @param {string | ResolveStepHook} target target | ||
*/ | ||
constructor(source, target) { | ||
@@ -14,2 +22,6 @@ this.source = source; | ||
/** | ||
* @param {Resolver} resolver the resolver | ||
* @returns {void} | ||
*/ | ||
apply(resolver) { | ||
@@ -22,2 +34,3 @@ const target = resolver.ensureHook(this.target); | ||
const file = request.path; | ||
if (!file) return callback(); | ||
fs.stat(file, (err, stat) => { | ||
@@ -24,0 +37,0 @@ if (err || !stat) { |
@@ -5,10 +5,26 @@ /* | ||
*/ | ||
"use strict"; | ||
/** @typedef {import("./Resolver")} Resolver */ | ||
/** @typedef {import("./Resolver").ResolveStepHook} ResolveStepHook */ | ||
module.exports = class FileKindPlugin { | ||
constructor(source, target) { | ||
/** | ||
* @param {string | ResolveStepHook} source source | ||
* @param {string | null} message message | ||
* @param {string | ResolveStepHook} target target | ||
*/ | ||
constructor(source, message, target) { | ||
this.source = source; | ||
this.target = target; | ||
this.message = /** @type {string | null} */ (target ? message : null); | ||
this.target = /** @type {string | ResolveStepHook} */ (target | ||
? target | ||
: message); | ||
} | ||
/** | ||
* @param {Resolver} resolver the resolver | ||
* @returns {void} | ||
*/ | ||
apply(resolver) { | ||
@@ -20,5 +36,11 @@ const target = resolver.ensureHook(this.target); | ||
if (request.directory) return callback(); | ||
resolver.doResolve(target, request, null, resolveContext, callback); | ||
resolver.doResolve( | ||
target, | ||
request, | ||
this.message, | ||
resolveContext, | ||
callback | ||
); | ||
}); | ||
} | ||
}; |
@@ -5,2 +5,3 @@ /* | ||
*/ | ||
"use strict"; | ||
@@ -7,0 +8,0 @@ |
@@ -5,2 +5,3 @@ /* | ||
*/ | ||
"use strict"; | ||
@@ -7,0 +8,0 @@ |
@@ -5,2 +5,3 @@ /* | ||
*/ | ||
"use strict"; | ||
@@ -7,0 +8,0 @@ |
@@ -5,5 +5,15 @@ /* | ||
*/ | ||
"use strict"; | ||
/** @typedef {import("./Resolver")} Resolver */ | ||
/** @typedef {import("./Resolver").ResolveStepHook} ResolveStepHook */ | ||
const namespaceStartCharCode = "@".charCodeAt(0); | ||
module.exports = class JoinRequestPartPlugin { | ||
/** | ||
* @param {string | ResolveStepHook} source source | ||
* @param {string | ResolveStepHook} target target | ||
*/ | ||
constructor(source, target) { | ||
@@ -14,2 +24,6 @@ this.source = source; | ||
/** | ||
* @param {Resolver} resolver the resolver | ||
* @returns {void} | ||
*/ | ||
apply(resolver) { | ||
@@ -22,8 +36,13 @@ const target = resolver.ensureHook(this.target); | ||
(request, resolveContext, callback) => { | ||
const req = request.request; | ||
const i = req.indexOf("/", 3); | ||
const req = request.request || ""; | ||
let i = req.indexOf("/", 3); | ||
if (i >= 0 && req.charCodeAt(2) === namespaceStartCharCode) { | ||
i = req.indexOf("/", i + 1); | ||
} | ||
let moduleName, remainingRequest; | ||
if (i < 0) { | ||
moduleName = req; | ||
remainingRequest = ""; | ||
remainingRequest = "."; | ||
} else { | ||
@@ -30,0 +49,0 @@ moduleName = req.slice(0, i); |
@@ -5,5 +5,13 @@ /* | ||
*/ | ||
"use strict"; | ||
/** @typedef {import("./Resolver")} Resolver */ | ||
/** @typedef {import("./Resolver").ResolveStepHook} ResolveStepHook */ | ||
module.exports = class JoinRequestPlugin { | ||
/** | ||
* @param {string | ResolveStepHook} source source | ||
* @param {string | ResolveStepHook} target target | ||
*/ | ||
constructor(source, target) { | ||
@@ -14,2 +22,6 @@ this.source = source; | ||
/** | ||
* @param {Resolver} resolver the resolver | ||
* @returns {void} | ||
*/ | ||
apply(resolver) { | ||
@@ -16,0 +28,0 @@ const target = resolver.ensureHook(this.target); |
@@ -5,4 +5,7 @@ /* | ||
*/ | ||
"use strict"; | ||
/** @typedef {import("./Resolver")} Resolver */ | ||
module.exports = class LogInfoPlugin { | ||
@@ -13,2 +16,6 @@ constructor(source) { | ||
/** | ||
* @param {Resolver} resolver the resolver | ||
* @returns {void} | ||
*/ | ||
apply(resolver) { | ||
@@ -15,0 +22,0 @@ const source = this.source; |
@@ -5,7 +5,20 @@ /* | ||
*/ | ||
"use strict"; | ||
const path = require("path"); | ||
const DescriptionFileUtils = require("./DescriptionFileUtils"); | ||
/** @typedef {import("./Resolver")} Resolver */ | ||
/** @typedef {import("./Resolver").ResolveStepHook} ResolveStepHook */ | ||
/** @typedef {{name: string|Array<string>, forceRelative: boolean}} MainFieldOptions */ | ||
const alreadyTriedMainField = Symbol("alreadyTriedMainField"); | ||
module.exports = class MainFieldPlugin { | ||
/** | ||
* @param {string | ResolveStepHook} source source | ||
* @param {MainFieldOptions} options options | ||
* @param {string | ResolveStepHook} target target | ||
*/ | ||
constructor(source, options, target) { | ||
@@ -17,2 +30,6 @@ this.source = source; | ||
/** | ||
* @param {Resolver} resolver the resolver | ||
* @returns {void} | ||
*/ | ||
apply(resolver) { | ||
@@ -23,27 +40,20 @@ const target = resolver.ensureHook(this.target); | ||
.tapAsync("MainFieldPlugin", (request, resolveContext, callback) => { | ||
if (request.path !== request.descriptionFileRoot) return callback(); | ||
if (request.alreadyTriedMainField === request.descriptionFilePath) | ||
if ( | ||
request.path !== request.descriptionFileRoot || | ||
request[alreadyTriedMainField] === request.descriptionFilePath || | ||
!request.descriptionFilePath | ||
) | ||
return callback(); | ||
const content = request.descriptionFileData; | ||
const filename = path.basename(request.descriptionFilePath); | ||
let mainModule; | ||
const field = this.options.name; | ||
if (Array.isArray(field)) { | ||
let current = content; | ||
for (let j = 0; j < field.length; j++) { | ||
if (current === null || typeof current !== "object") { | ||
current = null; | ||
break; | ||
} | ||
current = current[field[j]]; | ||
} | ||
if (typeof current === "string") { | ||
mainModule = current; | ||
} | ||
} else { | ||
if (typeof content[field] === "string") { | ||
mainModule = content[field]; | ||
} | ||
} | ||
if (!mainModule || mainModule === "." || mainModule === "./") { | ||
let mainModule = DescriptionFileUtils.getField( | ||
request.descriptionFileData, | ||
this.options.name | ||
); | ||
if ( | ||
!mainModule || | ||
typeof mainModule !== "string" || | ||
mainModule === "." || | ||
mainModule === "./" | ||
) { | ||
return callback(); | ||
@@ -58,3 +68,3 @@ } | ||
directory: mainModule.endsWith("/"), | ||
alreadyTriedMainField: request.descriptionFilePath | ||
[alreadyTriedMainField]: request.descriptionFilePath | ||
}; | ||
@@ -61,0 +71,0 @@ return resolver.doResolve( |
@@ -5,5 +5,13 @@ /* | ||
*/ | ||
"use strict"; | ||
/** @typedef {import("./Resolver")} Resolver */ | ||
/** @typedef {import("./Resolver").ResolveStepHook} ResolveStepHook */ | ||
module.exports = class ModuleKindPlugin { | ||
/** | ||
* @param {string | ResolveStepHook} source source | ||
* @param {string | ResolveStepHook} target target | ||
*/ | ||
constructor(source, target) { | ||
@@ -14,2 +22,6 @@ this.source = source; | ||
/** | ||
* @param {Resolver} resolver the resolver | ||
* @returns {void} | ||
*/ | ||
apply(resolver) { | ||
@@ -16,0 +28,0 @@ const target = resolver.ensureHook(this.target); |
@@ -5,2 +5,3 @@ /* | ||
*/ | ||
"use strict"; | ||
@@ -11,9 +12,21 @@ | ||
/** @typedef {import("./Resolver")} Resolver */ | ||
/** @typedef {import("./Resolver").ResolveStepHook} ResolveStepHook */ | ||
module.exports = class ModulesInHierachicDirectoriesPlugin { | ||
/** | ||
* @param {string | ResolveStepHook} source source | ||
* @param {string | Array<string>} directories directories | ||
* @param {string | ResolveStepHook} target target | ||
*/ | ||
constructor(source, directories, target) { | ||
this.source = source; | ||
this.directories = [].concat(directories); | ||
this.directories = /** @type {Array<string>} */ ([]).concat(directories); | ||
this.target = target; | ||
} | ||
/** | ||
* @param {Resolver} resolver the resolver | ||
* @returns {void} | ||
*/ | ||
apply(resolver) { | ||
@@ -20,0 +33,0 @@ const target = resolver.ensureHook(this.target); |
@@ -5,5 +5,14 @@ /* | ||
*/ | ||
"use strict"; | ||
/** @typedef {import("./Resolver")} Resolver */ | ||
/** @typedef {import("./Resolver").ResolveStepHook} ResolveStepHook */ | ||
module.exports = class ModulesInRootPlugin { | ||
/** | ||
* @param {string | ResolveStepHook} source source | ||
* @param {string} path path | ||
* @param {string | ResolveStepHook} target target | ||
*/ | ||
constructor(source, path, target) { | ||
@@ -15,2 +24,6 @@ this.source = source; | ||
/** | ||
* @param {Resolver} resolver the resolver | ||
* @returns {void} | ||
*/ | ||
apply(resolver) { | ||
@@ -17,0 +30,0 @@ const target = resolver.ensureHook(this.target); |
@@ -5,5 +5,13 @@ /* | ||
*/ | ||
"use strict"; | ||
/** @typedef {import("./Resolver")} Resolver */ | ||
/** @typedef {import("./Resolver").ResolveStepHook} ResolveStepHook */ | ||
module.exports = class NextPlugin { | ||
/** | ||
* @param {string | ResolveStepHook} source source | ||
* @param {string | ResolveStepHook} target target | ||
*/ | ||
constructor(source, target) { | ||
@@ -14,2 +22,6 @@ this.source = source; | ||
/** | ||
* @param {Resolver} resolver the resolver | ||
* @returns {void} | ||
*/ | ||
apply(resolver) { | ||
@@ -16,0 +28,0 @@ const target = resolver.ensureHook(this.target); |
@@ -5,5 +5,13 @@ /* | ||
*/ | ||
"use strict"; | ||
/** @typedef {import("./Resolver")} Resolver */ | ||
/** @typedef {import("./Resolver").ResolveStepHook} ResolveStepHook */ | ||
module.exports = class ParsePlugin { | ||
/** | ||
* @param {string | ResolveStepHook} source source | ||
* @param {string | ResolveStepHook} target target | ||
*/ | ||
constructor(source, target) { | ||
@@ -14,2 +22,6 @@ this.source = source; | ||
/** | ||
* @param {Resolver} resolver the resolver | ||
* @returns {void} | ||
*/ | ||
apply(resolver) { | ||
@@ -16,0 +28,0 @@ const target = resolver.ensureHook(this.target); |
@@ -186,1 +186,29 @@ /* | ||
exports.cachedJoin = cachedJoin; | ||
const checkExportsFieldTarget = relativePath => { | ||
let lastNonSlashIndex = 2; | ||
let slashIndex = relativePath.indexOf("/", 2); | ||
let cd = 0; | ||
while (slashIndex !== -1) { | ||
const folder = relativePath.slice(lastNonSlashIndex, slashIndex); | ||
switch (folder) { | ||
case "..": { | ||
cd--; | ||
if (cd < 0) | ||
return new Error( | ||
`Trying to access out of package scope. Requesting ${relativePath}` | ||
); | ||
break; | ||
} | ||
default: | ||
cd++; | ||
break; | ||
} | ||
lastNonSlashIndex = slashIndex + 1; | ||
slashIndex = relativePath.indexOf("/", lastNonSlashIndex); | ||
} | ||
}; | ||
exports.checkExportsFieldTarget = checkExportsFieldTarget; |
@@ -8,3 +8,15 @@ /* | ||
/** @typedef {import("./Resolver")} Resolver */ | ||
/** @typedef {import("./Resolver").ResolveStepHook} ResolveStepHook */ | ||
/** | ||
* @typedef {Object} PnpApiImpl | ||
* @property {function(string, string, Object): string} resolveToUnqualified | ||
*/ | ||
module.exports = class PnpPlugin { | ||
/** | ||
* @param {string | ResolveStepHook} source source | ||
* @param {PnpApiImpl} pnpApi pnpApi | ||
* @param {string | ResolveStepHook} target target | ||
*/ | ||
constructor(source, pnpApi, target) { | ||
@@ -16,2 +28,6 @@ this.source = source; | ||
/** | ||
* @param {Resolver} resolver the resolver | ||
* @returns {void} | ||
*/ | ||
apply(resolver) { | ||
@@ -23,2 +39,3 @@ const target = resolver.ensureHook(this.target); | ||
const req = request.request; | ||
if (!req) return callback(); | ||
@@ -45,3 +62,3 @@ // The trailing slash indicates to PnP that this value is a folder rather than a file | ||
if (apiResolution) { | ||
if (apiResolution && resolveContext.fileDependencies) { | ||
resolveContext.fileDependencies.add(apiResolution); | ||
@@ -48,0 +65,0 @@ } |
@@ -5,2 +5,3 @@ /* | ||
*/ | ||
"use strict"; | ||
@@ -17,2 +18,63 @@ | ||
/** @typedef {import("./ResolverFactory").ResolveOptions} ResolveOptions */ | ||
/** | ||
* @typedef {Object} FileSystemStats | ||
* @property {function(): boolean} isDirectory | ||
* @property {function(): boolean} isFile | ||
*/ | ||
/** | ||
* @typedef {Object} PossibleFileSystemError | ||
* @property {string=} code | ||
* @property {number=} errno | ||
* @property {string=} path | ||
* @property {string=} syscall | ||
*/ | ||
/** | ||
* @typedef {Object} FileSystem | ||
* @property {function(string, function(PossibleFileSystemError & Error | null | undefined, Buffer | string=): void): void} readFile | ||
* @property {(function(string, function(PossibleFileSystemError & Error | null | undefined, object=): void): void)=} readJson | ||
* @property {function(string, function(PossibleFileSystemError & Error | null | undefined, Buffer | string=): void): void} readlink | ||
* @property {function(string, function(PossibleFileSystemError & Error | null | undefined, FileSystemStats=): void): void} stat | ||
*/ | ||
/** | ||
* @typedef {Object} ResolveRequest | ||
* @property {string | false} path | ||
* @property {string=} request | ||
* @property {string=} query | ||
* @property {boolean=} directory | ||
* @property {boolean=} module | ||
* @property {string=} descriptionFilePath | ||
* @property {string=} descriptionFileRoot | ||
* @property {object=} descriptionFileData | ||
* @property {string=} relativePath | ||
* @property {boolean=} ignoreSymlinks | ||
*/ | ||
/** | ||
* String with special formatting | ||
* @typedef {string} StackEntry | ||
*/ | ||
/** @template T @typedef {{ add: (T) => void }} WriteOnlySet<T> */ | ||
/** | ||
* 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 | ||
*/ | ||
/** @typedef {AsyncSeriesBailHook<[ResolveRequest, ResolveContext], ResolveRequest | null>} ResolveStepHook */ | ||
/** | ||
* @param {string} str input string | ||
* @returns {string} in camel case | ||
*/ | ||
function toCamelCase(str) { | ||
@@ -23,7 +85,33 @@ return str.replace(/-([a-z])/g, str => str.substr(1).toUpperCase()); | ||
class Resolver { | ||
constructor(fileSystem) { | ||
/** | ||
* @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.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( | ||
@@ -33,2 +121,3 @@ ["request", "resolveContext"], | ||
), | ||
/** @type {AsyncSeriesHook<[ResolveRequest, ResolveContext], void>} */ | ||
result: new AsyncSeriesHook(["result", "resolveContext"], "result") | ||
@@ -38,2 +127,6 @@ }; | ||
/** | ||
* @param {string | ResolveStepHook} name hook name or hook itself | ||
* @returns {ResolveStepHook} the hook | ||
*/ | ||
ensureHook(name) { | ||
@@ -45,14 +138,14 @@ if (typeof name !== "string") { | ||
if (/^before/.test(name)) { | ||
return this.ensureHook( | ||
return /** @type {ResolveStepHook} */ (this.ensureHook( | ||
name[6].toLowerCase() + name.substr(7) | ||
).withOptions({ | ||
stage: -10 | ||
}); | ||
})); | ||
} | ||
if (/^after/.test(name)) { | ||
return this.ensureHook( | ||
return /** @type {ResolveStepHook} */ (this.ensureHook( | ||
name[5].toLowerCase() + name.substr(6) | ||
).withOptions({ | ||
stage: 10 | ||
}); | ||
})); | ||
} | ||
@@ -69,2 +162,6 @@ const hook = this.hooks[name]; | ||
/** | ||
* @param {string | ResolveStepHook} name hook name or hook itself | ||
* @returns {ResolveStepHook} the hook | ||
*/ | ||
getHook(name) { | ||
@@ -76,10 +173,14 @@ if (typeof name !== "string") { | ||
if (/^before/.test(name)) { | ||
return this.getHook(name[6].toLowerCase() + name.substr(7)).withOptions({ | ||
return /** @type {ResolveStepHook} */ (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({ | ||
return /** @type {ResolveStepHook} */ (this.getHook( | ||
name[5].toLowerCase() + name.substr(6) | ||
).withOptions({ | ||
stage: 10 | ||
}); | ||
})); | ||
} | ||
@@ -93,6 +194,14 @@ const hook = this.hooks[name]; | ||
/** | ||
* @param {object} context context information object | ||
* @param {string} path context path | ||
* @param {string} request request string | ||
* @returns {string | false} result | ||
*/ | ||
resolveSync(context, path, request) { | ||
let err, | ||
result, | ||
sync = false; | ||
/** @type {Error | null | undefined} */ | ||
let err = undefined; | ||
/** @type {string | false | undefined} */ | ||
let result = undefined; | ||
let sync = false; | ||
this.resolve(context, path, request, {}, (e, r) => { | ||
@@ -109,5 +218,14 @@ err = e; | ||
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=, ResolveRequest=): void} callback callback function | ||
* @returns {void} | ||
*/ | ||
resolve(context, path, request, resolveContext, callback) { | ||
@@ -142,2 +260,3 @@ const obj = { | ||
// We need log anyway to capture it in case of an error | ||
const parentLog = resolveContext.log; | ||
const log = []; | ||
@@ -150,3 +269,3 @@ return this.doResolve( | ||
log: msg => { | ||
resolveContext.log(msg); | ||
parentLog(msg); | ||
log.push(msg); | ||
@@ -213,11 +332,3 @@ }, | ||
doResolve(hook, request, message, resolveContext, callback) { | ||
const stackLine = | ||
hook.name + | ||
": (" + | ||
request.path + | ||
") " + | ||
(request.request || "") + | ||
(request.query || "") + | ||
(request.directory ? " directory" : "") + | ||
(request.module ? " module" : ""); | ||
const stackEntry = Resolver.createStackEntry(hook, request); | ||
@@ -227,3 +338,3 @@ let newStack; | ||
newStack = new Set(resolveContext.stack); | ||
if (resolveContext.stack.has(stackLine)) { | ||
if (resolveContext.stack.has(stackEntry)) { | ||
/** | ||
@@ -242,5 +353,5 @@ * Prevent recursion | ||
} | ||
newStack.add(stackLine); | ||
newStack.add(stackEntry); | ||
} else { | ||
newStack = new Set([stackLine]); | ||
newStack = new Set([stackEntry]); | ||
} | ||
@@ -271,3 +382,2 @@ this.hooks.resolveStep.call(hook, request); | ||
parse(identifier) { | ||
if (identifier === "") return null; | ||
const part = { | ||
@@ -274,0 +384,0 @@ request: "", |
@@ -5,2 +5,3 @@ /* | ||
*/ | ||
"use strict"; | ||
@@ -13,153 +14,212 @@ | ||
const ParsePlugin = require("./ParsePlugin"); | ||
const AliasFieldPlugin = require("./AliasFieldPlugin"); | ||
const AliasPlugin = require("./AliasPlugin"); | ||
const AppendPlugin = require("./AppendPlugin"); | ||
const DescriptionFilePlugin = require("./DescriptionFilePlugin"); | ||
const NextPlugin = require("./NextPlugin"); | ||
const TryNextPlugin = require("./TryNextPlugin"); | ||
const ModuleKindPlugin = require("./ModuleKindPlugin"); | ||
const DirectoryExistsPlugin = require("./DirectoryExistsPlugin"); | ||
const ExportsFieldPlugin = require("./ExportsFieldPlugin"); | ||
const FileExistsPlugin = require("./FileExistsPlugin"); | ||
const FileKindPlugin = require("./FileKindPlugin"); | ||
const JoinRequestPartPlugin = require("./JoinRequestPartPlugin"); | ||
const JoinRequestPlugin = require("./JoinRequestPlugin"); | ||
const JoinRequestPartPlugin = require("./JoinRequestPartPlugin"); | ||
const MainFieldPlugin = require("./MainFieldPlugin"); | ||
const ModuleKindPlugin = require("./ModuleKindPlugin"); | ||
const ModulesInHierachicDirectoriesPlugin = require("./ModulesInHierachicDirectoriesPlugin"); | ||
const ModulesInRootPlugin = require("./ModulesInRootPlugin"); | ||
const AliasPlugin = require("./AliasPlugin"); | ||
const AliasFieldPlugin = require("./AliasFieldPlugin"); | ||
const DirectoryExistsPlugin = require("./DirectoryExistsPlugin"); | ||
const FileExistsPlugin = require("./FileExistsPlugin"); | ||
const NextPlugin = require("./NextPlugin"); | ||
const ParsePlugin = require("./ParsePlugin"); | ||
const PnpPlugin = require("./PnpPlugin"); | ||
const ResultPlugin = require("./ResultPlugin"); | ||
const SelfReferencePlugin = require("./SelfReferencePlugin"); | ||
const SymlinkPlugin = require("./SymlinkPlugin"); | ||
const MainFieldPlugin = require("./MainFieldPlugin"); | ||
const TryNextPlugin = require("./TryNextPlugin"); | ||
const UnsafeCachePlugin = require("./UnsafeCachePlugin"); | ||
const UseFilePlugin = require("./UseFilePlugin"); | ||
const AppendPlugin = require("./AppendPlugin"); | ||
const ResultPlugin = require("./ResultPlugin"); | ||
const UnsafeCachePlugin = require("./UnsafeCachePlugin"); | ||
const PnpPlugin = require("./PnpPlugin"); | ||
exports.createResolver = function(options) { | ||
//// OPTIONS //// | ||
/** @typedef {import("./PnpPlugin").PnpApiImpl} PnpApi */ | ||
/** @typedef {import("./Resolver").FileSystem} FileSystem */ | ||
/** @typedef {import("./Resolver").ResolveRequest} ResolveRequest */ | ||
// A list of directories to resolve modules from, can be absolute path or folder name | ||
let modules = options.modules || ["node_modules"]; | ||
/** @typedef {string|string[]|false} AliasOptionNewRequest */ | ||
/** @typedef {{alias: AliasOptionNewRequest, name: string, onlyModule?: boolean}} AliasOptionEntry */ | ||
/** @typedef {{[k: string]: AliasOptionNewRequest}} AliasOptions */ | ||
/** @typedef {{apply: function(Resolver): void} | function(this: Resolver, Resolver): void} Plugin */ | ||
// A list of description files to read from | ||
const descriptionFiles = options.descriptionFiles || ["package.json"]; | ||
/** | ||
* @typedef {Object} UserResolveOptions | ||
* @property {(AliasOptions | AliasOptionEntry[])=} alias A list of module alias configurations or an object which maps key to value | ||
* @property {(string | string[])[]=} aliasFields A list of alias fields in description files | ||
* @property {(function(ResolveRequest): boolean)=} cachePredicate A function which decides whether a request should be cached or not. An object is passed with at least `path` and `request` properties. | ||
* @property {boolean=} cacheWithContext Whether or not the unsafeCache should include request context as part of the cache key. | ||
* @property {string[]=} descriptionFiles A list of description files to read from | ||
* @property {string[]=} conditionNames A list of exports field condition names. | ||
* @property {boolean=} enforceExtension Enforce that a extension from extensions must be used | ||
* @property {(string | string[])[]=} exportsFields A list of exports fields in description files | ||
* @property {string[]=} extensions A list of extensions which should be tried for files | ||
* @property {FileSystem} fileSystem The file system which should be used | ||
* @property {(Object | boolean)=} unsafeCache Use this cache object to unsafely cache the successful requests | ||
* @property {boolean=} symlinks Resolve symlinks to their symlinked location | ||
* @property {Resolver=} resolver A prepared Resolver to which the plugins are attached | ||
* @property {string[] | string=} modules A list of directories to resolve modules from, can be absolute path or folder name | ||
* @property {(string | string[] | {name: string | string[], forceRelative: boolean})[]=} mainFields A list of main fields in description files | ||
* @property {string[]=} mainFiles A list of main files in directories | ||
* @property {Plugin[]=} plugins A list of additional resolve plugins which should be applied | ||
* @property {PnpApi | null=} pnpApi A PnP API that should be used - null is "never", undefined is "auto" | ||
* @property {boolean=} resolveToContext Resolve to a context instead of a file | ||
* @property {boolean=} useSyncFileSystemCalls Use only the sync constiants of the file system calls | ||
*/ | ||
// 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()) || []; | ||
/** | ||
* @typedef {Object} ResolveOptions | ||
* @property {AliasOptionEntry[]} alias | ||
* @property {Set<string | string[]>} aliasFields | ||
* @property {(function(ResolveRequest): boolean)} cachePredicate | ||
* @property {boolean} cacheWithContext | ||
* @property {Set<string>} conditionNames A list of exports field condition names. | ||
* @property {string[]} descriptionFiles | ||
* @property {boolean} enforceExtension | ||
* @property {Set<string | string[]>} exportsFields | ||
* @property {Set<string>} extensions | ||
* @property {FileSystem} fileSystem | ||
* @property {Object | false} unsafeCache | ||
* @property {boolean} symlinks | ||
* @property {Resolver=} resolver | ||
* @property {Array<string | string[]>} modules | ||
* @property {{name: string[], forceRelative: boolean}[]} mainFields | ||
* @property {Set<string>} mainFiles | ||
* @property {Plugin[]} plugins | ||
* @property {PnpApi | null} pnpApi | ||
* @property {boolean} resolveToContext | ||
*/ | ||
// 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 alias configurations or an object which maps key to value | ||
let alias = options.alias || []; | ||
// A PnP API that should be used - null is "never", undefined is "auto" | ||
let pnpApi = options.pnpApi || null; | ||
/** | ||
* @param {PnpApi | null=} option option | ||
* @returns {PnpApi | null} processed option | ||
*/ | ||
function processPnpApiOption(option) { | ||
if ( | ||
options.pnpApi === undefined && | ||
option === undefined && | ||
/** @type {NodeJS.ProcessVersions & {pnp: string}} */ (process.versions).pnp | ||
) { | ||
// @ts-ignore | ||
pnpApi = require("pnpapi"); // eslint-disable-line node/no-missing-require | ||
return require("pnpapi"); // eslint-disable-line node/no-missing-require | ||
} | ||
// Resolve symlinks to their symlinked location | ||
const symlinks = | ||
typeof options.symlinks !== "undefined" ? options.symlinks : true; | ||
return option || null; | ||
} | ||
// Resolve to a context instead of a file | ||
const resolveToContext = options.resolveToContext || false; | ||
/** | ||
* @param {UserResolveOptions} options input options | ||
* @returns {ResolveOptions} output options | ||
*/ | ||
function createOptions(options) { | ||
const mainFieldsSet = new Set(options.mainFields || ["main"]); | ||
const mainFields = []; | ||
// 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; | ||
// 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); | ||
modules = mergeFilteredToArray([].concat(modules), item => { | ||
const type = getType(item); | ||
return type === PathType.Normal || type === PathType.Relative; | ||
}); | ||
mainFields = mainFields.map(item => { | ||
if (typeof item === "string" || Array.isArray(item)) { | ||
item = { | ||
for (const item of mainFieldsSet) { | ||
if (typeof item === "string") { | ||
mainFields.push({ | ||
name: [item], | ||
forceRelative: true | ||
}); | ||
} else if (Array.isArray(item)) { | ||
mainFields.push({ | ||
name: item, | ||
forceRelative: true | ||
}; | ||
}); | ||
} else { | ||
mainFields.push({ | ||
name: Array.isArray(item.name) ? item.name : [item.name], | ||
forceRelative: item.forceRelative | ||
}); | ||
} | ||
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); | ||
return { | ||
alias: | ||
typeof options.alias === "object" && | ||
!Array.isArray(options.alias) && | ||
options.alias !== null | ||
? aliasOptionsToArray(options.alias) | ||
: /** @type {Array<AliasOptionEntry>} */ (options.alias) || [], | ||
aliasFields: new Set(options.aliasFields), | ||
cachePredicate: | ||
options.cachePredicate || | ||
function() { | ||
return true; | ||
}, | ||
cacheWithContext: | ||
typeof options.cacheWithContext !== "undefined" | ||
? options.cacheWithContext | ||
: true, | ||
exportsFields: new Set(options.exportsFields || ["exports"]), | ||
conditionNames: new Set(options.conditionNames), | ||
descriptionFiles: Array.from( | ||
new Set(options.descriptionFiles || ["package.json"]) | ||
), | ||
enforceExtension: options.enforceExtension || false, | ||
extensions: new Set(options.extensions || [".js", ".json", ".node"]), | ||
fileSystem: options.useSyncFileSystemCalls | ||
? new SyncAsyncFileSystemDecorator(options.fileSystem) | ||
: options.fileSystem, | ||
unsafeCache: | ||
options.unsafeCache && typeof options.unsafeCache !== "object" | ||
? {} | ||
: options.unsafeCache || false, | ||
symlinks: typeof options.symlinks !== "undefined" ? options.symlinks : true, | ||
resolver: options.resolver, | ||
modules: mergeFilteredToArray( | ||
Array.isArray(options.modules) | ||
? options.modules | ||
: options.modules | ||
? [options.modules] | ||
: ["node_modules"], | ||
item => { | ||
const type = getType(item); | ||
return type === PathType.Normal || type === PathType.Relative; | ||
} | ||
if (typeof obj === "string" || Array.isArray(obj) || obj === false) { | ||
obj = { | ||
alias: obj | ||
}; | ||
} | ||
obj = { | ||
name: key, | ||
onlyModule: onlyModule, | ||
...obj | ||
}; | ||
return obj; | ||
}); | ||
} | ||
), | ||
mainFields, | ||
mainFiles: new Set(options.mainFiles || ["index"]), | ||
plugins: options.plugins || [], | ||
pnpApi: processPnpApiOption(options.pnpApi), | ||
resolveToContext: options.resolveToContext || false | ||
}; | ||
} | ||
if (unsafeCache && typeof unsafeCache !== "object") { | ||
unsafeCache = {}; | ||
} | ||
/** | ||
* @param {UserResolveOptions} options resolve options | ||
* @returns {Resolver} created resolver | ||
*/ | ||
exports.createResolver = function(options) { | ||
const normalizedOptions = createOptions(options); | ||
const { | ||
alias, | ||
aliasFields, | ||
cachePredicate, | ||
cacheWithContext, | ||
conditionNames, | ||
descriptionFiles, | ||
enforceExtension, | ||
exportsFields, | ||
extensions, | ||
fileSystem, | ||
mainFields, | ||
mainFiles, | ||
modules, | ||
plugins: userPlugins, | ||
pnpApi, | ||
resolveToContext, | ||
symlinks, | ||
unsafeCache, | ||
resolver: customResolver | ||
} = normalizedOptions; | ||
const plugins = userPlugins.slice(); | ||
const resolver = customResolver | ||
? customResolver | ||
: new Resolver(fileSystem, normalizedOptions); | ||
//// pipeline //// | ||
@@ -172,3 +232,5 @@ | ||
resolver.ensureHook("module"); | ||
resolver.ensureHook("resolveInDirectory"); | ||
resolver.ensureHook("resolveAsModule"); | ||
resolver.ensureHook("undescribedResolveInPackage"); | ||
resolver.ensureHook("resolveInPackage"); | ||
resolver.ensureHook("resolveInExistingDirectory"); | ||
@@ -183,2 +245,3 @@ resolver.ensureHook("relative"); | ||
resolver.ensureHook("file"); | ||
resolver.ensureHook("finalFile"); | ||
resolver.ensureHook("existingFile"); | ||
@@ -223,3 +286,8 @@ resolver.ensureHook("resolved"); | ||
// module | ||
// raw-module | ||
exportsFields.forEach(exportsField => { | ||
plugins.push( | ||
new SelfReferencePlugin("raw-module", exportsField, "resolve-as-module") | ||
); | ||
}); | ||
if (pnpApi) { | ||
@@ -237,9 +305,9 @@ plugins.push(new PnpPlugin("raw-module", pnpApi, "relative")); | ||
// module | ||
plugins.push(new JoinRequestPartPlugin("module", "resolve-in-directory")); | ||
plugins.push(new JoinRequestPartPlugin("module", "resolve-as-module")); | ||
// resolve-in-directory | ||
// resolve-as-module | ||
if (!resolveToContext) { | ||
plugins.push( | ||
new TryNextPlugin( | ||
"resolve-in-directory", | ||
new FileKindPlugin( | ||
"resolve-as-module", | ||
"single file module", | ||
@@ -252,7 +320,35 @@ "undescribed-raw-file" | ||
new DirectoryExistsPlugin( | ||
"resolve-in-directory", | ||
"resolve-in-existing-directory" | ||
"resolve-as-module", | ||
"undescribed-resolve-in-package" | ||
) | ||
); | ||
// undescribed-resolve-in-package | ||
plugins.push( | ||
new DescriptionFilePlugin( | ||
"undescribed-resolve-in-package", | ||
descriptionFiles, | ||
false, | ||
"resolve-in-package" | ||
) | ||
); | ||
plugins.push( | ||
new NextPlugin("after-undescribed-resolve-in-package", "resolve-in-package") | ||
); | ||
// resolve-in-package | ||
exportsFields.forEach(exportsField => { | ||
plugins.push( | ||
new ExportsFieldPlugin( | ||
"resolve-in-package", | ||
conditionNames, | ||
exportsField, | ||
"final-file" | ||
) | ||
); | ||
}); | ||
plugins.push( | ||
new NextPlugin("resolve-in-package", "resolve-in-existing-directory") | ||
); | ||
// resolve-in-existing-directory | ||
@@ -276,3 +372,3 @@ plugins.push( | ||
if (!resolveToContext) { | ||
plugins.push(new FileKindPlugin("described-relative", "raw-file")); | ||
plugins.push(new FileKindPlugin("described-relative", null, "raw-file")); | ||
} | ||
@@ -352,4 +448,7 @@ plugins.push( | ||
}); | ||
plugins.push(new FileExistsPlugin("file", "existing-file")); | ||
plugins.push(new NextPlugin("file", "final-file")); | ||
// final-file | ||
plugins.push(new FileExistsPlugin("final-file", "existing-file")); | ||
// existing-file | ||
@@ -366,5 +465,9 @@ if (symlinks) | ||
plugins.forEach(plugin => { | ||
plugin.apply(resolver); | ||
}); | ||
for (const plugin of plugins) { | ||
if (typeof plugin === "function") { | ||
plugin.call(resolver, resolver); | ||
} else { | ||
plugin.apply(resolver); | ||
} | ||
} | ||
@@ -374,17 +477,46 @@ return resolver; | ||
/** | ||
* @param {AliasOptions} alias alias | ||
* @returns {Array<AliasOptionEntry>} array of entries | ||
*/ | ||
function aliasOptionsToArray(alias) { | ||
return Object.keys(alias).map(key => { | ||
/** @type {AliasOptionEntry} */ | ||
const obj = { name: key, onlyModule: false, alias: alias[key] }; | ||
if (/\$$/.test(key)) { | ||
obj.onlyModule = true; | ||
obj.name = key.substr(0, key.length - 1); | ||
} | ||
return obj; | ||
}); | ||
} | ||
/** | ||
* Merging filtered elements | ||
* @param {string[]} array source array | ||
* @param {function(string): boolean} filter predicate | ||
* @returns {Array<string | string[]>} merge result | ||
*/ | ||
function mergeFilteredToArray(array, filter) { | ||
return array.reduce((array, item) => { | ||
/** @type {Array<string | string[]>} */ | ||
const result = []; | ||
const set = new Set(array); | ||
for (const item of set) { | ||
if (filter(item)) { | ||
const lastElement = array[array.length - 1]; | ||
const lastElement = | ||
result.length > 0 ? result[result.length - 1] : undefined; | ||
if (Array.isArray(lastElement)) { | ||
lastElement.push(item); | ||
} else { | ||
array.push([item]); | ||
result.push([item]); | ||
} | ||
return array; | ||
} else { | ||
array.push(item); | ||
return array; | ||
result.push(item); | ||
} | ||
}, []); | ||
} | ||
return result; | ||
} |
@@ -5,5 +5,12 @@ /* | ||
*/ | ||
"use strict"; | ||
/** @typedef {import("tapable").AsyncHook} AsyncHook */ | ||
/** @typedef {import("./Resolver")} Resolver */ | ||
module.exports = class ResultPlugin { | ||
/** | ||
* @param {AsyncHook} source source | ||
*/ | ||
constructor(source) { | ||
@@ -13,2 +20,6 @@ this.source = source; | ||
/** | ||
* @param {Resolver} resolver the resolver | ||
* @returns {void} | ||
*/ | ||
apply(resolver) { | ||
@@ -15,0 +26,0 @@ this.source.tapAsync( |
@@ -5,9 +5,17 @@ /* | ||
*/ | ||
"use strict"; | ||
const forEachBail = require("./forEachBail"); | ||
const getPaths = require("./getPaths"); | ||
const forEachBail = require("./forEachBail"); | ||
const { getType, PathType } = require("./pathUtils"); | ||
/** @typedef {import("./Resolver")} Resolver */ | ||
/** @typedef {import("./Resolver").ResolveStepHook} ResolveStepHook */ | ||
module.exports = class SymlinkPlugin { | ||
/** | ||
* @param {string | ResolveStepHook} source source | ||
* @param {string | ResolveStepHook} target target | ||
*/ | ||
constructor(source, target) { | ||
@@ -18,2 +26,6 @@ this.source = source; | ||
/** | ||
* @param {Resolver} resolver the resolver | ||
* @returns {void} | ||
*/ | ||
apply(resolver) { | ||
@@ -43,3 +55,3 @@ const target = resolver.ensureHook(this.target); | ||
// Shortcut when absolute symlink found | ||
const resultType = getType(result); | ||
const resultType = getType(result.toString()); | ||
if ( | ||
@@ -61,3 +73,3 @@ resultType === PathType.AbsoluteWin || | ||
: pathSeqments.slice(); | ||
const result = resultSeqments.reverse().reduce((a, b) => { | ||
const result = resultSeqments.reduceRight((a, b) => { | ||
return resolver.join(a, b); | ||
@@ -64,0 +76,0 @@ }); |
@@ -5,2 +5,3 @@ /* | ||
*/ | ||
"use strict"; | ||
@@ -7,0 +8,0 @@ |
@@ -5,5 +5,14 @@ /* | ||
*/ | ||
"use strict"; | ||
/** @typedef {import("./Resolver")} Resolver */ | ||
/** @typedef {import("./Resolver").ResolveStepHook} ResolveStepHook */ | ||
module.exports = class TryNextPlugin { | ||
/** | ||
* @param {string | ResolveStepHook} source source | ||
* @param {string} message message | ||
* @param {string | ResolveStepHook} target target | ||
*/ | ||
constructor(source, message, target) { | ||
@@ -15,2 +24,6 @@ this.source = source; | ||
/** | ||
* @param {Resolver} resolver the resolver | ||
* @returns {void} | ||
*/ | ||
apply(resolver) { | ||
@@ -17,0 +30,0 @@ const target = resolver.ensureHook(this.target); |
@@ -5,4 +5,10 @@ /* | ||
*/ | ||
"use strict"; | ||
/** @typedef {import("./Resolver")} Resolver */ | ||
/** @typedef {import("./Resolver").ResolveRequest} ResolveRequest */ | ||
/** @typedef {import("./Resolver").ResolveStepHook} ResolveStepHook */ | ||
/** @typedef {{[k: string]: any}} Cache */ | ||
function getCacheId(request, withContext) { | ||
@@ -18,2 +24,9 @@ return JSON.stringify({ | ||
module.exports = class UnsafeCachePlugin { | ||
/** | ||
* @param {string | ResolveStepHook} source source | ||
* @param {function(ResolveRequest): boolean} filterPredicate filterPredicate | ||
* @param {Cache} cache cache | ||
* @param {boolean} withContext withContext | ||
* @param {string | ResolveStepHook} target target | ||
*/ | ||
constructor(source, filterPredicate, cache, withContext, target) { | ||
@@ -23,6 +36,10 @@ this.source = source; | ||
this.withContext = withContext; | ||
this.cache = cache || {}; | ||
this.cache = cache; | ||
this.target = target; | ||
} | ||
/** | ||
* @param {Resolver} resolver the resolver | ||
* @returns {void} | ||
*/ | ||
apply(resolver) { | ||
@@ -29,0 +46,0 @@ const target = resolver.ensureHook(this.target); |
@@ -5,5 +5,14 @@ /* | ||
*/ | ||
"use strict"; | ||
/** @typedef {import("./Resolver")} Resolver */ | ||
/** @typedef {import("./Resolver").ResolveStepHook} ResolveStepHook */ | ||
module.exports = class UseFilePlugin { | ||
/** | ||
* @param {string | ResolveStepHook} source source | ||
* @param {string} filename filename | ||
* @param {string | ResolveStepHook} target target | ||
*/ | ||
constructor(source, filename, target) { | ||
@@ -15,2 +24,6 @@ this.source = source; | ||
/** | ||
* @param {Resolver} resolver the resolver | ||
* @returns {void} | ||
*/ | ||
apply(resolver) { | ||
@@ -17,0 +30,0 @@ const target = resolver.ensureHook(this.target); |
{ | ||
"name": "enhanced-resolve", | ||
"version": "5.0.0-beta.4", | ||
"version": "5.0.0-beta.5", | ||
"author": "Tobias Koppers @sokra", | ||
@@ -8,2 +8,3 @@ "description": "Offers a async require.resolve function. It's highly configurable.", | ||
"lib", | ||
"types.d.ts", | ||
"LICENSE" | ||
@@ -13,34 +14,37 @@ ], | ||
"graceful-fs": "^4.2.0", | ||
"tapable": "^2.0.0-beta.8" | ||
"tapable": "^2.0.0-beta.10" | ||
}, | ||
"licenses": [ | ||
{ | ||
"type": "MIT", | ||
"url": "http://www.opensource.org/licenses/mit-license.php" | ||
} | ||
], | ||
"license": "MIT", | ||
"devDependencies": { | ||
"@types/mocha": "^5.2.7", | ||
"@types/node": "^10.12.21", | ||
"eslint": "^5.9.0", | ||
"eslint-config-prettier": "^3.3.0", | ||
"eslint-plugin-jsdoc": "^15.2.0", | ||
"eslint-plugin-node": "^8.0.0", | ||
"eslint-plugin-prettier": "^3.0.0", | ||
"@types/mocha": "^7.0.2", | ||
"@types/node": "^13.7.7", | ||
"eslint": "^6.8.0", | ||
"eslint-config-prettier": "^6.10.0", | ||
"eslint-plugin-jsdoc": "^22.0.0", | ||
"eslint-plugin-node": "^11.0.0", | ||
"eslint-plugin-prettier": "^3.1.2", | ||
"husky": "^1.2.0", | ||
"lint-staged": "^8.1.0", | ||
"memfs": "^2.15.4", | ||
"mocha": "^6.1.4", | ||
"mocha": "^7.1.0", | ||
"nyc": "^14.1.1", | ||
"prettier": "^1.15.2", | ||
"should": "^13.2.3", | ||
"typescript": "^3.5.2" | ||
"tooling": "webpack/tooling#v1.6.0", | ||
"typescript": "^3.8.3" | ||
}, | ||
"engines": { | ||
"node": ">=8.9.0" | ||
"node": ">=10.13.0" | ||
}, | ||
"main": "lib/node.js", | ||
"main": "lib/index.js", | ||
"types": "types.d.ts", | ||
"homepage": "http://github.com/webpack/enhanced-resolve", | ||
"scripts": { | ||
"lint": "eslint lib test && tsc", | ||
"lint": "yarn run code-lint && yarn run type-lint && yarn run special-lint", | ||
"fix": "yarn run code-lint-fix && yarn run special-lint-fix", | ||
"code-lint": "eslint --cache lib test", | ||
"code-lint-fix": "eslint --cache lib test --fix", | ||
"type-lint": "tsc", | ||
"special-lint": "node node_modules/tooling/lockfile-lint && node node_modules/tooling/inherit-types && node node_modules/tooling/format-file-header && node node_modules/tooling/generate-types", | ||
"special-lint-fix": "node node_modules/tooling/inherit-types --write && node node_modules/tooling/format-file-header --write && node node_modules/tooling/generate-types --write", | ||
"pretty": "prettier --loglevel warn --write \"{lib,test}/**/*.{js,json}\"", | ||
@@ -47,0 +51,0 @@ "pretest": "yarn lint", |
@@ -84,5 +84,7 @@ # enhanced-resolve | ||
| cacheWithContext | true | If unsafe cache is enabled, includes `request.context` in the cache key | | ||
| conditionNames | ["node"] | A list of exports field condition names | | ||
| descriptionFiles | ["package.json"] | A list of description files to read from | | ||
| enforceExtension | false | Enforce that a extension from extensions must be used | | ||
| extensions | [".js", ".json", ".node"] | A list of extensions which should be tried for files | | ||
| exportsFields | ["exports"] | A list of exports fields in description files | | ||
| mainFields | ["main"] | A list of main fields in description files | | ||
@@ -89,0 +91,0 @@ | mainFiles | ["index"] | A list of main files in directories | |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
125120
41
4021
156
16
Updatedtapable@^2.0.0-beta.10