enhanced-resolve
Advanced tools
Comparing version 4.1.0 to 5.0.0-beta.0
@@ -19,35 +19,59 @@ /* | ||
const target = resolver.ensureHook(this.target); | ||
resolver.getHook(this.source).tapAsync("AliasFieldPlugin", (request, resolveContext, callback) => { | ||
if(!request.descriptionFileData) return callback(); | ||
const innerRequest = getInnerRequest(resolver, request); | ||
if(!innerRequest) return callback(); | ||
const fieldData = DescriptionFileUtils.getField(request.descriptionFileData, this.field); | ||
if(typeof fieldData !== "object") { | ||
if(resolveContext.log) resolveContext.log("Field '" + this.field + "' doesn't contain a valid alias configuration"); | ||
return callback(); | ||
} | ||
const data1 = fieldData[innerRequest]; | ||
const data2 = fieldData[innerRequest.replace(/^\.\//, "")]; | ||
const data = typeof data1 !== "undefined" ? data1 : data2; | ||
if(data === innerRequest) return callback(); | ||
if(data === undefined) return callback(); | ||
if(data === false) { | ||
const ignoreObj = Object.assign({}, request, { | ||
path: false | ||
}); | ||
return callback(null, ignoreObj); | ||
} | ||
const obj = Object.assign({}, request, { | ||
path: request.descriptionFileRoot, | ||
request: data | ||
}); | ||
resolver.doResolve(target, obj, "aliased from description file " + request.descriptionFilePath + " with mapping '" + innerRequest + "' to '" + data + "'", resolveContext, (err, result) => { | ||
if(err) return callback(err); | ||
resolver | ||
.getHook(this.source) | ||
.tapAsync("AliasFieldPlugin", (request, resolveContext, callback) => { | ||
if (!request.descriptionFileData) return callback(); | ||
const innerRequest = getInnerRequest(resolver, request); | ||
if (!innerRequest) return callback(); | ||
const fieldData = DescriptionFileUtils.getField( | ||
request.descriptionFileData, | ||
this.field | ||
); | ||
if (typeof fieldData !== "object") { | ||
if (resolveContext.log) | ||
resolveContext.log( | ||
"Field '" + | ||
this.field + | ||
"' doesn't contain a valid alias configuration" | ||
); | ||
return callback(); | ||
} | ||
const data1 = fieldData[innerRequest]; | ||
const data2 = fieldData[innerRequest.replace(/^\.\//, "")]; | ||
const data = typeof data1 !== "undefined" ? data1 : data2; | ||
if (data === innerRequest) return callback(); | ||
if (data === undefined) return callback(); | ||
if (data === false) { | ||
const ignoreObj = { | ||
...request, | ||
path: false | ||
}; | ||
return callback(null, ignoreObj); | ||
} | ||
const obj = { | ||
...request, | ||
path: request.descriptionFileRoot, | ||
request: data | ||
}; | ||
resolver.doResolve( | ||
target, | ||
obj, | ||
"aliased from description file " + | ||
request.descriptionFilePath + | ||
" with mapping '" + | ||
innerRequest + | ||
"' to '" + | ||
data + | ||
"'", | ||
resolveContext, | ||
(err, result) => { | ||
if (err) return callback(err); | ||
// Don't allow other aliasing or raw request | ||
if(result === undefined) return callback(null, null); | ||
callback(null, result); | ||
// Don't allow other aliasing or raw request | ||
if (result === undefined) return callback(null, null); | ||
callback(null, result); | ||
} | ||
); | ||
}); | ||
}); | ||
} | ||
}; |
@@ -7,19 +7,4 @@ /* | ||
function startsWith(string, searchString) { | ||
const stringLength = string.length; | ||
const searchLength = searchString.length; | ||
const forEachBail = require("./forEachBail"); | ||
// early out if the search length is greater than the search string | ||
if(searchLength > stringLength) { | ||
return false; | ||
} | ||
let index = -1; | ||
while(++index < searchLength) { | ||
if(string.charCodeAt(index) !== searchString.charCodeAt(index)) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
module.exports = class AliasPlugin { | ||
@@ -34,25 +19,71 @@ constructor(source, options, target) { | ||
const target = resolver.ensureHook(this.target); | ||
resolver.getHook(this.source).tapAsync("AliasPlugin", (request, resolveContext, callback) => { | ||
const innerRequest = request.request || request.path; | ||
if(!innerRequest) return callback(); | ||
for(const item of this.options) { | ||
if(innerRequest === item.name || (!item.onlyModule && startsWith(innerRequest, item.name + "/"))) { | ||
if(innerRequest !== item.alias && !startsWith(innerRequest, item.alias + "/")) { | ||
const newRequestStr = item.alias + innerRequest.substr(item.name.length); | ||
const obj = Object.assign({}, request, { | ||
request: newRequestStr | ||
}); | ||
return resolver.doResolve(target, obj, "aliased with mapping '" + item.name + "': '" + item.alias + "' to '" + newRequestStr + "'", resolveContext, (err, result) => { | ||
if(err) return callback(err); | ||
resolver | ||
.getHook(this.source) | ||
.tapAsync("AliasPlugin", (request, resolveContext, callback) => { | ||
const innerRequest = request.request || request.path; | ||
if (!innerRequest) return callback(); | ||
forEachBail( | ||
this.options, | ||
(item, callback) => { | ||
let shouldStop = false; | ||
if ( | ||
innerRequest === item.name || | ||
(!item.onlyModule && innerRequest.startsWith(item.name + "/")) | ||
) { | ||
const remainingRequest = innerRequest.substr(item.name.length); | ||
const resolveWithAlias = (alias, callback) => { | ||
if ( | ||
innerRequest !== alias && | ||
!innerRequest.startsWith(alias + "/") | ||
) { | ||
shouldStop = true; | ||
const newRequestStr = alias + remainingRequest; | ||
const obj = { | ||
...request, | ||
request: newRequestStr | ||
}; | ||
return resolver.doResolve( | ||
target, | ||
obj, | ||
"aliased with mapping '" + | ||
item.name + | ||
"': '" + | ||
alias + | ||
"' to '" + | ||
newRequestStr + | ||
"'", | ||
resolveContext, | ||
(err, result) => { | ||
if (err) return callback(err); | ||
if (result) return callback(null, result); | ||
return callback(); | ||
} | ||
); | ||
} | ||
return callback(); | ||
}; | ||
const stoppingCallback = (err, result) => { | ||
if (err) return callback(err); | ||
// Don't allow other aliasing or raw request | ||
if(result === undefined) return callback(null, null); | ||
callback(null, result); | ||
}); | ||
} | ||
} | ||
} | ||
return callback(); | ||
}); | ||
if (result) return callback(null, result); | ||
// Don't allow other aliasing or raw request | ||
if (shouldStop) return callback(null, null); | ||
return callback(); | ||
}; | ||
if (Array.isArray(item.alias)) { | ||
return forEachBail( | ||
item.alias, | ||
resolveWithAlias, | ||
stoppingCallback | ||
); | ||
} else { | ||
return resolveWithAlias(item.alias, stoppingCallback); | ||
} | ||
} | ||
return callback(); | ||
}, | ||
callback | ||
); | ||
}); | ||
} | ||
}; |
@@ -16,10 +16,20 @@ /* | ||
const target = resolver.ensureHook(this.target); | ||
resolver.getHook(this.source).tapAsync("AppendPlugin", (request, resolveContext, callback) => { | ||
const obj = Object.assign({}, request, { | ||
path: request.path + this.appending, | ||
relativePath: request.relativePath && (request.relativePath + this.appending) | ||
resolver | ||
.getHook(this.source) | ||
.tapAsync("AppendPlugin", (request, resolveContext, callback) => { | ||
const obj = { | ||
...request, | ||
path: request.path + this.appending, | ||
relativePath: | ||
request.relativePath && request.relativePath + this.appending | ||
}; | ||
resolver.doResolve( | ||
target, | ||
obj, | ||
this.appending, | ||
resolveContext, | ||
callback | ||
); | ||
}); | ||
resolver.doResolve(target, obj, this.appending, resolveContext, callback); | ||
}); | ||
} | ||
}; |
@@ -13,6 +13,15 @@ /* | ||
this.levels = []; | ||
if(duration > 0) { | ||
this.levels.push(new Set(), new Set(), new Set(), new Set(), new Set(), new Set(), new Set(), new Set(), new Set()); | ||
for(let i = 8000; i < duration; i += 500) | ||
this.levels.push(new Set()); | ||
if (duration > 0) { | ||
this.levels.push( | ||
new Set(), | ||
new Set(), | ||
new Set(), | ||
new Set(), | ||
new Set(), | ||
new Set(), | ||
new Set(), | ||
new Set(), | ||
new Set() | ||
); | ||
for (let i = 8000; i < duration; i += 500) this.levels.push(new Set()); | ||
} | ||
@@ -28,4 +37,7 @@ this.count = 0; | ||
ensureTick() { | ||
if(!this.interval && this.duration > 0 && !this.nextTick) | ||
this.interval = setInterval(this.tick, Math.floor(this.duration / this.levels.length)); | ||
if (!this.interval && this.duration > 0 && !this.nextTick) | ||
this.interval = setInterval( | ||
this.tick, | ||
Math.floor(this.duration / this.levels.length) | ||
); | ||
} | ||
@@ -36,3 +48,3 @@ | ||
this.running.delete(name); | ||
if(this.duration > 0) { | ||
if (this.duration > 0) { | ||
this.data.set(name, [err, result]); | ||
@@ -45,3 +57,3 @@ const levelData = this.levels[0]; | ||
} | ||
for(let i = 0; i < callbacks.length; i++) { | ||
for (let i = 0; i < callbacks.length; i++) { | ||
callbacks[i](err, result); | ||
@@ -52,3 +64,3 @@ } | ||
finishedSync(name, err, result) { | ||
if(this.duration > 0) { | ||
if (this.duration > 0) { | ||
this.data.set(name, [err, result]); | ||
@@ -64,3 +76,3 @@ const levelData = this.levels[0]; | ||
provide(name, provider, callback) { | ||
if(typeof name !== "string") { | ||
if (typeof name !== "string") { | ||
callback(new TypeError("path must be a string")); | ||
@@ -70,10 +82,10 @@ return; | ||
let running = this.running.get(name); | ||
if(running) { | ||
if (running) { | ||
running.push(callback); | ||
return; | ||
} | ||
if(this.duration > 0) { | ||
if (this.duration > 0) { | ||
this.checkTicks(); | ||
const data = this.data.get(name); | ||
if(data) { | ||
if (data) { | ||
return process.nextTick(() => { | ||
@@ -84,3 +96,3 @@ callback.apply(null, data); | ||
} | ||
this.running.set(name, running = [callback]); | ||
this.running.set(name, (running = [callback])); | ||
provider(name, (err, result) => { | ||
@@ -92,11 +104,10 @@ this.finished(name, err, result); | ||
provideSync(name, provider) { | ||
if(typeof name !== "string") { | ||
if (typeof name !== "string") { | ||
throw new TypeError("path must be a string"); | ||
} | ||
if(this.duration > 0) { | ||
if (this.duration > 0) { | ||
this.checkTicks(); | ||
const data = this.data.get(name); | ||
if(data) { | ||
if(data[0]) | ||
throw data[0]; | ||
if (data) { | ||
if (data[0]) throw data[0]; | ||
return data[1]; | ||
@@ -108,3 +119,3 @@ } | ||
result = provider(name); | ||
} catch(e) { | ||
} catch (e) { | ||
this.finishedSync(name, e); | ||
@@ -119,3 +130,3 @@ throw e; | ||
const decay = this.levels.pop(); | ||
for(let item of decay) { | ||
for (let item of decay) { | ||
this.data.delete(item); | ||
@@ -126,3 +137,3 @@ } | ||
this.levels.unshift(decay); | ||
if(this.count === 0) { | ||
if (this.count === 0) { | ||
clearInterval(this.interval); | ||
@@ -132,14 +143,18 @@ this.interval = null; | ||
return true; | ||
} else if(this.nextTick) { | ||
} else if (this.nextTick) { | ||
this.nextTick += Math.floor(this.duration / this.levels.length); | ||
const time = new Date().getTime(); | ||
if(this.nextTick > time) { | ||
if (this.nextTick > time) { | ||
this.nextTick = null; | ||
this.interval = setInterval(this.tick, Math.floor(this.duration / this.levels.length)); | ||
this.interval = setInterval( | ||
this.tick, | ||
Math.floor(this.duration / this.levels.length) | ||
); | ||
return true; | ||
} | ||
} else if(this.passive) { | ||
} else if (this.passive) { | ||
clearInterval(this.interval); | ||
this.interval = null; | ||
this.nextTick = new Date().getTime() + Math.floor(this.duration / this.levels.length); | ||
this.nextTick = | ||
new Date().getTime() + Math.floor(this.duration / this.levels.length); | ||
} else { | ||
@@ -152,4 +167,4 @@ this.passive = true; | ||
this.passive = false; | ||
if(this.nextTick) { | ||
while(!this.tick()); | ||
if (this.nextTick) { | ||
while (!this.tick()); | ||
} | ||
@@ -159,3 +174,3 @@ } | ||
purge(what) { | ||
if(!what) { | ||
if (!what) { | ||
this.count = 0; | ||
@@ -168,9 +183,8 @@ clearInterval(this.interval); | ||
}); | ||
} else if(typeof what === "string") { | ||
for(let key of this.data.keys()) { | ||
if(key.startsWith(what)) | ||
this.data.delete(key); | ||
} else if (typeof what === "string") { | ||
for (let key of this.data.keys()) { | ||
if (key.startsWith(what)) this.data.delete(key); | ||
} | ||
} else { | ||
for(let i = what.length - 1; i >= 0; i--) { | ||
for (let i = what.length - 1; i >= 0; i--) { | ||
this.purge(what[i]); | ||
@@ -191,30 +205,42 @@ } | ||
this._stat = this.fileSystem.stat ? this.fileSystem.stat.bind(this.fileSystem) : null; | ||
if(!this._stat) this.stat = null; | ||
this._stat = this.fileSystem.stat | ||
? this.fileSystem.stat.bind(this.fileSystem) | ||
: null; | ||
if (!this._stat) this.stat = null; | ||
this._statSync = this.fileSystem.statSync ? this.fileSystem.statSync.bind(this.fileSystem) : null; | ||
if(!this._statSync) this.statSync = null; | ||
this._statSync = this.fileSystem.statSync | ||
? this.fileSystem.statSync.bind(this.fileSystem) | ||
: null; | ||
if (!this._statSync) this.statSync = null; | ||
this._readdir = this.fileSystem.readdir ? this.fileSystem.readdir.bind(this.fileSystem) : null; | ||
if(!this._readdir) this.readdir = null; | ||
this._readdir = this.fileSystem.readdir | ||
? this.fileSystem.readdir.bind(this.fileSystem) | ||
: null; | ||
if (!this._readdir) this.readdir = null; | ||
this._readdirSync = this.fileSystem.readdirSync ? this.fileSystem.readdirSync.bind(this.fileSystem) : null; | ||
if(!this._readdirSync) this.readdirSync = null; | ||
this._readdirSync = this.fileSystem.readdirSync | ||
? this.fileSystem.readdirSync.bind(this.fileSystem) | ||
: null; | ||
if (!this._readdirSync) this.readdirSync = null; | ||
this._readFile = this.fileSystem.readFile ? this.fileSystem.readFile.bind(this.fileSystem) : null; | ||
if(!this._readFile) this.readFile = null; | ||
this._readFile = this.fileSystem.readFile | ||
? this.fileSystem.readFile.bind(this.fileSystem) | ||
: null; | ||
if (!this._readFile) this.readFile = null; | ||
this._readFileSync = this.fileSystem.readFileSync ? this.fileSystem.readFileSync.bind(this.fileSystem) : null; | ||
if(!this._readFileSync) this.readFileSync = null; | ||
this._readFileSync = this.fileSystem.readFileSync | ||
? this.fileSystem.readFileSync.bind(this.fileSystem) | ||
: null; | ||
if (!this._readFileSync) this.readFileSync = null; | ||
if(this.fileSystem.readJson) { | ||
if (this.fileSystem.readJson) { | ||
this._readJson = this.fileSystem.readJson.bind(this.fileSystem); | ||
} else if(this.readFile) { | ||
} else if (this.readFile) { | ||
this._readJson = (path, callback) => { | ||
this.readFile(path, (err, buffer) => { | ||
if(err) return callback(err); | ||
if (err) return callback(err); | ||
let data; | ||
try { | ||
data = JSON.parse(buffer.toString("utf-8")); | ||
} catch(e) { | ||
} catch (e) { | ||
return callback(e); | ||
@@ -228,6 +254,6 @@ } | ||
} | ||
if(this.fileSystem.readJsonSync) { | ||
if (this.fileSystem.readJsonSync) { | ||
this._readJsonSync = this.fileSystem.readJsonSync.bind(this.fileSystem); | ||
} else if(this.readFileSync) { | ||
this._readJsonSync = (path) => { | ||
} else if (this.readFileSync) { | ||
this._readJsonSync = path => { | ||
const buffer = this.readFileSync(path); | ||
@@ -241,7 +267,11 @@ const data = JSON.parse(buffer.toString("utf-8")); | ||
this._readlink = this.fileSystem.readlink ? this.fileSystem.readlink.bind(this.fileSystem) : null; | ||
if(!this._readlink) this.readlink = null; | ||
this._readlink = this.fileSystem.readlink | ||
? this.fileSystem.readlink.bind(this.fileSystem) | ||
: null; | ||
if (!this._readlink) this.readlink = null; | ||
this._readlinkSync = this.fileSystem.readlinkSync ? this.fileSystem.readlinkSync.bind(this.fileSystem) : null; | ||
if(!this._readlinkSync) this.readlinkSync = null; | ||
this._readlinkSync = this.fileSystem.readlinkSync | ||
? this.fileSystem.readlinkSync.bind(this.fileSystem) | ||
: null; | ||
if (!this._readlinkSync) this.readlinkSync = null; | ||
} | ||
@@ -248,0 +278,0 @@ |
@@ -17,12 +17,23 @@ /* | ||
const target = resolver.ensureHook(this.target); | ||
resolver.getHook(this.source).tapAsync("CloneBasenamePlugin", (request, resolveContext, callback) => { | ||
const filename = basename(request.path); | ||
const filePath = resolver.join(request.path, filename); | ||
const obj = Object.assign({}, request, { | ||
path: filePath, | ||
relativePath: request.relativePath && resolver.join(request.relativePath, filename) | ||
resolver | ||
.getHook(this.source) | ||
.tapAsync("CloneBasenamePlugin", (request, resolveContext, callback) => { | ||
const filename = basename(request.path); | ||
const filePath = resolver.join(request.path, filename); | ||
const obj = { | ||
...request, | ||
path: filePath, | ||
relativePath: | ||
request.relativePath && | ||
resolver.join(request.relativePath, filename) | ||
}; | ||
resolver.doResolve( | ||
target, | ||
obj, | ||
"using path: " + filePath, | ||
resolveContext, | ||
callback | ||
); | ||
}); | ||
resolver.doResolve(target, obj, "using path: " + filePath, resolveContext, callback); | ||
}); | ||
} | ||
}; |
@@ -7,10 +7,13 @@ /* | ||
module.exports = function createInnerContext(options, message, messageOptional) { | ||
module.exports = function createInnerContext( | ||
options, | ||
message, | ||
messageOptional | ||
) { | ||
let messageReported = false; | ||
const childContext = { | ||
log: (() => { | ||
if(!options.log) return undefined; | ||
if(!message) return options.log; | ||
const logFunction = (msg) => { | ||
if(!messageReported) { | ||
let innerLog = undefined; | ||
if (options.log) { | ||
if (message) { | ||
innerLog = msg => { | ||
if (!messageReported) { | ||
options.log(message); | ||
@@ -21,8 +24,14 @@ messageReported = true; | ||
}; | ||
return logFunction; | ||
})(), | ||
stack: options.stack, | ||
missing: options.missing | ||
} else { | ||
innerLog = options.log; | ||
} | ||
} | ||
const childContext = { | ||
log: innerLog, | ||
fileDependencies: options.fileDependencies, | ||
contextDependencies: options.contextDependencies, | ||
missingDependencies: options.missingDependencies, | ||
stack: options.stack | ||
}; | ||
return childContext; | ||
}; |
@@ -10,5 +10,6 @@ /* | ||
module.exports = class DescriptionFilePlugin { | ||
constructor(source, filenames, target) { | ||
constructor(source, filenames, pathIsFile, target) { | ||
this.source = source; | ||
this.filenames = [].concat(filenames); | ||
this.pathIsFile = pathIsFile; | ||
this.target = target; | ||
@@ -19,32 +20,64 @@ } | ||
const target = resolver.ensureHook(this.target); | ||
resolver.getHook(this.source).tapAsync("DescriptionFilePlugin", (request, resolveContext, callback) => { | ||
const directory = request.path; | ||
DescriptionFileUtils.loadDescriptionFile(resolver, directory, this.filenames, resolveContext, (err, result) => { | ||
if(err) return callback(err); | ||
if(!result) { | ||
if(resolveContext.missing) { | ||
this.filenames.forEach((filename) => { | ||
resolveContext.missing.add(resolver.join(directory, filename)); | ||
}); | ||
} | ||
if(resolveContext.log) resolveContext.log("No description file found"); | ||
return callback(); | ||
resolver | ||
.getHook(this.source) | ||
.tapAsync( | ||
"DescriptionFilePlugin", | ||
(request, resolveContext, callback) => { | ||
const directory = this.pathIsFile | ||
? DescriptionFileUtils.cdUp(request.path) | ||
: request.path; | ||
if (!directory) return callback(); | ||
DescriptionFileUtils.loadDescriptionFile( | ||
resolver, | ||
directory, | ||
this.filenames, | ||
request.descriptionFilePath && { | ||
path: request.descriptionFilePath, | ||
content: request.descriptionFileData, | ||
directory: request.descriptionFileRoot | ||
}, | ||
resolveContext, | ||
(err, result) => { | ||
if (err) return callback(err); | ||
if (!result) { | ||
if (resolveContext.log) | ||
resolveContext.log( | ||
`No description file found in ${directory} or above` | ||
); | ||
return callback(); | ||
} | ||
const relativePath = | ||
"." + | ||
request.path | ||
.substr(result.directory.length) | ||
.replace(/\\/g, "/"); | ||
const obj = { | ||
...request, | ||
descriptionFilePath: result.path, | ||
descriptionFileData: result.content, | ||
descriptionFileRoot: result.directory, | ||
relativePath: relativePath | ||
}; | ||
resolver.doResolve( | ||
target, | ||
obj, | ||
"using description file: " + | ||
result.path + | ||
" (relative path: " + | ||
relativePath + | ||
")", | ||
resolveContext, | ||
(err, result) => { | ||
if (err) return callback(err); | ||
// Don't allow other processing | ||
if (result === undefined) return callback(null, null); | ||
callback(null, result); | ||
} | ||
); | ||
} | ||
); | ||
} | ||
const relativePath = "." + request.path.substr(result.directory.length).replace(/\\/g, "/"); | ||
const obj = Object.assign({}, request, { | ||
descriptionFilePath: result.path, | ||
descriptionFileData: result.content, | ||
descriptionFileRoot: result.directory, | ||
relativePath: relativePath | ||
}); | ||
resolver.doResolve(target, obj, "using description file: " + result.path + " (relative path: " + relativePath + ")", resolveContext, (err, result) => { | ||
if(err) return callback(err); | ||
// Don't allow other processing | ||
if(result === undefined) return callback(null, null); | ||
callback(null, result); | ||
}); | ||
}); | ||
}); | ||
); | ||
} | ||
}; |
@@ -9,63 +9,100 @@ /* | ||
function loadDescriptionFile(resolver, directory, filenames, resolveContext, callback) { | ||
function loadDescriptionFile( | ||
resolver, | ||
directory, | ||
filenames, | ||
oldInfo, | ||
resolveContext, | ||
callback | ||
) { | ||
(function findDescriptionFile() { | ||
forEachBail(filenames, (filename, callback) => { | ||
const descriptionFilePath = resolver.join(directory, filename); | ||
if(resolver.fileSystem.readJson) { | ||
resolver.fileSystem.readJson(descriptionFilePath, (err, content) => { | ||
if(err) { | ||
if(typeof err.code !== "undefined") return callback(); | ||
return onJson(err); | ||
if (oldInfo && oldInfo.directory === directory) { | ||
// We already have info for this directory and can reuse it | ||
return callback(null, oldInfo); | ||
} | ||
forEachBail( | ||
filenames, | ||
(filename, callback) => { | ||
const descriptionFilePath = resolver.join(directory, filename); | ||
if (resolver.fileSystem.readJson) { | ||
resolver.fileSystem.readJson(descriptionFilePath, (err, content) => { | ||
if (err) { | ||
if (typeof err.code !== "undefined") { | ||
if (resolveContext.missingDependencies) { | ||
resolveContext.missingDependencies.add(descriptionFilePath); | ||
} | ||
return callback(); | ||
} | ||
if (resolveContext.fileDependencies) { | ||
resolveContext.fileDependencies.add(descriptionFilePath); | ||
} | ||
return onJson(err); | ||
} | ||
if (resolveContext.fileDependencies) { | ||
resolveContext.fileDependencies.add(descriptionFilePath); | ||
} | ||
onJson(null, content); | ||
}); | ||
} else { | ||
resolver.fileSystem.readFile(descriptionFilePath, (err, content) => { | ||
if (err) { | ||
if (resolveContext.missingDependencies) { | ||
resolveContext.missingDependencies.add(descriptionFilePath); | ||
} | ||
return callback(); | ||
} | ||
if (resolveContext.fileDependencies) { | ||
resolveContext.fileDependencies.add(descriptionFilePath); | ||
} | ||
let json; | ||
try { | ||
json = JSON.parse(content); | ||
} catch (e) { | ||
onJson(e); | ||
} | ||
onJson(null, json); | ||
}); | ||
} | ||
function onJson(err, content) { | ||
if (err) { | ||
if (resolveContext.log) | ||
resolveContext.log( | ||
descriptionFilePath + " (directory description file): " + err | ||
); | ||
else | ||
err.message = | ||
descriptionFilePath + " (directory description file): " + err; | ||
return callback(err); | ||
} | ||
onJson(null, content); | ||
}); | ||
} else { | ||
resolver.fileSystem.readFile(descriptionFilePath, (err, content) => { | ||
if(err) return callback(); | ||
let json; | ||
try { | ||
json = JSON.parse(content); | ||
} catch(e) { | ||
onJson(e); | ||
} | ||
onJson(null, json); | ||
}); | ||
} | ||
function onJson(err, content) { | ||
if(err) { | ||
if(resolveContext.log) | ||
resolveContext.log(descriptionFilePath + " (directory description file): " + err); | ||
else | ||
err.message = descriptionFilePath + " (directory description file): " + err; | ||
return callback(err); | ||
callback(null, { | ||
content: content, | ||
directory: directory, | ||
path: descriptionFilePath | ||
}); | ||
} | ||
callback(null, { | ||
content: content, | ||
directory: directory, | ||
path: descriptionFilePath | ||
}); | ||
} | ||
}, (err, result) => { | ||
if(err) return callback(err); | ||
if(result) { | ||
return callback(null, result); | ||
} else { | ||
directory = cdUp(directory); | ||
if(!directory) { | ||
return callback(); | ||
}, | ||
(err, result) => { | ||
if (err) return callback(err); | ||
if (result) { | ||
return callback(null, result); | ||
} else { | ||
return findDescriptionFile(); | ||
directory = cdUp(directory); | ||
if (!directory) { | ||
return callback(); | ||
} else { | ||
return findDescriptionFile(); | ||
} | ||
} | ||
} | ||
}); | ||
}()); | ||
); | ||
})(); | ||
} | ||
function getField(content, field) { | ||
if(!content) return undefined; | ||
if(Array.isArray(field)) { | ||
if (!content) return undefined; | ||
if (Array.isArray(field)) { | ||
let current = content; | ||
for(let j = 0; j < field.length; j++) { | ||
if(current === null || typeof current !== "object") { | ||
for (let j = 0; j < field.length; j++) { | ||
if (current === null || typeof current !== "object") { | ||
current = null; | ||
@@ -76,7 +113,7 @@ break; | ||
} | ||
if(typeof current === "object") { | ||
if (typeof current === "object") { | ||
return current; | ||
} | ||
} else { | ||
if(typeof content[field] === "object") { | ||
if (typeof content[field] === "object") { | ||
return content[field]; | ||
@@ -88,7 +125,7 @@ } | ||
function cdUp(directory) { | ||
if(directory === "/") return null; | ||
if (directory === "/") return null; | ||
const i = directory.lastIndexOf("/"), | ||
j = directory.lastIndexOf("\\"); | ||
const p = i < 0 ? j : j < 0 ? i : i < j ? j : i; | ||
if(p < 0) return null; | ||
if (p < 0) return null; | ||
return directory.substr(0, p || 1); | ||
@@ -95,0 +132,0 @@ } |
@@ -15,20 +15,37 @@ /* | ||
const target = resolver.ensureHook(this.target); | ||
resolver.getHook(this.source).tapAsync("DirectoryExistsPlugin", (request, resolveContext, callback) => { | ||
const fs = resolver.fileSystem; | ||
const directory = request.path; | ||
fs.stat(directory, (err, stat) => { | ||
if(err || !stat) { | ||
if(resolveContext.missing) resolveContext.missing.add(directory); | ||
if(resolveContext.log) resolveContext.log(directory + " doesn't exist"); | ||
return callback(); | ||
resolver | ||
.getHook(this.source) | ||
.tapAsync( | ||
"DirectoryExistsPlugin", | ||
(request, resolveContext, callback) => { | ||
const fs = resolver.fileSystem; | ||
const directory = request.path; | ||
fs.stat(directory, (err, stat) => { | ||
if (err || !stat) { | ||
if (resolveContext.missingDependencies) | ||
resolveContext.missingDependencies.add(directory); | ||
if (resolveContext.log) | ||
resolveContext.log(directory + " doesn't exist"); | ||
return callback(); | ||
} | ||
if (!stat.isDirectory()) { | ||
if (resolveContext.missingDependencies) | ||
resolveContext.missingDependencies.add(directory); | ||
if (resolveContext.log) | ||
resolveContext.log(directory + " is not a directory"); | ||
return callback(); | ||
} | ||
if (resolveContext.fileDependencies) | ||
resolveContext.fileDependencies.add(directory); | ||
resolver.doResolve( | ||
target, | ||
request, | ||
`existing directory ${directory}`, | ||
resolveContext, | ||
callback | ||
); | ||
}); | ||
} | ||
if(!stat.isDirectory()) { | ||
if(resolveContext.missing) resolveContext.missing.add(directory); | ||
if(resolveContext.log) resolveContext.log(directory + " is not a directory"); | ||
return callback(); | ||
} | ||
resolver.doResolve(target, request, "existing directory", resolveContext, callback); | ||
}); | ||
}); | ||
); | ||
} | ||
}; |
@@ -16,19 +16,31 @@ /* | ||
const fs = resolver.fileSystem; | ||
resolver.getHook(this.source).tapAsync("FileExistsPlugin", (request, resolveContext, callback) => { | ||
const file = request.path; | ||
fs.stat(file, (err, stat) => { | ||
if(err || !stat) { | ||
if(resolveContext.missing) resolveContext.missing.add(file); | ||
if(resolveContext.log) resolveContext.log(file + " doesn't exist"); | ||
return callback(); | ||
} | ||
if(!stat.isFile()) { | ||
if(resolveContext.missing) resolveContext.missing.add(file); | ||
if(resolveContext.log) resolveContext.log(file + " is not a file"); | ||
return callback(); | ||
} | ||
resolver.doResolve(target, request, "existing file: " + file, resolveContext, callback); | ||
resolver | ||
.getHook(this.source) | ||
.tapAsync("FileExistsPlugin", (request, resolveContext, callback) => { | ||
const file = request.path; | ||
fs.stat(file, (err, stat) => { | ||
if (err || !stat) { | ||
if (resolveContext.missingDependencies) | ||
resolveContext.missingDependencies.add(file); | ||
if (resolveContext.log) resolveContext.log(file + " doesn't exist"); | ||
return callback(); | ||
} | ||
if (!stat.isFile()) { | ||
if (resolveContext.missingDependencies) | ||
resolveContext.missingDependencies.add(file); | ||
if (resolveContext.log) resolveContext.log(file + " is not a file"); | ||
return callback(); | ||
} | ||
if (resolveContext.fileDependencies) | ||
resolveContext.fileDependencies.add(file); | ||
resolver.doResolve( | ||
target, | ||
request, | ||
"existing file: " + file, | ||
resolveContext, | ||
callback | ||
); | ||
}); | ||
}); | ||
}); | ||
} | ||
}; |
@@ -15,9 +15,9 @@ /* | ||
const target = resolver.ensureHook(this.target); | ||
resolver.getHook(this.source).tapAsync("FileKindPlugin", (request, resolveContext, callback) => { | ||
if(request.directory) return callback(); | ||
const obj = Object.assign({}, request); | ||
delete obj.directory; | ||
resolver.doResolve(target, obj, null, resolveContext, callback); | ||
}); | ||
resolver | ||
.getHook(this.source) | ||
.tapAsync("FileKindPlugin", (request, resolveContext, callback) => { | ||
if (request.directory) return callback(); | ||
resolver.doResolve(target, request, null, resolveContext, callback); | ||
}); | ||
} | ||
}; |
@@ -8,59 +8,55 @@ /* | ||
module.exports = function forEachBail(array, iterator, callback) { | ||
if(array.length === 0) return callback(); | ||
let currentPos = array.length; | ||
let currentResult; | ||
let done = []; | ||
for(let i = 0; i < array.length; i++) { | ||
const itCb = createIteratorCallback(i); | ||
iterator(array[i], itCb); | ||
if(currentPos === 0) break; | ||
} | ||
if (array.length === 0) return callback(); | ||
function createIteratorCallback(i) { | ||
return(...args) => { // eslint-disable-line | ||
if(i >= currentPos) return; // ignore | ||
done.push(i); | ||
if(args.length > 0) { | ||
currentPos = i + 1; | ||
done = done.filter(item => { | ||
return item <= i; | ||
}); | ||
currentResult = args; | ||
let index = 0; | ||
let inCall = true; | ||
let inCallResult; | ||
const innerCallback = (err, result) => { | ||
if (err || result !== undefined) { | ||
if (inCall) { | ||
inCallResult = [err, result]; | ||
return; | ||
} | ||
if(done.length === currentPos) { | ||
callback.apply(null, currentResult); | ||
currentPos = 0; | ||
callback(err, result); | ||
return; | ||
} | ||
if (inCall) { | ||
inCallResult = true; | ||
return; | ||
} | ||
inCall = true; | ||
// eslint-disable-next-line no-constant-condition | ||
while (true) { | ||
if (index === array.length) return callback(); | ||
iterator(array[index++], innerCallback); | ||
if (inCallResult !== undefined) { | ||
if (inCallResult !== true) { | ||
return callback(...inCallResult); | ||
} | ||
inCallResult = undefined; | ||
// continue loop | ||
} else { | ||
inCall = false; | ||
return; | ||
} | ||
}; | ||
} | ||
}; | ||
} | ||
}; | ||
module.exports.withIndex = function forEachBailWithIndex(array, iterator, callback) { | ||
if(array.length === 0) return callback(); | ||
let currentPos = array.length; | ||
let currentResult; | ||
let done = []; | ||
for(let i = 0; i < array.length; i++) { | ||
const itCb = createIteratorCallback(i); | ||
iterator(array[i], i, itCb); | ||
if(currentPos === 0) break; | ||
} | ||
function createIteratorCallback(i) { | ||
return(...args) => { // eslint-disable-line | ||
if(i >= currentPos) return; // ignore | ||
done.push(i); | ||
if(args.length > 0) { | ||
currentPos = i + 1; | ||
done = done.filter(item => { | ||
return item <= i; | ||
}); | ||
currentResult = args; | ||
inCall = true; | ||
// eslint-disable-next-line no-constant-condition | ||
while (true) { | ||
if (index === array.length) return callback(); | ||
iterator(array[index++], innerCallback); | ||
if (inCallResult !== undefined) { | ||
if (inCallResult !== true) { | ||
return callback(...inCallResult); | ||
} | ||
if(done.length === currentPos) { | ||
callback.apply(null, currentResult); | ||
currentPos = 0; | ||
} | ||
}; | ||
inCallResult = undefined; | ||
// continue loop | ||
} else { | ||
inCall = false; | ||
return; | ||
} | ||
} | ||
}; |
@@ -8,10 +8,12 @@ /* | ||
module.exports = function getInnerRequest(resolver, request) { | ||
if(typeof request.__innerRequest === "string" && | ||
if ( | ||
typeof request.__innerRequest === "string" && | ||
request.__innerRequest_request === request.request && | ||
request.__innerRequest_relativePath === request.relativePath) | ||
request.__innerRequest_relativePath === request.relativePath | ||
) | ||
return request.__innerRequest; | ||
let innerRequest; | ||
if(request.request) { | ||
if (request.request) { | ||
innerRequest = request.request; | ||
if(/^\.\.?\//.test(innerRequest) && request.relativePath) { | ||
if (/^\.\.?\//.test(innerRequest) && request.relativePath) { | ||
innerRequest = resolver.join(request.relativePath, innerRequest); | ||
@@ -24,3 +26,3 @@ } | ||
request.__innerRequest_relativePath = request.relativePath; | ||
return request.__innerRequest = innerRequest; | ||
return (request.__innerRequest = innerRequest); | ||
}; |
@@ -8,3 +8,3 @@ /* | ||
module.exports = function getPaths(path) { | ||
const parts = path.split(/(.*?[\\\/]+)/); | ||
const parts = path.split(/(.*?[\\/]+)/); | ||
const paths = [path]; | ||
@@ -14,3 +14,3 @@ const seqments = [parts[parts.length - 1]]; | ||
path = path.substr(0, path.length - part.length - 1); | ||
for(let i = parts.length - 2; i > 2; i -= 2) { | ||
for (let i = parts.length - 2; i > 2; i -= 2) { | ||
paths.push(path); | ||
@@ -34,5 +34,5 @@ part = parts[i]; | ||
const p = i < 0 ? j : j < 0 ? i : i < j ? j : i; | ||
if(p < 0) return null; | ||
if (p < 0) return null; | ||
const s = path.substr(p + 1); | ||
return s; | ||
}; |
@@ -15,11 +15,16 @@ /* | ||
const target = resolver.ensureHook(this.target); | ||
resolver.getHook(this.source).tapAsync("JoinRequestPlugin", (request, resolveContext, callback) => { | ||
const obj = Object.assign({}, request, { | ||
path: resolver.join(request.path, request.request), | ||
relativePath: request.relativePath && resolver.join(request.relativePath, request.request), | ||
request: undefined | ||
resolver | ||
.getHook(this.source) | ||
.tapAsync("JoinRequestPlugin", (request, resolveContext, callback) => { | ||
const obj = { | ||
...request, | ||
path: resolver.join(request.path, request.request), | ||
relativePath: | ||
request.relativePath && | ||
resolver.join(request.relativePath, request.request), | ||
request: undefined | ||
}; | ||
resolver.doResolve(target, obj, null, resolveContext, callback); | ||
}); | ||
resolver.doResolve(target, obj, null, resolveContext, callback); | ||
}); | ||
} | ||
}; |
@@ -14,16 +14,29 @@ /* | ||
const source = this.source; | ||
resolver.getHook(this.source).tapAsync("LogInfoPlugin", (request, resolveContext, callback) => { | ||
if(!resolveContext.log) return callback(); | ||
const log = resolveContext.log; | ||
const prefix = "[" + source + "] "; | ||
if(request.path) log(prefix + "Resolving in directory: " + request.path); | ||
if(request.request) log(prefix + "Resolving request: " + request.request); | ||
if(request.module) log(prefix + "Request is an module request."); | ||
if(request.directory) log(prefix + "Request is a directory request."); | ||
if(request.query) log(prefix + "Resolving request query: " + request.query); | ||
if(request.descriptionFilePath) log(prefix + "Has description data from " + request.descriptionFilePath); | ||
if(request.relativePath) log(prefix + "Relative path from description file is: " + request.relativePath); | ||
callback(); | ||
}); | ||
resolver | ||
.getHook(this.source) | ||
.tapAsync("LogInfoPlugin", (request, resolveContext, callback) => { | ||
if (!resolveContext.log) return callback(); | ||
const log = resolveContext.log; | ||
const prefix = "[" + source + "] "; | ||
if (request.path) | ||
log(prefix + "Resolving in directory: " + request.path); | ||
if (request.request) | ||
log(prefix + "Resolving request: " + request.request); | ||
if (request.module) log(prefix + "Request is an module request."); | ||
if (request.directory) log(prefix + "Request is a directory request."); | ||
if (request.query) | ||
log(prefix + "Resolving request query: " + request.query); | ||
if (request.descriptionFilePath) | ||
log( | ||
prefix + "Has description data from " + request.descriptionFilePath | ||
); | ||
if (request.relativePath) | ||
log( | ||
prefix + | ||
"Relative path from description file is: " + | ||
request.relativePath | ||
); | ||
callback(); | ||
}); | ||
} | ||
}; |
@@ -18,36 +18,55 @@ /* | ||
const target = resolver.ensureHook(this.target); | ||
resolver.getHook(this.source).tapAsync("MainFieldPlugin", (request, resolveContext, callback) => { | ||
if(request.path !== request.descriptionFileRoot) return callback(); | ||
if(request.alreadyTriedMainField === 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; | ||
resolver | ||
.getHook(this.source) | ||
.tapAsync("MainFieldPlugin", (request, resolveContext, callback) => { | ||
if (request.path !== request.descriptionFileRoot) return callback(); | ||
if (request.alreadyTriedMainField === 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]]; | ||
} | ||
current = current[field[j]]; | ||
if (typeof current === "string") { | ||
mainModule = current; | ||
} | ||
} else { | ||
if (typeof content[field] === "string") { | ||
mainModule = content[field]; | ||
} | ||
} | ||
if(typeof current === "string") { | ||
mainModule = current; | ||
if (!mainModule || mainModule === "." || mainModule === "./") { | ||
return callback(); | ||
} | ||
} else { | ||
if(typeof content[field] === "string") { | ||
mainModule = content[field]; | ||
} | ||
} | ||
if(!mainModule) return callback(); | ||
if(this.options.forceRelative && !/^\.\.?\//.test(mainModule)) | ||
mainModule = "./" + mainModule; | ||
const obj = Object.assign({}, request, { | ||
request: mainModule, | ||
alreadyTriedMainField: request.descriptionFilePath | ||
if (this.options.forceRelative && !/^\.\.?\//.test(mainModule)) | ||
mainModule = "./" + mainModule; | ||
const obj = { | ||
...request, | ||
request: mainModule, | ||
module: false, | ||
directory: mainModule.endsWith("/"), | ||
alreadyTriedMainField: request.descriptionFilePath | ||
}; | ||
return resolver.doResolve( | ||
target, | ||
obj, | ||
"use " + | ||
mainModule + | ||
" from " + | ||
this.options.name + | ||
" in " + | ||
filename, | ||
resolveContext, | ||
callback | ||
); | ||
}); | ||
return resolver.doResolve(target, obj, "use " + mainModule + " from " + this.options.name + " in " + filename, resolveContext, callback); | ||
}); | ||
} | ||
}; |
@@ -15,15 +15,21 @@ /* | ||
const target = resolver.ensureHook(this.target); | ||
resolver.getHook(this.source).tapAsync("ModuleKindPlugin", (request, resolveContext, callback) => { | ||
if(!request.module) return callback(); | ||
const obj = Object.assign({}, request); | ||
delete obj.module; | ||
resolver.doResolve(target, obj, "resolve as module", resolveContext, (err, result) => { | ||
if(err) return callback(err); | ||
resolver | ||
.getHook(this.source) | ||
.tapAsync("ModuleKindPlugin", (request, resolveContext, callback) => { | ||
if (!request.module) return callback(); | ||
resolver.doResolve( | ||
target, | ||
request, | ||
"resolve as module", | ||
resolveContext, | ||
(err, result) => { | ||
if (err) return callback(err); | ||
// Don't allow other alternatives | ||
if(result === undefined) return callback(null, null); | ||
callback(null, result); | ||
// Don't allow other alternatives | ||
if (result === undefined) return callback(null, null); | ||
callback(null, result); | ||
} | ||
); | ||
}); | ||
}); | ||
} | ||
}; |
@@ -19,27 +19,50 @@ /* | ||
const target = resolver.ensureHook(this.target); | ||
resolver.getHook(this.source).tapAsync("ModulesInHierachicDirectoriesPlugin", (request, resolveContext, callback) => { | ||
const fs = resolver.fileSystem; | ||
const addrs = getPaths(request.path).paths.map(p => { | ||
return this.directories.map(d => resolver.join(p, d)); | ||
}).reduce((array, p) => { | ||
array.push.apply(array, p); | ||
return array; | ||
}, []); | ||
forEachBail(addrs, (addr, callback) => { | ||
fs.stat(addr, (err, stat) => { | ||
if(!err && stat && stat.isDirectory()) { | ||
const obj = Object.assign({}, request, { | ||
path: addr, | ||
request: "./" + request.request | ||
}); | ||
const message = "looking for modules in " + addr; | ||
return resolver.doResolve(target, obj, message, resolveContext, callback); | ||
} | ||
if(resolveContext.log) resolveContext.log(addr + " doesn't exist or is not a directory"); | ||
if(resolveContext.missing) resolveContext.missing.add(addr); | ||
return callback(); | ||
}); | ||
}, callback); | ||
}); | ||
resolver | ||
.getHook(this.source) | ||
.tapAsync( | ||
"ModulesInHierachicDirectoriesPlugin", | ||
(request, resolveContext, callback) => { | ||
const fs = resolver.fileSystem; | ||
const addrs = getPaths(request.path) | ||
.paths.map(p => { | ||
return this.directories.map(d => resolver.join(p, d)); | ||
}) | ||
.reduce((array, p) => { | ||
array.push.apply(array, p); | ||
return array; | ||
}, []); | ||
forEachBail( | ||
addrs, | ||
(addr, callback) => { | ||
fs.stat(addr, (err, stat) => { | ||
if (!err && stat && stat.isDirectory()) { | ||
const obj = { | ||
...request, | ||
path: addr, | ||
request: "./" + request.request, | ||
module: false | ||
}; | ||
const message = "looking for modules in " + addr; | ||
return resolver.doResolve( | ||
target, | ||
obj, | ||
message, | ||
resolveContext, | ||
callback | ||
); | ||
} | ||
if (resolveContext.log) | ||
resolveContext.log( | ||
addr + " doesn't exist or is not a directory" | ||
); | ||
if (resolveContext.missingDependencies) | ||
resolveContext.missingDependencies.add(addr); | ||
return callback(); | ||
}); | ||
}, | ||
callback | ||
); | ||
} | ||
); | ||
} | ||
}; |
@@ -16,10 +16,20 @@ /* | ||
const target = resolver.ensureHook(this.target); | ||
resolver.getHook(this.source).tapAsync("ModulesInRootPlugin", (request, resolveContext, callback) => { | ||
const obj = Object.assign({}, request, { | ||
path: this.path, | ||
request: "./" + request.request | ||
resolver | ||
.getHook(this.source) | ||
.tapAsync("ModulesInRootPlugin", (request, resolveContext, callback) => { | ||
const obj = { | ||
...request, | ||
path: this.path, | ||
request: "./" + request.request, | ||
module: false | ||
}; | ||
resolver.doResolve( | ||
target, | ||
obj, | ||
"looking for modules in " + this.path, | ||
resolveContext, | ||
callback | ||
); | ||
}); | ||
resolver.doResolve(target, obj, "looking for modules in " + this.path, resolveContext, callback); | ||
}); | ||
} | ||
}; |
@@ -15,6 +15,8 @@ /* | ||
const target = resolver.ensureHook(this.target); | ||
resolver.getHook(this.source).tapAsync("NextPlugin", (request, resolveContext, callback) => { | ||
resolver.doResolve(target, request, null, resolveContext, callback); | ||
}); | ||
resolver | ||
.getHook(this.source) | ||
.tapAsync("NextPlugin", (request, resolveContext, callback) => { | ||
resolver.doResolve(target, request, null, resolveContext, callback); | ||
}); | ||
} | ||
}; |
114
lib/node.js
@@ -7,13 +7,10 @@ /* | ||
const fs = require("fs"); | ||
const ResolverFactory = require("./ResolverFactory"); | ||
const NodeJsInputFileSystem = require("./NodeJsInputFileSystem"); | ||
const CachedInputFileSystem = require("./CachedInputFileSystem"); | ||
const nodeFileSystem = new CachedInputFileSystem(new NodeJsInputFileSystem(), 4000); | ||
const nodeFileSystem = new CachedInputFileSystem(fs, 4000); | ||
const nodeContext = { | ||
environments: [ | ||
"node+es3+es5+process+native" | ||
] | ||
environments: ["node+es3+es5+process+native"] | ||
}; | ||
@@ -25,4 +22,10 @@ | ||
}); | ||
module.exports = function resolve(context, path, request, resolveContext, callback) { | ||
if(typeof context === "string") { | ||
module.exports = function resolve( | ||
context, | ||
path, | ||
request, | ||
resolveContext, | ||
callback | ||
) { | ||
if (typeof context === "string") { | ||
callback = resolveContext; | ||
@@ -34,3 +37,3 @@ resolveContext = request; | ||
} | ||
if(typeof callback !== "function") { | ||
if (typeof callback !== "function") { | ||
callback = resolveContext; | ||
@@ -47,3 +50,3 @@ } | ||
module.exports.sync = function resolveSync(context, path, request) { | ||
if(typeof context === "string") { | ||
if (typeof context === "string") { | ||
request = path; | ||
@@ -56,79 +59,10 @@ path = context; | ||
const asyncContextResolver = ResolverFactory.createResolver({ | ||
extensions: [".js", ".json", ".node"], | ||
resolveToContext: true, | ||
fileSystem: nodeFileSystem | ||
}); | ||
module.exports.context = function resolveContext(context, path, request, resolveContext, callback) { | ||
if(typeof context === "string") { | ||
callback = resolveContext; | ||
resolveContext = request; | ||
request = path; | ||
path = context; | ||
context = nodeContext; | ||
} | ||
if(typeof callback !== "function") { | ||
callback = resolveContext; | ||
} | ||
asyncContextResolver.resolve(context, path, request, resolveContext, callback); | ||
}; | ||
const syncContextResolver = ResolverFactory.createResolver({ | ||
extensions: [".js", ".json", ".node"], | ||
resolveToContext: true, | ||
useSyncFileSystemCalls: true, | ||
fileSystem: nodeFileSystem | ||
}); | ||
module.exports.context.sync = function resolveContextSync(context, path, request) { | ||
if(typeof context === "string") { | ||
request = path; | ||
path = context; | ||
context = nodeContext; | ||
} | ||
return syncContextResolver.resolveSync(context, path, request); | ||
}; | ||
const asyncLoaderResolver = ResolverFactory.createResolver({ | ||
extensions: [".js", ".json", ".node"], | ||
moduleExtensions: ["-loader"], | ||
mainFields: ["loader", "main"], | ||
fileSystem: nodeFileSystem | ||
}); | ||
module.exports.loader = function resolveLoader(context, path, request, resolveContext, callback) { | ||
if(typeof context === "string") { | ||
callback = resolveContext; | ||
resolveContext = request; | ||
request = path; | ||
path = context; | ||
context = nodeContext; | ||
} | ||
if(typeof callback !== "function") { | ||
callback = resolveContext; | ||
} | ||
asyncLoaderResolver.resolve(context, path, request, resolveContext, callback); | ||
}; | ||
const syncLoaderResolver = ResolverFactory.createResolver({ | ||
extensions: [".js", ".json", ".node"], | ||
moduleExtensions: ["-loader"], | ||
mainFields: ["loader", "main"], | ||
useSyncFileSystemCalls: true, | ||
fileSystem: nodeFileSystem | ||
}); | ||
module.exports.loader.sync = function resolveLoaderSync(context, path, request) { | ||
if(typeof context === "string") { | ||
request = path; | ||
path = context; | ||
context = nodeContext; | ||
} | ||
return syncLoaderResolver.resolveSync(context, path, request); | ||
}; | ||
module.exports.create = function create(options) { | ||
options = Object.assign({ | ||
fileSystem: nodeFileSystem | ||
}, options); | ||
options = { | ||
fileSystem: nodeFileSystem, | ||
...options | ||
}; | ||
const resolver = ResolverFactory.createResolver(options); | ||
return function(context, path, request, resolveContext, callback) { | ||
if(typeof context === "string") { | ||
if (typeof context === "string") { | ||
callback = resolveContext; | ||
@@ -140,3 +74,3 @@ resolveContext = request; | ||
} | ||
if(typeof callback !== "function") { | ||
if (typeof callback !== "function") { | ||
callback = resolveContext; | ||
@@ -149,9 +83,10 @@ } | ||
module.exports.create.sync = function createSync(options) { | ||
options = Object.assign({ | ||
options = { | ||
useSyncFileSystemCalls: true, | ||
fileSystem: nodeFileSystem | ||
}, options); | ||
fileSystem: nodeFileSystem, | ||
...options | ||
}; | ||
const resolver = ResolverFactory.createResolver(options); | ||
return function(context, path, request) { | ||
if(typeof context === "string") { | ||
if (typeof context === "string") { | ||
request = path; | ||
@@ -168,3 +103,2 @@ path = context; | ||
module.exports.NodeJsInputFileSystem = NodeJsInputFileSystem; | ||
module.exports.CachedInputFileSystem = CachedInputFileSystem; |
@@ -15,17 +15,18 @@ /* | ||
const target = resolver.ensureHook(this.target); | ||
resolver.getHook(this.source).tapAsync("ParsePlugin", (request, resolveContext, callback) => { | ||
const parsed = resolver.parse(request.request); | ||
const obj = Object.assign({}, request, parsed); | ||
if(request.query && !parsed.query) { | ||
obj.query = request.query; | ||
} | ||
if(parsed && resolveContext.log) { | ||
if(parsed.module) | ||
resolveContext.log("Parsed request is a module"); | ||
if(parsed.directory) | ||
resolveContext.log("Parsed request is a directory"); | ||
} | ||
resolver.doResolve(target, obj, null, resolveContext, callback); | ||
}); | ||
resolver | ||
.getHook(this.source) | ||
.tapAsync("ParsePlugin", (request, resolveContext, callback) => { | ||
const parsed = resolver.parse(request.request); | ||
const obj = { ...request, ...parsed }; | ||
if (request.query && !parsed.query) { | ||
obj.query = request.query; | ||
} | ||
if (parsed && resolveContext.log) { | ||
if (parsed.module) resolveContext.log("Parsed request is a module"); | ||
if (parsed.directory) | ||
resolveContext.log("Parsed request is a directory"); | ||
} | ||
resolver.doResolve(target, obj, null, resolveContext, callback); | ||
}); | ||
} | ||
}; |
@@ -7,17 +7,11 @@ /* | ||
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 { AsyncSeriesBailHook, AsyncSeriesHook, SyncHook } = require("tapable"); | ||
const createInnerContext = require("./createInnerContext"); | ||
const { | ||
normalize, | ||
cachedJoin: join, | ||
getType, | ||
PathType | ||
} = require("./pathUtils"); | ||
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) { | ||
@@ -32,17 +26,4 @@ hook.name = name; | ||
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 { | ||
class Resolver { | ||
constructor(fileSystem) { | ||
super(); | ||
this.fileSystem = fileSystem; | ||
@@ -52,46 +33,26 @@ this.hooks = { | ||
noResolve: withName("noResolve", new SyncHook(["request", "error"])), | ||
resolve: withName("resolve", new AsyncSeriesBailHook(["request", "resolveContext"])), | ||
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; | ||
if (typeof name !== "string") { | ||
return name; | ||
} | ||
name = toCamelCase(name); | ||
if(/^before/.test(name)) { | ||
return this.ensureHook(name[6].toLowerCase() + name.substr(7)).withOptions({ | ||
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({ | ||
if (/^after/.test(name)) { | ||
return this.ensureHook( | ||
name[5].toLowerCase() + name.substr(6) | ||
).withOptions({ | ||
stage: 10 | ||
@@ -101,4 +62,7 @@ }); | ||
const hook = this.hooks[name]; | ||
if(!hook) { | ||
return this.hooks[name] = withName(name, new AsyncSeriesBailHook(["request", "resolveContext"])); | ||
if (!hook) { | ||
return (this.hooks[name] = withName( | ||
name, | ||
new AsyncSeriesBailHook(["request", "resolveContext"]) | ||
)); | ||
} | ||
@@ -109,5 +73,7 @@ return hook; | ||
getHook(name) { | ||
if(typeof name !== "string") return name; | ||
if (typeof name !== "string") { | ||
return name; | ||
} | ||
name = toCamelCase(name); | ||
if(/^before/.test(name)) { | ||
if (/^before/.test(name)) { | ||
return this.getHook(name[6].toLowerCase() + name.substr(7)).withOptions({ | ||
@@ -117,3 +83,3 @@ stage: -10 | ||
} | ||
if(/^after/.test(name)) { | ||
if (/^after/.test(name)) { | ||
return this.getHook(name[5].toLowerCase() + name.substr(6)).withOptions({ | ||
@@ -124,3 +90,3 @@ stage: 10 | ||
const hook = this.hooks[name]; | ||
if(!hook) { | ||
if (!hook) { | ||
throw new Error(`Hook ${name} doesn't exist`); | ||
@@ -132,3 +98,5 @@ } | ||
resolveSync(context, path, request) { | ||
let err, result, sync = false; | ||
let err, | ||
result, | ||
sync = false; | ||
this.resolve(context, path, request, {}, (e, r) => { | ||
@@ -139,4 +107,8 @@ err = e; | ||
}); | ||
if(!sync) throw new Error("Cannot 'resolveSync' because the fileSystem is not sync. Use 'resolve'!"); | ||
if(err) throw err; | ||
if (!sync) { | ||
throw new Error( | ||
"Cannot 'resolveSync' because the fileSystem is not sync. Use 'resolve'!" | ||
); | ||
} | ||
if (err) throw err; | ||
return result; | ||
@@ -146,10 +118,2 @@ } | ||
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 = { | ||
@@ -161,61 +125,97 @@ context: context, | ||
const message = "resolve '" + request + "' in '" + path + "'"; | ||
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 finishResolved = 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 finishWithoutResolve = log => { | ||
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 log = []; | ||
return this.doResolve(this.hooks.resolve, obj, message, { | ||
log: msg => { | ||
if(resolveContext.log) { | ||
return this.doResolve( | ||
this.hooks.resolve, | ||
obj, | ||
message, | ||
{ | ||
log: msg => { | ||
resolveContext.log(msg); | ||
} | ||
log.push(msg); | ||
log.push(msg); | ||
}, | ||
fileDependencies: resolveContext.fileDependencies, | ||
contextDependencies: resolveContext.contextDependencies, | ||
missingDependencies: resolveContext.missingDependencies, | ||
stack: resolveContext.stack | ||
}, | ||
missing: localMissing, | ||
stack: resolveContext.stack | ||
}, (err, result) => { | ||
if(err) return callback(err); | ||
(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); | ||
}); | ||
}); | ||
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, | ||
fileDependencies: resolveContext.fileDependencies, | ||
contextDependencies: resolveContext.contextDependencies, | ||
missingDependencies: resolveContext.missingDependencies, | ||
stack: resolveContext.stack | ||
}, | ||
(err, result) => { | ||
if (err) return callback(err); | ||
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), | ||
stack: resolveContext.stack | ||
}, | ||
(err, result) => { | ||
if (err) return callback(err); | ||
return finishWithoutResolve(log); | ||
} | ||
); | ||
} | ||
); | ||
} | ||
} | ||
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 || "") + | ||
const stackLine = | ||
hook.name + | ||
": (" + | ||
request.path + | ||
") " + | ||
(request.request || "") + | ||
(request.query || "") + | ||
(request.directory ? " directory" : "") + | ||
@@ -225,9 +225,13 @@ (request.module ? " module" : ""); | ||
let newStack; | ||
if(resolveContext.stack) { | ||
if (resolveContext.stack) { | ||
newStack = new Set(resolveContext.stack); | ||
if(resolveContext.stack.has(stackLine)) { | ||
if (resolveContext.stack.has(stackLine)) { | ||
// Prevent recursion | ||
const recursionError = new Error("Recursion in resolving\nStack:\n " + Array.from(newStack).join("\n ")); | ||
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"); | ||
if (resolveContext.log) | ||
resolveContext.log("abort resolving because of recursion"); | ||
return callback(recursionError); | ||
@@ -241,11 +245,16 @@ } | ||
if(hook.isUsed()) { | ||
const innerContext = createInnerContext({ | ||
log: resolveContext.log, | ||
missing: resolveContext.missing, | ||
stack: newStack | ||
}, message); | ||
if (hook.isUsed()) { | ||
const innerContext = createInnerContext( | ||
{ | ||
log: resolveContext.log, | ||
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); | ||
if (err) return callback(err); | ||
if (result) return callback(null, result); | ||
callback(); | ||
@@ -259,3 +268,3 @@ }); | ||
parse(identifier) { | ||
if(identifier === "") return null; | ||
if (identifier === "") return null; | ||
const part = { | ||
@@ -269,5 +278,5 @@ request: "", | ||
const idxQuery = identifier.indexOf("?"); | ||
if(idxQuery === 0) { | ||
if (idxQuery === 0) { | ||
part.query = identifier; | ||
} else if(idxQuery > 0) { | ||
} else if (idxQuery > 0) { | ||
part.request = identifier.slice(0, idxQuery); | ||
@@ -278,6 +287,6 @@ part.query = identifier.slice(idxQuery); | ||
} | ||
if(part.request) { | ||
if (part.request) { | ||
part.module = this.isModule(part.request); | ||
part.directory = this.isDirectory(part.request); | ||
if(part.directory) { | ||
if (part.directory) { | ||
part.request = part.request.substr(0, part.request.length - 1); | ||
@@ -290,26 +299,19 @@ } | ||
isModule(path) { | ||
return !REGEXP_NOT_MODULE.test(path); | ||
return getType(path) === PathType.Normal; | ||
} | ||
/** | ||
* @param {string} path a path | ||
* @returns {boolean} true, if the path is a directory path | ||
*/ | ||
isDirectory(path) { | ||
return REGEXP_DIRECTORY.test(path); | ||
return path.endsWith("/"); | ||
} | ||
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; | ||
return join(path, request); | ||
} | ||
normalize(path) { | ||
return memoryFsNormalize(path); | ||
return normalize(path); | ||
} | ||
@@ -316,0 +318,0 @@ } |
@@ -8,2 +8,3 @@ /* | ||
const Resolver = require("./Resolver"); | ||
const { getType, PathType } = require("./pathUtils"); | ||
@@ -19,2 +20,3 @@ const SyncAsyncFileSystemDecorator = require("./SyncAsyncFileSystemDecorator"); | ||
const JoinRequestPlugin = require("./JoinRequestPlugin"); | ||
const JoinRequestPartPlugin = require("./JoinRequestPartPlugin"); | ||
const ModulesInHierachicDirectoriesPlugin = require("./ModulesInHierachicDirectoriesPlugin"); | ||
@@ -24,5 +26,2 @@ const ModulesInRootPlugin = require("./ModulesInRootPlugin"); | ||
const AliasFieldPlugin = require("./AliasFieldPlugin"); | ||
const ConcordExtensionsPlugin = require("./ConcordExtensionsPlugin"); | ||
const ConcordMainPlugin = require("./ConcordMainPlugin"); | ||
const ConcordModulesPlugin = require("./ConcordModulesPlugin"); | ||
const DirectoryExistsPlugin = require("./DirectoryExistsPlugin"); | ||
@@ -35,7 +34,6 @@ const FileExistsPlugin = require("./FileExistsPlugin"); | ||
const ResultPlugin = require("./ResultPlugin"); | ||
const ModuleAppendPlugin = require("./ModuleAppendPlugin"); | ||
const UnsafeCachePlugin = require("./UnsafeCachePlugin"); | ||
const PnpPlugin = require("./PnpPlugin"); | ||
exports.createResolver = function(options) { | ||
//// OPTIONS //// | ||
@@ -69,13 +67,17 @@ | ||
// 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 || []; | ||
// A PnP API that should be used - null is "never", undefined is "auto" | ||
const pnpApi = | ||
options.pnpApi === undefined | ||
? process.versions.pnp | ||
? // eslint-disable-next-line node/no-missing-require | ||
require("pnpapi") | ||
: null | ||
: options.pnpApi; | ||
// Resolve symlinks to their symlinked location | ||
const symlinks = typeof options.symlinks !== "undefined" ? options.symlinks : true; | ||
const symlinks = | ||
typeof options.symlinks !== "undefined" ? options.symlinks : true; | ||
@@ -89,12 +91,14 @@ // Resolve to a context instead of a file | ||
// Whether or not the unsafeCache should include request context as part of the cache key. | ||
const cacheWithContext = typeof options.cacheWithContext !== "undefined" ? options.cacheWithContext : true; | ||
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; | ||
}; | ||
const cachePredicate = | ||
options.cachePredicate || | ||
function() { | ||
return true; | ||
}; | ||
@@ -112,15 +116,19 @@ // The file system which should be used | ||
if(!resolver) { | ||
resolver = new Resolver(useSyncFileSystemCalls ? new SyncAsyncFileSystemDecorator(fileSystem) : fileSystem); | ||
if (!resolver) { | ||
resolver = new Resolver( | ||
useSyncFileSystemCalls | ||
? new SyncAsyncFileSystemDecorator(fileSystem) | ||
: fileSystem | ||
); | ||
} | ||
extensions = [].concat(extensions); | ||
moduleExtensions = [].concat(moduleExtensions); | ||
modules = mergeFilteredToArray([].concat(modules), item => { | ||
return !isAbsolutePath(item); | ||
const type = getType(item); | ||
return type === PathType.Normal || type === PathType.Relative; | ||
}); | ||
mainFields = mainFields.map(item => { | ||
if(typeof item === "string" || Array.isArray(item)) { | ||
if (typeof item === "string" || Array.isArray(item)) { | ||
item = { | ||
@@ -134,11 +142,11 @@ name: item, | ||
if(typeof alias === "object" && !Array.isArray(alias)) { | ||
if (typeof alias === "object" && !Array.isArray(alias)) { | ||
alias = Object.keys(alias).map(key => { | ||
let onlyModule = false; | ||
let obj = alias[key]; | ||
if(/\$$/.test(key)) { | ||
if (/\$$/.test(key)) { | ||
onlyModule = true; | ||
key = key.substr(0, key.length - 1); | ||
} | ||
if(typeof obj === "string") { | ||
if (typeof obj === "string" || Array.isArray(obj)) { | ||
obj = { | ||
@@ -148,6 +156,7 @@ alias: obj | ||
} | ||
obj = Object.assign({ | ||
obj = { | ||
name: key, | ||
onlyModule: onlyModule | ||
}, obj); | ||
onlyModule: onlyModule, | ||
...obj | ||
}; | ||
return obj; | ||
@@ -157,3 +166,3 @@ }); | ||
if(unsafeCache && typeof unsafeCache !== "object") { | ||
if (unsafeCache && typeof unsafeCache !== "object") { | ||
unsafeCache = {}; | ||
@@ -169,5 +178,8 @@ } | ||
resolver.ensureHook("module"); | ||
resolver.ensureHook("resolveInDirectory"); | ||
resolver.ensureHook("resolveInExistingDirectory"); | ||
resolver.ensureHook("relative"); | ||
resolver.ensureHook("describedRelative"); | ||
resolver.ensureHook("directory"); | ||
resolver.ensureHook("undescribedExistingDirectory"); | ||
resolver.ensureHook("existingDirectory"); | ||
@@ -181,4 +193,12 @@ resolver.ensureHook("undescribedRawFile"); | ||
// resolve | ||
if(unsafeCache) { | ||
plugins.push(new UnsafeCachePlugin("resolve", cachePredicate, unsafeCache, cacheWithContext, "new-resolve")); | ||
if (unsafeCache) { | ||
plugins.push( | ||
new UnsafeCachePlugin( | ||
"resolve", | ||
cachePredicate, | ||
unsafeCache, | ||
cacheWithContext, | ||
"new-resolve" | ||
) | ||
); | ||
plugins.push(new ParsePlugin("new-resolve", "parsed-resolve")); | ||
@@ -190,11 +210,15 @@ } else { | ||
// parsed-resolve | ||
plugins.push(new DescriptionFilePlugin("parsed-resolve", descriptionFiles, "described-resolve")); | ||
plugins.push( | ||
new DescriptionFilePlugin( | ||
"parsed-resolve", | ||
descriptionFiles, | ||
false, | ||
"described-resolve" | ||
) | ||
); | ||
plugins.push(new NextPlugin("after-parsed-resolve", "described-resolve")); | ||
// described-resolve | ||
if(alias.length > 0) | ||
if (alias.length > 0) | ||
plugins.push(new AliasPlugin("described-resolve", alias, "resolve")); | ||
if(enableConcord) { | ||
plugins.push(new ConcordModulesPlugin("described-resolve", {}, "resolve")); | ||
} | ||
aliasFields.forEach(item => { | ||
@@ -206,57 +230,117 @@ plugins.push(new AliasFieldPlugin("described-resolve", item, "resolve")); | ||
// raw-module | ||
moduleExtensions.forEach(item => { | ||
plugins.push(new ModuleAppendPlugin("raw-module", item, "module")); | ||
}); | ||
if(!enforceModuleExtension) | ||
plugins.push(new TryNextPlugin("raw-module", null, "module")); | ||
// module | ||
if (pnpApi) { | ||
plugins.push(new PnpPlugin("raw-module", pnpApi, "relative")); | ||
} | ||
modules.forEach(item => { | ||
if(Array.isArray(item)) | ||
plugins.push(new ModulesInHierachicDirectoriesPlugin("module", item, "resolve")); | ||
else | ||
plugins.push(new ModulesInRootPlugin("module", item, "resolve")); | ||
if (Array.isArray(item)) | ||
plugins.push( | ||
new ModulesInHierachicDirectoriesPlugin("raw-module", item, "module") | ||
); | ||
else plugins.push(new ModulesInRootPlugin("raw-module", item, "module")); | ||
}); | ||
// module | ||
plugins.push(new JoinRequestPartPlugin("module", "resolve-in-directory")); | ||
// resolve-in-directory | ||
if (!resolveToContext) { | ||
plugins.push( | ||
new TryNextPlugin( | ||
"resolve-in-directory", | ||
"single file module", | ||
"undescribed-raw-file" | ||
) | ||
); | ||
} | ||
plugins.push( | ||
new DirectoryExistsPlugin( | ||
"resolve-in-directory", | ||
"resolve-in-existing-directory" | ||
) | ||
); | ||
// resolve-in-existing-directory | ||
plugins.push( | ||
new JoinRequestPlugin("resolve-in-existing-directory", "relative") | ||
); | ||
// relative | ||
plugins.push(new DescriptionFilePlugin("relative", descriptionFiles, "described-relative")); | ||
plugins.push( | ||
new DescriptionFilePlugin( | ||
"relative", | ||
descriptionFiles, | ||
true, | ||
"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")); | ||
if (!resolveToContext) { | ||
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")); | ||
plugins.push( | ||
new DirectoryExistsPlugin("directory", "undescribed-existing-directory") | ||
); | ||
if(resolveToContext) { | ||
// existing-directory | ||
plugins.push(new NextPlugin("existing-directory", "resolved")); | ||
if (resolveToContext) { | ||
// undescribed-existing-directory | ||
plugins.push(new NextPlugin("undescribed-existing-directory", "resolved")); | ||
} else { | ||
// undescribed-existing-directory | ||
plugins.push( | ||
new DescriptionFilePlugin( | ||
"undescribed-existing-directory", | ||
descriptionFiles, | ||
false, | ||
"existing-directory" | ||
) | ||
); | ||
mainFiles.forEach(item => { | ||
plugins.push( | ||
new UseFilePlugin( | ||
"undescribed-existing-directory", | ||
item, | ||
"undescribed-raw-file" | ||
) | ||
); | ||
}); | ||
// existing-directory | ||
if(enableConcord) { | ||
plugins.push(new ConcordMainPlugin("existing-directory", {}, "resolve")); | ||
} | ||
// described-existing-directory | ||
mainFields.forEach(item => { | ||
plugins.push(new MainFieldPlugin("existing-directory", item, "resolve")); | ||
plugins.push( | ||
new MainFieldPlugin( | ||
"existing-directory", | ||
item, | ||
"resolve-in-existing-directory" | ||
) | ||
); | ||
}); | ||
mainFiles.forEach(item => { | ||
plugins.push(new UseFilePlugin("existing-directory", item, "undescribed-raw-file")); | ||
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 DescriptionFilePlugin( | ||
"undescribed-raw-file", | ||
descriptionFiles, | ||
true, | ||
"raw-file" | ||
) | ||
); | ||
plugins.push(new NextPlugin("after-undescribed-raw-file", "raw-file")); | ||
// raw-file | ||
if(!enforceExtension) { | ||
if (!enforceExtension) { | ||
plugins.push(new TryNextPlugin("raw-file", "no extension", "file")); | ||
} | ||
if(enableConcord) { | ||
plugins.push(new ConcordExtensionsPlugin("raw-file", {}, "file")); | ||
} | ||
extensions.forEach(item => { | ||
@@ -267,17 +351,13 @@ plugins.push(new AppendPlugin("raw-file", item, "file")); | ||
// file | ||
if(alias.length > 0) | ||
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 | ||
if (symlinks) | ||
plugins.push(new SymlinkPlugin("existing-file", "existing-file")); | ||
plugins.push(new NextPlugin("existing-file", "resolved")); | ||
} | ||
@@ -299,5 +379,5 @@ | ||
return array.reduce((array, item) => { | ||
if(filter(item)) { | ||
if (filter(item)) { | ||
const lastElement = array[array.length - 1]; | ||
if(Array.isArray(lastElement)) { | ||
if (Array.isArray(lastElement)) { | ||
lastElement.push(item); | ||
@@ -314,5 +394,1 @@ } else { | ||
} | ||
function isAbsolutePath(path) { | ||
return /^[A-Z]:|^\//.test(path); | ||
} |
@@ -13,11 +13,15 @@ /* | ||
apply(resolver) { | ||
this.source.tapAsync("ResultPlugin", (request, resolverContext, callback) => { | ||
const obj = Object.assign({}, request); | ||
if(resolverContext.log) resolverContext.log("reporting result " + obj.path); | ||
resolver.hooks.result.callAsync(obj, resolverContext, err => { | ||
if(err) return callback(err); | ||
callback(null, obj); | ||
}); | ||
}); | ||
this.source.tapAsync( | ||
"ResultPlugin", | ||
(request, resolverContext, callback) => { | ||
const obj = { ...request }; | ||
if (resolverContext.log) | ||
resolverContext.log("reporting result " + obj.path); | ||
resolver.hooks.result.callAsync(obj, resolverContext, err => { | ||
if (err) return callback(err); | ||
callback(null, obj); | ||
}); | ||
} | ||
); | ||
} | ||
}; |
@@ -9,2 +9,3 @@ /* | ||
const forEachBail = require("./forEachBail"); | ||
const { getType, PathType } = require("./pathUtils"); | ||
@@ -20,32 +21,58 @@ module.exports = class SymlinkPlugin { | ||
const fs = resolver.fileSystem; | ||
resolver.getHook(this.source).tapAsync("SymlinkPlugin", (request, resolveContext, callback) => { | ||
const pathsResult = getPaths(request.path); | ||
const pathSeqments = pathsResult.seqments; | ||
const paths = pathsResult.paths; | ||
resolver | ||
.getHook(this.source) | ||
.tapAsync("SymlinkPlugin", (request, resolveContext, callback) => { | ||
if (request.ignoreSymlinks) return callback(); | ||
const pathsResult = getPaths(request.path); | ||
const pathSeqments = pathsResult.seqments; | ||
const paths = pathsResult.paths; | ||
let containsSymlink = false; | ||
forEachBail.withIndex(paths, (path, idx, callback) => { | ||
fs.readlink(path, (err, result) => { | ||
if(!err && result) { | ||
pathSeqments[idx] = result; | ||
containsSymlink = true; | ||
// Shortcut when absolute symlink found | ||
if(/^(\/|[a-zA-Z]:($|\\))/.test(result)) | ||
return callback(null, idx); | ||
let containsSymlink = false; | ||
let idx = -1; | ||
forEachBail( | ||
paths, | ||
(path, callback) => { | ||
idx++; | ||
if (resolveContext.fileDependencies) | ||
resolveContext.fileDependencies.add(path); | ||
fs.readlink(path, (err, result) => { | ||
if (!err && result) { | ||
pathSeqments[idx] = result; | ||
containsSymlink = true; | ||
// Shortcut when absolute symlink found | ||
const resultType = getType(result); | ||
if ( | ||
resultType === PathType.AbsoluteWin || | ||
resultType === PathType.AbsolutePosix | ||
) { | ||
return callback(null, idx); | ||
} | ||
} | ||
callback(); | ||
}); | ||
}, | ||
(err, idx) => { | ||
if (!containsSymlink) return callback(); | ||
const resultSeqments = | ||
typeof idx === "number" | ||
? pathSeqments.slice(0, idx + 1) | ||
: pathSeqments.slice(); | ||
const result = resultSeqments.reverse().reduce((a, b) => { | ||
return resolver.join(a, b); | ||
}); | ||
const obj = { | ||
...request, | ||
path: result | ||
}; | ||
resolver.doResolve( | ||
target, | ||
obj, | ||
"resolved symlink to " + result, | ||
resolveContext, | ||
callback | ||
); | ||
} | ||
callback(); | ||
}); | ||
}, (err, idx) => { | ||
if(!containsSymlink) return callback(); | ||
const resultSeqments = typeof idx === "number" ? pathSeqments.slice(0, idx + 1) : pathSeqments.slice(); | ||
const result = resultSeqments.reverse().reduce((a, b) => { | ||
return resolver.join(a, b); | ||
}); | ||
const obj = Object.assign({}, request, { | ||
path: result | ||
}); | ||
resolver.doResolve(target, obj, "resolved symlink to " + result, resolveContext, callback); | ||
); | ||
}); | ||
}); | ||
} | ||
}; |
@@ -9,8 +9,8 @@ /* | ||
this.fs = fs; | ||
if(fs.statSync) { | ||
this.stat = function(arg, callback) { | ||
if (fs.statSync) { | ||
this.stat = (arg, callback) => { | ||
let result; | ||
try { | ||
result = fs.statSync(arg); | ||
} catch(e) { | ||
} catch (e) { | ||
return callback(e); | ||
@@ -20,9 +20,11 @@ } | ||
}; | ||
this.statSync = arg => fs.statSync(arg); | ||
} | ||
if(fs.readdirSync) { | ||
this.readdir = function(arg, callback) { | ||
if (fs.readdirSync) { | ||
this.readdir = (arg, callback) => { | ||
let result; | ||
try { | ||
result = fs.readdirSync(arg); | ||
} catch(e) { | ||
} catch (e) { | ||
return callback(e); | ||
@@ -32,9 +34,11 @@ } | ||
}; | ||
this.readdirSync = arg => fs.readdirSync(arg); | ||
} | ||
if(fs.readFileSync) { | ||
this.readFile = function(arg, callback) { | ||
if (fs.readFileSync) { | ||
this.readFile = (arg, callback) => { | ||
let result; | ||
try { | ||
result = fs.readFileSync(arg); | ||
} catch(e) { | ||
} catch (e) { | ||
return callback(e); | ||
@@ -44,9 +48,11 @@ } | ||
}; | ||
this.readFileSync = arg => fs.readFileSync(arg); | ||
} | ||
if(fs.readlinkSync) { | ||
this.readlink = function(arg, callback) { | ||
if (fs.readlinkSync) { | ||
this.readlink = (arg, callback) => { | ||
let result; | ||
try { | ||
result = fs.readlinkSync(arg); | ||
} catch(e) { | ||
} catch (e) { | ||
return callback(e); | ||
@@ -56,9 +62,11 @@ } | ||
}; | ||
this.readlinkSync = arg => fs.readlinkSync(arg); | ||
} | ||
if(fs.readJsonSync) { | ||
this.readJson = function(arg, callback) { | ||
if (fs.readJsonSync) { | ||
this.readJson = (arg, callback) => { | ||
let result; | ||
try { | ||
result = fs.readJsonSync(arg); | ||
} catch(e) { | ||
} catch (e) { | ||
return callback(e); | ||
@@ -68,4 +76,6 @@ } | ||
}; | ||
this.readJsonSync = arg => fs.readJsonSync(arg); | ||
} | ||
} | ||
module.exports = SyncAsyncFileSystemDecorator; |
@@ -16,6 +16,14 @@ /* | ||
const target = resolver.ensureHook(this.target); | ||
resolver.getHook(this.source).tapAsync("TryNextPlugin", (request, resolveContext, callback) => { | ||
resolver.doResolve(target, request, this.message, resolveContext, callback); | ||
}); | ||
resolver | ||
.getHook(this.source) | ||
.tapAsync("TryNextPlugin", (request, resolveContext, callback) => { | ||
resolver.doResolve( | ||
target, | ||
request, | ||
this.message, | ||
resolveContext, | ||
callback | ||
); | ||
}); | ||
} | ||
}; |
@@ -27,16 +27,24 @@ /* | ||
const target = resolver.ensureHook(this.target); | ||
resolver.getHook(this.source).tapAsync("UnsafeCachePlugin", (request, resolveContext, callback) => { | ||
if(!this.filterPredicate(request)) return callback(); | ||
const cacheId = getCacheId(request, this.withContext); | ||
const cacheEntry = this.cache[cacheId]; | ||
if(cacheEntry) { | ||
return callback(null, cacheEntry); | ||
} | ||
resolver.doResolve(target, request, null, resolveContext, (err, result) => { | ||
if(err) return callback(err); | ||
if(result) return callback(null, this.cache[cacheId] = result); | ||
callback(); | ||
resolver | ||
.getHook(this.source) | ||
.tapAsync("UnsafeCachePlugin", (request, resolveContext, callback) => { | ||
if (!this.filterPredicate(request)) return callback(); | ||
const cacheId = getCacheId(request, this.withContext); | ||
const cacheEntry = this.cache[cacheId]; | ||
if (cacheEntry) { | ||
return callback(null, cacheEntry); | ||
} | ||
resolver.doResolve( | ||
target, | ||
request, | ||
null, | ||
resolveContext, | ||
(err, result) => { | ||
if (err) return callback(err); | ||
if (result) return callback(null, (this.cache[cacheId] = result)); | ||
callback(); | ||
} | ||
); | ||
}); | ||
}); | ||
} | ||
}; |
@@ -16,11 +16,22 @@ /* | ||
const target = resolver.ensureHook(this.target); | ||
resolver.getHook(this.source).tapAsync("UseFilePlugin", (request, resolveContext, callback) => { | ||
const filePath = resolver.join(request.path, this.filename); | ||
const obj = Object.assign({}, request, { | ||
path: filePath, | ||
relativePath: request.relativePath && resolver.join(request.relativePath, this.filename) | ||
resolver | ||
.getHook(this.source) | ||
.tapAsync("UseFilePlugin", (request, resolveContext, callback) => { | ||
const filePath = resolver.join(request.path, this.filename); | ||
const obj = { | ||
...request, | ||
path: filePath, | ||
relativePath: | ||
request.relativePath && | ||
resolver.join(request.relativePath, this.filename) | ||
}; | ||
resolver.doResolve( | ||
target, | ||
obj, | ||
"using path: " + filePath, | ||
resolveContext, | ||
callback | ||
); | ||
}); | ||
resolver.doResolve(target, obj, "using path: " + filePath, resolveContext, callback); | ||
}); | ||
} | ||
}; |
{ | ||
"name": "enhanced-resolve", | ||
"version": "4.1.0", | ||
"version": "5.0.0-beta.0", | ||
"author": "Tobias Koppers @sokra", | ||
@@ -11,5 +11,4 @@ "description": "Offers a async require.resolve function. It's highly configurable.", | ||
"dependencies": { | ||
"graceful-fs": "^4.1.2", | ||
"memory-fs": "^0.4.0", | ||
"tapable": "^1.0.0" | ||
"graceful-fs": "^4.2.0", | ||
"tapable": "^2.0.0-beta" | ||
}, | ||
@@ -23,15 +22,16 @@ "licenses": [ | ||
"devDependencies": { | ||
"beautify-lint": "^1.0.3", | ||
"codecov.io": "^0.1.6", | ||
"coveralls": "^2.11.6", | ||
"eslint": "^3.14.1", | ||
"eslint-plugin-node": "^3.0.5", | ||
"eslint-plugin-nodeca": "^1.0.3", | ||
"istanbul": "^0.4.1", | ||
"js-beautify": "^1.5.10", | ||
"mocha": "^2.3.4", | ||
"eslint": "^5.9.0", | ||
"eslint-config-prettier": "^3.3.0", | ||
"eslint-plugin-node": "^8.0.0", | ||
"eslint-plugin-prettier": "^3.0.0", | ||
"husky": "^1.2.0", | ||
"lint-staged": "^8.1.0", | ||
"memfs": "^2.15.4", | ||
"mocha": "^6.1.4", | ||
"nyc": "^14.1.1", | ||
"prettier": "^1.15.2", | ||
"should": "^8.0.2" | ||
}, | ||
"engines": { | ||
"node": ">=6.9.0" | ||
"node": ">=8.9.0" | ||
}, | ||
@@ -41,11 +41,21 @@ "main": "lib/node.js", | ||
"scripts": { | ||
"beautify-lint": "beautify-lint lib/**.js test/*.js", | ||
"beautify": "beautify-rewrite lib/**.js test/*.js", | ||
"lint": "eslint lib test", | ||
"pretest": "npm run lint && npm run beautify-lint", | ||
"pretty": "prettier --loglevel warn --write \"{lib,test}/**/*.{js,json}\"", | ||
"pretest": "yarn lint", | ||
"test": "mocha --full-trace --check-leaks", | ||
"precover": "npm run lint && npm run beautify-lint", | ||
"cover": "istanbul cover node_modules/mocha/bin/_mocha", | ||
"travis": "npm run cover -- --report lcovonly" | ||
"precover": "yarn lint", | ||
"cover": "nyc --reporter=html node node_modules/mocha/bin/_mocha", | ||
"pretravis": "yarn lint", | ||
"travis": "nyc --reporter=lcovonly node node_modules/mocha/bin/_mocha" | ||
}, | ||
"husky": { | ||
"hooks": { | ||
"pre-commit": "lint-staged" | ||
} | ||
}, | ||
"lint-staged": { | ||
"*.js": [ | ||
"eslint --cache" | ||
] | ||
}, | ||
"repository": { | ||
@@ -52,0 +62,0 @@ "type": "git", |
142
README.md
@@ -7,9 +7,10 @@ # enhanced-resolve | ||
* plugin system | ||
* provide a custom filesystem | ||
* sync and async node.js filesystems included | ||
- plugin system | ||
- provide a custom filesystem | ||
- sync and async node.js filesystems included | ||
## Getting Started | ||
## Getting Started | ||
### Install | ||
```sh | ||
@@ -22,17 +23,42 @@ # npm | ||
### Resolve | ||
There is a Node.js API which allows to resolve requests according to the Node.js resolving rules. | ||
Sync and async APIs are offered. A `create` method allows to create a custom resolve function. | ||
```js | ||
const resolve = require("enhanced-resolve"); | ||
resolve("/some/path/to/folder", "module/dir", (err, result) => { | ||
result; // === "/some/path/node_modules/module/dir/index.js" | ||
}); | ||
resolve.sync("/some/path/to/folder", "../../dir"); | ||
// === "/some/path/dir/index.js" | ||
const myResolve = resolve.create({ | ||
// or resolve.create.sync | ||
extensions: [".ts", ".js"] | ||
// see more options below | ||
}); | ||
myResolve("/some/path/to/folder", "ts-module", (err, result) => { | ||
result; // === "/some/node_modules/ts-module/index.ts" | ||
}); | ||
``` | ||
### Creating a Resolver | ||
The easiest way to create a resolver is to use the `createResolver` function on `ResolveFactory`, along with one of the supplied File System implementations. | ||
```js | ||
const { | ||
NodeJsInputFileSystem, | ||
CachedInputFileSystem, | ||
ResolverFactory | ||
} = require('enhanced-resolve'); | ||
const fs = require("fs"); | ||
const { CachedInputFileSystem, ResolverFactory } = require("enhanced-resolve"); | ||
// create a resolver | ||
const myResolver = ResolverFactory.createResolver({ | ||
// Typical usage will consume the `NodeJsInputFileSystem` + `CachedInputFileSystem`, which wraps the Node.js `fs` wrapper to add resilience + caching. | ||
fileSystem: new CachedInputFileSystem(new NodeJsInputFileSystem(), 4000), | ||
extensions: ['.js', '.json'] | ||
/* any other resolver options here. Options/defaults can be seen below */ | ||
// Typical usage will consume the `fs` + `CachedInputFileSystem`, which wraps Node.js `fs` to add caching. | ||
fileSystem: new CachedInputFileSystem(fs, 4000), | ||
extensions: [".js", ".json"] | ||
/* any other resolver options here. Options/defaults can be seen below */ | ||
}); | ||
@@ -43,52 +69,58 @@ | ||
const resolveContext = {}; | ||
const lookupStartPath = '/Users/webpack/some/root/dir'; | ||
const request = './path/to-look-up.js'; | ||
myResolver.resolve({}, lookupStartPath, request, resolveContext, (err/*Error*/, filepath/*string*/) => { | ||
// Do something with the path | ||
const lookupStartPath = "/Users/webpack/some/root/dir"; | ||
const request = "./path/to-look-up.js"; | ||
myResolver.resolve({}, lookupStartPath, request, resolveContext, ( | ||
err /*Error*/, | ||
filepath /*string*/ | ||
) => { | ||
// Do something with the path | ||
}); | ||
``` | ||
For more examples creating different types resolvers (sync/async, context, etc) see `lib/node.js`. | ||
#### Resolver Options | ||
| Field | Default | Description | | ||
| ------------------------ | --------------------------- | ---------------------------------------------------------------------------------- | | ||
| alias | [] | A list of module alias configurations or an object which maps key to value | | ||
| aliasFields | [] | A list of alias fields in description files | | ||
| cacheWithContext | true | If unsafe cache is enabled, includes `request.context` in the cache key | | ||
| descriptionFiles | ["package.json"] | A list of description files to read from | | ||
| enforceExtension | false | Enforce that a extension from extensions must be used | | ||
| enforceModuleExtension | false | Enforce that a extension from moduleExtensions must be used | | ||
| extensions | [".js", ".json", ".node"] | A list of extensions which should be tried for files | | ||
| mainFields | ["main"] | A list of main fields in description files | | ||
| mainFiles | ["index"] | A list of main files in directories | | ||
| modules | ["node_modules"] | A list of directories to resolve modules from, can be absolute path or folder name | | ||
| unsafeCache | false | Use this cache object to unsafely cache the successful requests | | ||
| plugins | [] | A list of additional resolve plugins which should be applied | | ||
| symlinks | true | Whether to resolve symlinks to their symlinked location | | ||
| cachePredicate | function() { return true }; | A function which decides whether a request should be cached or not. An object is passed to the function with `path` and `request` properties. | | ||
| moduleExtensions | [] | A list of module extensions which should be tried for modules | | ||
| resolveToContext | false | Resolve to a context instead of a file | | ||
| fileSystem | | The file system which should be used | | ||
| resolver | undefined | A prepared Resolver to which the plugins are attached | | ||
| Field | Default | Description | | ||
| ---------------- | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| alias | [] | A list of module alias configurations or an object which maps key to value | | ||
| aliasFields | [] | A list of alias fields in description files | | ||
| cacheWithContext | true | If unsafe cache is enabled, includes `request.context` in the cache key | | ||
| 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 | | ||
| mainFields | ["main"] | A list of main fields in description files | | ||
| mainFiles | ["index"] | A list of main files in directories | | ||
| modules | ["node_modules"] | A list of directories to resolve modules from, can be absolute path or folder name | | ||
| unsafeCache | false | Use this cache object to unsafely cache the successful requests | | ||
| plugins | [] | A list of additional resolve plugins which should be applied | | ||
| symlinks | true | Whether to resolve symlinks to their symlinked location | | ||
| cachePredicate | function() { return true }; | A function which decides whether a request should be cached or not. An object is passed to the function with `path` and `request` properties. | | ||
| resolveToContext | false | Resolve to a context instead of a file | | ||
| fileSystem | | The file system which should be used | | ||
| resolver | undefined | A prepared Resolver to which the plugins are attached | | ||
## Plugins | ||
Similar to `webpack`, the core of `enhanced-resolve` functionality is implemented as individual plugins that are executed using [`Tapable`](https://github.com/webpack/tapable). These plugins can extend the functionality of the library, adding other ways for files/contexts to be resolved. | ||
Similar to `webpack`, the core of `enhanced-resolve` functionality is implemented as individual plugins that are executed using [`tapable`](https://github.com/webpack/tapable). | ||
These plugins can extend the functionality of the library, adding other ways for files/contexts to be resolved. | ||
A plugin should be a `class` (or its ES5 equivalent) with an `apply` method. The `apply` method will receive a `resolver` instance, that can be used to hook in to the event system. | ||
### Plugin Boilerplate | ||
```js | ||
class MyResolverPlugin { | ||
constructor(source, target) { | ||
this.source = source; | ||
this.target = target; | ||
} | ||
constructor(source, target) { | ||
this.source = source; | ||
this.target = target; | ||
} | ||
apply(resolver) { | ||
const target = resolver.ensureHook(this.target); | ||
resolver.getHook(this.source).tapAsync("MyResolverPlugin", (request, resolveContext, callback) => { | ||
// Any logic you need to create a new `request` can go here | ||
resolver.doResolve(target, request, null, resolveContext, callback); | ||
}); | ||
} | ||
apply(resolver) { | ||
const target = resolver.ensureHook(this.target); | ||
resolver | ||
.getHook(this.source) | ||
.tapAsync("MyResolverPlugin", (request, resolveContext, callback) => { | ||
// Any logic you need to create a new `request` can go here | ||
resolver.doResolve(target, request, null, resolveContext, callback); | ||
}); | ||
} | ||
} | ||
@@ -101,3 +133,3 @@ ``` | ||
``` javascript | ||
```javascript | ||
npm test | ||
@@ -108,4 +140,4 @@ ``` | ||
## Passing options from webpack | ||
## Passing options from webpack | ||
If you are using `webpack`, and you want to pass custom options to `enhanced-resolve`, the options are passed from the `resolve` key of your webpack configuration e.g.: | ||
@@ -115,4 +147,4 @@ | ||
resolve: { | ||
extensions: ['', '.js', '.jsx'], | ||
modules: ['src', 'node_modules'], | ||
extensions: ['.js', '.jsx'], | ||
modules: [path.resolve(__dirname, 'src'), 'node_modules'], | ||
plugins: [new DirectoryNamedWebpackPlugin()] | ||
@@ -125,4 +157,4 @@ ... | ||
Copyright (c) 2012-2016 Tobias Koppers | ||
Copyright (c) 2012-2019 JS Foundation and other contributors | ||
MIT (http://www.opensource.org/licenses/mit-license.php) |
Sorry, the diff of this file is not supported yet
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
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
2
2494
154
77468
11
37
1
1
1
+ Addedtapable@2.2.1(transitive)
- Removedmemory-fs@^0.4.0
- Removedcore-util-is@1.0.3(transitive)
- Removederrno@0.1.8(transitive)
- Removedinherits@2.0.4(transitive)
- Removedisarray@1.0.0(transitive)
- Removedmemory-fs@0.4.1(transitive)
- Removedprocess-nextick-args@2.0.1(transitive)
- Removedprr@1.0.1(transitive)
- Removedreadable-stream@2.3.8(transitive)
- Removedsafe-buffer@5.1.2(transitive)
- Removedstring_decoder@1.1.1(transitive)
- Removedtapable@1.1.3(transitive)
- Removedutil-deprecate@1.0.2(transitive)
Updatedgraceful-fs@^4.2.0
Updatedtapable@^2.0.0-beta