Skip to content

Commit

Permalink
Implements optional peer dependencies (#6671)
Browse files Browse the repository at this point in the history
* Implements optional peer dependencies

* Implements the new peerDependenciesMeta field

* Runs prettier

* Updates the changelog

* Fixes flow
  • Loading branch information
arcanis committed Dec 3, 2018
1 parent 066f0c8 commit 011a634
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 1 deletion.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Expand Up @@ -4,6 +4,14 @@ Please add one entry in this file for each change in Yarn's behavior. Use the sa

## Master

- Implements a new `package.json` field: `peerDependenciesMeta`

[#6671](https://github.com/yarnpkg/yarn/pull/6671) - [**Maël Nison**](https://twitter.com/arcanis)

- Adds an `optional` settings to `peerDependenciesMeta` to silence missing peer dependency warnings

[#6671](https://github.com/yarnpkg/yarn/pull/6671) - [**Maël Nison**](https://twitter.com/arcanis)

- Implements `yarn policies set-version [range]`. Check [the documentation]() for usage & tips.

[#6673](https://github.com/yarnpkg/yarn/pull/6673) - [**Maël Nison**](https://twitter.com/arcanis)
Expand All @@ -16,6 +24,10 @@ Please add one entry in this file for each change in Yarn's behavior. Use the sa

[#6683](https://github.com/yarnpkg/yarn/issues/6683) - [**Rowan Lonsdale**](https://github.com/hWorblehat)

- Fixes postinstall scripts for third-party packages when they were referencing a binary from their own dependencies

[#6712](https://github.com/yarnpkg/yarn/pull/6712) - [**Maël Nison**](https://twitter.com/arcanis)

## 1.12.3

**Important:** This release contains a cache bump. It will cause the very first install following the upgrade to take slightly more time, especially if you don't use the [Offline Mirror](https://yarnpkg.com/blog/2016/11/24/offline-mirror/) feature. After that everything will be back to normal.
Expand Down
16 changes: 16 additions & 0 deletions __tests__/commands/install/integration.js
Expand Up @@ -1123,3 +1123,19 @@ test('install will not warn for missing peerDep when both shallower and deeper',
const warningMessage = messageParts.every(part => stdout.includes(part));
expect(warningMessage).toBe(false);
}));

test('install will warn for missing peer dependencies', () =>
runInstall({}, 'missing-peer-dep', (config, reporter, install, getStdout) => {
const stdout = getStdout();
const messageParts = reporter.lang('unmetPeer', 'undefined').split('undefined');
const warningMessage = messageParts.every(part => stdout.includes(part));
expect(warningMessage).toBe(true);
}));

test('install will not warn for missing optional peer dependencies', () =>
runInstall({}, 'missing-opt-peer-dep', (config, reporter, install, getStdout) => {
const stdout = getStdout();
const messageParts = reporter.lang('unmetPeer', 'undefined').split('undefined');
const warningMessage = messageParts.every(part => stdout.includes(part));
expect(warningMessage).toBe(false);
}));
12 changes: 12 additions & 0 deletions __tests__/fixtures/install/missing-opt-peer-dep/foo/package.json
@@ -0,0 +1,12 @@
{
"name": "foo",
"version": "1.0.0",
"peerDependencies": {
"bar": "*"
},
"peerDependenciesMeta": {
"bar": {
"optional": true
}
}
}
6 changes: 6 additions & 0 deletions __tests__/fixtures/install/missing-opt-peer-dep/package.json
@@ -0,0 +1,6 @@
{
"name": "missing-peer-dep",
"dependencies": {
"foo": "file:./foo"
}
}
7 changes: 7 additions & 0 deletions __tests__/fixtures/install/missing-peer-dep/foo/package.json
@@ -0,0 +1,7 @@
{
"name": "foo",
"version": "1.0.0",
"peerDependencies": {
"bar": "*"
}
}
6 changes: 6 additions & 0 deletions __tests__/fixtures/install/missing-peer-dep/package.json
@@ -0,0 +1,6 @@
{
"name": "missing-peer-dep",
"dependencies": {
"foo": "file:./foo"
}
}
10 changes: 9 additions & 1 deletion src/package-linker.js
Expand Up @@ -595,11 +595,15 @@ export default class PackageLinker {
resolvePeerModules() {
for (const pkg of this.resolver.getManifests()) {
const peerDeps = pkg.peerDependencies;
const peerDepsMeta = pkg.peerDependenciesMeta;

if (!peerDeps) {
continue;
}

const ref = pkg._reference;
invariant(ref, 'Package reference is missing');

// TODO: We are taking the "shortest" ref tree but there may be multiple ref trees with the same length
const refTree = ref.requests.map(req => req.parentNames).sort((arr1, arr2) => arr1.length - arr2.length)[0];

Expand All @@ -618,6 +622,10 @@ export default class PackageLinker {

for (const peerDepName in peerDeps) {
const range = peerDeps[peerDepName];
const meta = peerDepsMeta && peerDepsMeta[peerDepName];

const isOptional = !!(meta && meta.optional);

const peerPkgs = this.resolver.getAllInfoForPackageName(peerDepName);

let peerError = 'unmetPeer';
Expand Down Expand Up @@ -649,7 +657,7 @@ export default class PackageLinker {
resolvedPeerPkg.level,
),
);
} else {
} else if (!isOptional) {
this.reporter.warn(
this.reporter.lang(
peerError,
Expand Down
17 changes: 17 additions & 0 deletions src/types.js
Expand Up @@ -13,6 +13,20 @@ export type CLIFunction = (config: Config, reporter: Reporter, flags: Object, ar
type _CLIFunctionReturn = boolean;
export type CLIFunctionReturn = ?_CLIFunctionReturn | Promise<?_CLIFunctionReturn>;

export type DependencyMeta = {};

export type DependenciesMeta = {
[name: string]: DependencyMeta,
};

export type PeerDependencyMeta = {
optional?: boolean,
};

export type PeerDependenciesMeta = {
[name: string]: PeerDependencyMeta,
};

// dependency request pattern data structure that's used to request dependencies from a
// PackageResolver
export type DependencyRequestPattern = {
Expand Down Expand Up @@ -132,6 +146,9 @@ export type Manifest = {
peerDependencies?: Dependencies,
optionalDependencies?: Dependencies,

dependenciesMeta?: DependenciesMeta,
peerDependenciesMeta?: PeerDependenciesMeta,

bundleDependencies?: Array<string>,
bundledDependencies?: Array<string>,

Expand Down

0 comments on commit 011a634

Please sign in to comment.