Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,12 @@
"zipp",
"zippi",
"zizizi",
"codecov"
"codecov",
"xiaoxiaojx",
"Natsu",
"tsconfigs",
"preact",
"compat"
],
"ignorePaths": ["package.json", "yarn.lock", "coverage", "*.log"]
}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ myResolver.resolve(
| restrictions | [] | A list of resolve restrictions |
| roots | [] | A list of root paths |
| symlinks | true | Whether to resolve symlinks to their symlinked location |
| tsconfig | true | Path to tsconfig.json for paths mapping. Default true loads tsconfig.json, or pass a string path. |
| unsafeCache | false | Use this cache object to unsafely cache the successful requests |

## Plugins
Expand Down
145 changes: 8 additions & 137 deletions lib/AliasPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,13 @@

"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 {string | Array<string> | false} Alias */
/** @typedef {{alias: Alias, name: string, onlyModule?: boolean}} AliasOption */

const { aliasResolveHandler } = require("./AliasUtils");

module.exports = class AliasPlugin {
/**
* @param {string | ResolveStepHook} source source
Expand All @@ -32,143 +30,16 @@ module.exports = class AliasPlugin {
*/
apply(resolver) {
const target = resolver.ensureHook(this.target);
/**
* @param {string} maybeAbsolutePath path
* @returns {null|string} absolute path with slash ending
*/
const getAbsolutePathWithSlashEnding = (maybeAbsolutePath) => {
const type = getType(maybeAbsolutePath);
if (type === PathType.AbsolutePosix || type === PathType.AbsoluteWin) {
return resolver.join(maybeAbsolutePath, "_").slice(0, -1);
}
return null;
};
/**
* @param {string} path path
* @param {string} maybeSubPath sub path
* @returns {boolean} true, if path is sub path
*/
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(
aliasResolveHandler(
resolver,
this.options,
(item, callback) => {
/** @type {boolean} */
let shouldStop = false;

const matchRequest =
innerRequest === item.name ||
(!item.onlyModule &&
(request.request
? innerRequest.startsWith(`${item.name}/`)
: isSubPath(innerRequest, item.name)));

const splitName = item.name.split("*");
const matchWildcard = !item.onlyModule && splitName.length === 2;

if (matchRequest || matchWildcard) {
/**
* @param {Alias} alias alias
* @param {(err?: null|Error, result?: null|ResolveRequest) => void} callback callback
* @returns {void}
*/
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);
}

let newRequestStr;

const [prefix, suffix] = splitName;
if (
matchWildcard &&
innerRequest.startsWith(prefix) &&
innerRequest.endsWith(suffix)
) {
const match = innerRequest.slice(
prefix.length,
innerRequest.length - suffix.length,
);
newRequestStr = alias.toString().replace("*", match);
}

if (
matchRequest &&
innerRequest !== alias &&
!innerRequest.startsWith(`${alias}/`)
) {
/** @type {string} */
const remainingRequest = innerRequest.slice(item.name.length);
newRequestStr = alias + remainingRequest;
}

if (newRequestStr !== undefined) {
shouldStop = true;
/** @type {ResolveRequest} */
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();
};

/**
* @param {(null | Error)=} err error
* @param {(null | ResolveRequest)=} result result
* @returns {void}
*/
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,
);
}
return resolveWithAlias(item.alias, stoppingCallback);
}

return callback();
},
target,
request,
resolveContext,
callback,
);
});
Expand Down
172 changes: 172 additions & 0 deletions lib/AliasUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
/*
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").ResolveContext} ResolveContext */
/** @typedef {import("./Resolver").ResolveStepHook} ResolveStepHook */
/** @typedef {import("./Resolver").ResolveCallback} ResolveCallback */
/** @typedef {string | Array<string> | false} Alias */
/** @typedef {{alias: Alias, name: string, onlyModule?: boolean}} AliasOption */

/** @typedef {(err?: null | Error, result?: null | ResolveRequest) => void} InnerCallback */
/**
* @param {Resolver} resolver resolver
* @param {Array<AliasOption>} options options
* @param {ResolveStepHook} target target
* @param {ResolveRequest} request request
* @param {ResolveContext} resolveContext resolve context
* @param {InnerCallback} callback callback
* @returns {void}
*/
function aliasResolveHandler(
resolver,
options,
target,
request,
resolveContext,
callback,
) {
const innerRequest = request.request || request.path;
if (!innerRequest) return callback();

/**
* @param {string} maybeAbsolutePath path
* @returns {null|string} absolute path with slash ending
*/
const getAbsolutePathWithSlashEnding = (maybeAbsolutePath) => {
const type = getType(maybeAbsolutePath);
if (type === PathType.AbsolutePosix || type === PathType.AbsoluteWin) {
return resolver.join(maybeAbsolutePath, "_").slice(0, -1);
}
return null;
};
/**
* @param {string} path path
* @param {string} maybeSubPath sub path
* @returns {boolean} true, if path is sub path
*/
const isSubPath = (path, maybeSubPath) => {
const absolutePath = getAbsolutePathWithSlashEnding(maybeSubPath);
if (!absolutePath) return false;
return path.startsWith(absolutePath);
};

forEachBail(
options,
(item, callback) => {
/** @type {boolean} */
let shouldStop = false;

const matchRequest =
innerRequest === item.name ||
(!item.onlyModule &&
(request.request
? innerRequest.startsWith(`${item.name}/`)
: isSubPath(innerRequest, item.name)));

const splitName = item.name.split("*");
const matchWildcard = !item.onlyModule && splitName.length === 2;

if (matchRequest || matchWildcard) {
/**
* @param {Alias} alias alias
* @param {(err?: null|Error, result?: null|ResolveRequest) => void} callback callback
* @returns {void}
*/
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);
}

let newRequestStr;

const [prefix, suffix] = splitName;
if (
matchWildcard &&
innerRequest.startsWith(prefix) &&
innerRequest.endsWith(suffix)
) {
const match = innerRequest.slice(
prefix.length,
innerRequest.length - suffix.length,
);
newRequestStr = alias.toString().replace("*", match);
}

if (
matchRequest &&
innerRequest !== alias &&
!innerRequest.startsWith(`${alias}/`)
) {
/** @type {string} */
const remainingRequest = innerRequest.slice(item.name.length);
newRequestStr = alias + remainingRequest;
}

if (newRequestStr !== undefined) {
shouldStop = true;
/** @type {ResolveRequest} */
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();
};

/**
* @param {(null | Error)=} err error
* @param {(null | ResolveRequest)=} result result
* @returns {void}
*/
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);
}
return resolveWithAlias(item.alias, stoppingCallback);
}

return callback();
},
callback,
);
}

module.exports.aliasResolveHandler = aliasResolveHandler;
Loading