Skip to content
Closed
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ Options:
-S, --silent If using npm, don't save in package.json
-Y, --yarn Install with Yarn
-P, --pnpm Install with pnpm
-n, --no-registry Do not use a remote registry to find dependencies list
-r, --registry <uri> Install from custom registry (defaults to NPM registry)
--dry-run Do not install packages, but show the install command that will be run
-a, --auth <token> Provide an NPM authToken for private packages.
Expand Down
5 changes: 5 additions & 0 deletions src/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ program
.option("-S, --silent", "If using npm, don't save in package.json")
.option("-Y, --yarn", "Install with Yarn")
.option("-P, --pnpm", "Install with pnpm")
.option(
"-n, --no-registry",
"Use local node_modules instead of a remote registry to get the list of peerDependencies"
)
.option(
"-r, --registry <uri>",
"Install from custom registry (defaults to NPM registry)"
Expand Down Expand Up @@ -156,6 +160,7 @@ const options = {
packageName,
// If packageVersion is undefined, default to "latest"
version: packageVersion || "latest",
noRegistry: program.noRegistry,
// If registry is undefined, default to the official NPM registry
// See: https://docs.npmjs.com/using-npm/registry.html
registry: program.registry || "https://registry.npmjs.org",
Expand Down
82 changes: 52 additions & 30 deletions src/install-peerdeps.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,17 +106,20 @@ function spawnInstall(command, args) {
* Gets the contents of the package.json for a package at a specific version
* @param {Object} requestInfo - information needed to make the request for the data
* @param {string} requestInfo.packageName - the name of the package
* @param {Boolean} requestInfo.noRegistry - Gets the package dependencies list from the local node_modules instead of remote registry
* @param {string} requestInfo.registry - the URI of the registry on which the package is hosted
* @param {Boolean} onlyPeers - true if only the peers have been requested to be installed. In this case, check for the package to already have been installed.
* @param {string} version - the version (or version tag) to attempt to install. Ignored if an installed version of the package is found in node_modules.
* @param {string} requestInfo.version - the version (or version tag) to attempt to install. Ignored if an installed version of the package is found in node_modules.
* @returns {Promise<Object>} - a Promise which resolves to the JSON response from the registry
*/
function getPackageJson(
{ packageName, registry, auth, proxy },
onlyPeers,
function getPackageJson({
packageName,
noRegistry,
registry,
auth,
proxy,
version
) {
if (onlyPeers) {
}) {
if (noRegistry) {
if (fs.existsSync(`node_modules/${packageName}`)) {
return Promise.resolve(
JSON.parse(
Expand Down Expand Up @@ -144,12 +147,40 @@ function getPackageJson(
});
}

/**
* Builds the package install string based on the version
* @param {Object} options - information needed to build a package install string
* @param {string} optoins.name - name of the package
* @param {string} options.version - version string of the package
* @returns {string} - the package name and version formatted for an install command
*/
const getPackageString = ({ name, version }) => {
// check for whitespace
if (version.indexOf(" ") >= 0) {
// Semver ranges can have a join of comparator sets
// e.g. '^3.0.2 || ^4.0.0' or '>=1.2.7 <1.3.0'
// Take each version in the range and find the maxSatisfying
const rangeSplit = version
.split(" ")
.map(v => coerce(v))
.filter(v => valid(v));
const versionToInstall = maxSatisfying(rangeSplit, version);

if (versionToInstall === null) {
return name;
}
return `${name}@${versionToInstall}`;
}
return `${name}@${version}`;
};

/**
* Installs the peer dependencies of the provided packages
* @param {Object} options - options for the install child_process
* @param {string} options.packageName - the name of the package for which to install peer dependencies
* @param {string} options.version - the version of the package
* @param {string} options.packageManager - the package manager to use (Yarn or npm)
* @param {string} options.noRegistry - Disable going to a remote registry to find a list of peers. Use local node_modules instead
* @param {string} options.registry - the URI of the registry to install from
* @param {string} options.dev - whether to install the dependencies as devDependencies
* @param {boolean} options.onlyPeers - whether to install the package itself or only its peers
Expand All @@ -163,6 +194,7 @@ function installPeerDeps(
packageName,
version,
packageManager,
noRegistry,
registry,
dev,
global,
Expand All @@ -175,7 +207,7 @@ function installPeerDeps(
},
cb
) {
getPackageJson({ packageName, registry, auth, proxy }, onlyPeers, version)
getPackageJson({ packageName, noRegistry, registry, auth, proxy, version })
// Catch before .then because the .then is so long
.catch(err => cb(err))
.then(data => {
Expand All @@ -192,28 +224,18 @@ function installPeerDeps(
// If onlyPeers option is true, don't install the package itself,
// only its peers.
let packagesString = onlyPeers ? "" : `${packageName}@${data.version}`;
Object.keys(peerDepsVersionMap).forEach(depName => {
// Get the peer dependency version
const peerDepVersion = peerDepsVersionMap[depName];
// Check if there is whitespace
if (peerDepVersion.indexOf(" ") >= 0) {
// Semver ranges can have a join of comparator sets
// e.g. '^3.0.2 || ^4.0.0' or '>=1.2.7 <1.3.0'
// Take each version in the range and find the maxSatisfying
const rangeSplit = peerDepVersion
.split(" ")
.map(v => coerce(v))
.filter(v => valid(v));
const versionToInstall = maxSatisfying(rangeSplit, peerDepVersion);
if (versionToInstall === null) {
packagesString += ` ${depName}`;
} else {
packagesString += ` ${depName}@${versionToInstall}`;
}
} else {
packagesString += ` ${depName}@${peerDepVersion}`;
}
});

const packageList = Object.keys(peerDepsVersionMap).map(name =>
getPackageString({
name,
version: peerDepsVersionMap[name]
})
);

if (packageList.length > 0) {
packagesString = `${packagesString} ${packageList.join(" ")}`;
}

// Construct command based on package manager of current project
let globalFlag = packageManager === C.yarn ? "global" : "--global";
if (!global) {
Expand Down