120 lines
4.0 KiB
JavaScript
120 lines
4.0 KiB
JavaScript
|
// Info: this file has been generated by Yarn with the approval of the
|
||
|
// `resolve` maintainers. Bugs caused by a code located here should be
|
||
|
// opened against the Yarn repository.
|
||
|
|
||
|
const path = require(`path`);
|
||
|
|
||
|
module.exports = function (_, opts) {
|
||
|
opts = opts || {};
|
||
|
|
||
|
if (opts.forceNodeResolution || !process.versions.pnp)
|
||
|
return opts;
|
||
|
|
||
|
// It would be nice if we could throw, but that would break the transparent
|
||
|
// compatibility with packages that use `resolve` today (such as Gulp). Since
|
||
|
// it's the whole point of this patch, we don't.
|
||
|
//
|
||
|
// if (opts.packageIterator || opts.paths)
|
||
|
// throw new Error(`The "packageIterator" and "paths" options cannot be used in PnP environments. Set "forceNodeResolution: true" if absolutely needed, or branch on process.versions.pnp otherwise.`);
|
||
|
|
||
|
const {findPnpApi} = require(`module`);
|
||
|
|
||
|
const runPnpResolution = (request, basedir) => {
|
||
|
// Extract the name of the package being requested (1=package name, 2=internal path)
|
||
|
const parts = request.match(/^((?:@[^/]+\/)?[^/]+)(\/.*)?/);
|
||
|
if (!parts)
|
||
|
throw new Error(`Assertion failed: Expected the "resolve" package to call the "paths" callback with package names only (got "${request}")`);
|
||
|
|
||
|
// Make sure that basedir ends with a slash
|
||
|
if (basedir.charAt(basedir.length - 1) !== `/`)
|
||
|
basedir = path.join(basedir, `/`);
|
||
|
|
||
|
const api = findPnpApi(basedir);
|
||
|
if (api === null)
|
||
|
return undefined;
|
||
|
|
||
|
// This is guaranteed to return the path to the "package.json" file from the given package
|
||
|
let manifestPath;
|
||
|
try {
|
||
|
manifestPath = api.resolveToUnqualified(`${parts[1]}/package.json`, basedir, {considerBuiltins: false});
|
||
|
} catch (err) {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
if (manifestPath === null)
|
||
|
throw new Error(`Assertion failed: The resolution thinks that "${parts[1]}" is a Node builtin`);
|
||
|
|
||
|
// Strip the package.json to get the package folder
|
||
|
const packagePath = path.dirname(manifestPath);
|
||
|
|
||
|
// Attach the internal path to the resolved package directory
|
||
|
const unqualifiedPath = typeof parts[2] !== `undefined`
|
||
|
? path.join(packagePath, parts[2])
|
||
|
: packagePath;
|
||
|
|
||
|
return {packagePath, unqualifiedPath};
|
||
|
};
|
||
|
|
||
|
const runPnpResolutionOnArray = (request, paths) => {
|
||
|
for (let i = 0; i < paths.length; i++) {
|
||
|
const resolution = runPnpResolution(request, paths[i]);
|
||
|
if (resolution || i === paths.length - 1) {
|
||
|
return resolution;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return null;
|
||
|
};
|
||
|
|
||
|
const originalPaths = Array.isArray(opts.paths) ? opts.paths : [];
|
||
|
|
||
|
const packageIterator = (request, basedir, getCandidates, opts) => {
|
||
|
const pathsToTest = [basedir].concat(originalPaths);
|
||
|
const resolution = runPnpResolutionOnArray(request, pathsToTest);
|
||
|
if (resolution == null)
|
||
|
return getCandidates();
|
||
|
|
||
|
return [resolution.unqualifiedPath];
|
||
|
};
|
||
|
|
||
|
const paths = (request, basedir, getNodeModulePaths, opts) => {
|
||
|
const pathsToTest = [basedir].concat(originalPaths);
|
||
|
const resolution = runPnpResolutionOnArray(request, pathsToTest);
|
||
|
if (resolution == null)
|
||
|
return getNodeModulePaths().concat(originalPaths);
|
||
|
|
||
|
// Stip the local named folder
|
||
|
let nodeModules = path.dirname(resolution.packagePath);
|
||
|
|
||
|
// Strip the scope named folder if needed
|
||
|
if (request.match(/^@[^/]+\//))
|
||
|
nodeModules = path.dirname(nodeModules);
|
||
|
|
||
|
return [nodeModules];
|
||
|
};
|
||
|
|
||
|
// We need to keep track whether we're in `packageIterator` or not so that
|
||
|
// the code is compatible with both `resolve` 1.9+ and `resolve` 1.15+
|
||
|
let isInsideIterator = false;
|
||
|
|
||
|
if (!opts.__skipPackageIterator) {
|
||
|
opts.packageIterator = function (request, basedir, getCandidates, opts) {
|
||
|
isInsideIterator = true;
|
||
|
try {
|
||
|
return packageIterator(request, basedir, getCandidates, opts);
|
||
|
} finally {
|
||
|
isInsideIterator = false;
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
opts.paths = function (request, basedir, getNodeModulePaths, opts) {
|
||
|
if (isInsideIterator)
|
||
|
return getNodeModulePaths().concat(originalPaths);
|
||
|
|
||
|
return paths(request, basedir, getNodeModulePaths, opts);
|
||
|
};
|
||
|
|
||
|
return opts;
|
||
|
};
|