You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
131 lines
3.8 KiB
131 lines
3.8 KiB
/* |
|
MIT License http://www.opensource.org/licenses/mit-license.php |
|
Author Tobias Koppers @sokra |
|
*/ |
|
|
|
"use strict"; |
|
|
|
const forEachBail = require("./forEachBail"); |
|
const { PathType, getType } = require("./util/path"); |
|
|
|
/** @typedef {import("./Resolver")} Resolver */ |
|
/** @typedef {import("./Resolver").ResolveRequest} ResolveRequest */ |
|
/** @typedef {import("./Resolver").ResolveStepHook} ResolveStepHook */ |
|
/** @typedef {{alias: string|Array<string>|false, name: string, onlyModule?: boolean}} AliasOption */ |
|
|
|
module.exports = class AliasPlugin { |
|
/** |
|
* @param {string | ResolveStepHook} source source |
|
* @param {AliasOption | Array<AliasOption>} options options |
|
* @param {string | ResolveStepHook} target target |
|
*/ |
|
constructor(source, options, target) { |
|
this.source = source; |
|
this.options = Array.isArray(options) ? options : [options]; |
|
this.target = target; |
|
} |
|
|
|
/** |
|
* @param {Resolver} resolver the resolver |
|
* @returns {void} |
|
*/ |
|
apply(resolver) { |
|
const target = resolver.ensureHook(this.target); |
|
const getAbsolutePathWithSlashEnding = maybeAbsolutePath => { |
|
const type = getType(maybeAbsolutePath); |
|
if (type === PathType.AbsolutePosix || type === PathType.AbsoluteWin) { |
|
return resolver.join(maybeAbsolutePath, "_").slice(0, -1); |
|
} |
|
return null; |
|
}; |
|
const isSubPath = (path, maybeSubPath) => { |
|
const absolutePath = getAbsolutePathWithSlashEnding(maybeSubPath); |
|
if (!absolutePath) return false; |
|
return path.startsWith(absolutePath); |
|
}; |
|
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 && |
|
(request.request |
|
? innerRequest.startsWith(`${item.name}/`) |
|
: isSubPath(innerRequest, item.name))) |
|
) { |
|
const remainingRequest = innerRequest.substr(item.name.length); |
|
const resolveWithAlias = (alias, callback) => { |
|
if (alias === false) { |
|
/** @type {ResolveRequest} */ |
|
const ignoreObj = { |
|
...request, |
|
path: false |
|
}; |
|
if (typeof resolveContext.yield === "function") { |
|
resolveContext.yield(ignoreObj); |
|
return callback(null, null); |
|
} |
|
return callback(null, ignoreObj); |
|
} |
|
if ( |
|
innerRequest !== alias && |
|
!innerRequest.startsWith(alias + "/") |
|
) { |
|
shouldStop = true; |
|
const newRequestStr = alias + remainingRequest; |
|
const obj = { |
|
...request, |
|
request: newRequestStr, |
|
fullySpecified: false |
|
}; |
|
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); |
|
|
|
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 |
|
); |
|
}); |
|
} |
|
};
|
|
|