Skip to content

Commit

Permalink
Correctly resolve peerDependencies for concurrent installs (#2801)
Browse files Browse the repository at this point in the history
* Correctly resolve peerDependencies for concurrent installs

* Tests for resolving peerDependencies when using add command
  • Loading branch information
kamilogorek authored and bestander committed Feb 28, 2017
1 parent cd13d01 commit 0ad2bf9
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 41 deletions.
53 changes: 53 additions & 0 deletions __tests__/commands/add.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* @flow */

import {ConsoleReporter} from '../../src/reporters/index.js';
import * as reporters from '../../src/reporters/index.js';
import {getPackageVersion, createLockfile, explodeLockfile, run as buildRun, runInstall} from './_helpers.js';
import {Add} from '../../src/cli/commands/add.js';
import * as constants from '../../src/constants.js';
Expand Down Expand Up @@ -702,3 +703,55 @@ test.concurrent('install with latest tag and --prefer-offline flag', (): Promise
assert.notEqual(version, '1.1.0');
});
});

test.concurrent('doesn\'t warn when peer dependency is met during add', (): Promise<void> => {
return buildRun(
reporters.BufferReporter,
fixturesLoc,
async (args, flags, config, reporter, lockfile): Promise<void> => {
const add = new Add(args, flags, config, reporter, lockfile);
await add.init();
const output = reporter.getBuffer();
const warnings = output.filter((entry) => entry.type === 'warning');
assert(!warnings.some((warning) => warning.data.toString().toLowerCase().includes('unmet peer')));
assert(!warnings.some((warning) => warning.data.toString().toLowerCase().includes('incorrect peer')));
},
['[email protected]', '[email protected]'],
{},
'add-with-peer-dependency-met',
);
});

test.concurrent('warns when peer dependency is not met during add', (): Promise<void> => {
return buildRun(
reporters.BufferReporter,
fixturesLoc,
async (args, flags, config, reporter, lockfile): Promise<void> => {
const add = new Add(args, flags, config, reporter, lockfile);
await add.init();
const output = reporter.getBuffer();
const warnings = output.filter((entry) => entry.type === 'warning');
assert(warnings.some((warning) => warning.data.toString().toLowerCase().includes('unmet peer')));
},
['[email protected]'],
{},
'add-with-peer-dependency-not-met',
);
});

test.concurrent('warns when peer dependency is incorrect during add', (): Promise<void> => {
return buildRun(
reporters.BufferReporter,
fixturesLoc,
async (args, flags, config, reporter, lockfile): Promise<void> => {
const add = new Add(args, flags, config, reporter, lockfile);
await add.init();
const output = reporter.getBuffer();
const warnings = output.filter((entry) => entry.type === 'warning');
assert(warnings.some((warning) => warning.data.toString().toLowerCase().includes('incorrect peer')));
},
['[email protected]', '[email protected]'],
{},
'add-with-peer-dependency-incorrect',
);
});
Empty file.
Empty file.
Empty file.
50 changes: 9 additions & 41 deletions src/package-linker.js
Original file line number Diff line number Diff line change
Expand Up @@ -288,48 +288,16 @@ export default class PackageLinker {

for (const name in peerDeps) {
const range = peerDeps[name];

// find a dependency in the tree above us that matches
let searchPatterns: Array<string> = [];
for (let request of ref.requests) {
do {
// get resolved pattern for this request
const dep = this.resolver.getResolvedPattern(request.pattern);
if (!dep) {
continue;
}

//
const ref = dep._reference;
invariant(ref, 'expected reference');
searchPatterns = searchPatterns.concat(ref.dependencies);
} while (request = request.parentRequest);
}

// if the resolver already knows about the peer dependency, add those patterns as well
const packagePatterns = this.resolver.patternsByPackage[name];
if (packagePatterns) {
searchPatterns = searchPatterns.concat(packagePatterns);
}

// include root seed patterns last
searchPatterns = searchPatterns.concat(this.resolver.seedPatterns);

// find matching dep in search patterns
let foundDep: ?{pattern: string, version: string};
for (const pattern of searchPatterns) {
const dep = this.resolver.getResolvedPattern(pattern);
if (dep && dep.name === name) {
foundDep = {pattern, version: dep.version};
break;
}
}

// validate found peer dependency
if (foundDep && this._satisfiesPeerDependency(range, foundDep.version)) {
ref.addDependencies([foundDep.pattern]);
const patterns = this.resolver.patternsByPackage[name] || [];
const foundPattern = patterns.find((pattern) => {
const resolvedPattern = this.resolver.getResolvedPattern(pattern);
return resolvedPattern ? this._satisfiesPeerDependency(range, resolvedPattern.version) : false;
});

if (foundPattern) {
ref.addDependencies([foundPattern]);
} else {
const depError = foundDep ? 'incorrectPeer' : 'unmetPeer';
const depError = patterns.length > 0 ? 'incorrectPeer' : 'unmetPeer';
const [pkgHuman, depHuman] = [`${pkg.name}@${pkg.version}`, `${name}@${range}`];
this.reporter.warn(this.reporter.lang(depError, pkgHuman, depHuman));
}
Expand Down

0 comments on commit 0ad2bf9

Please sign in to comment.