mirror of
https://github.com/pnpm/pnpm.git
synced 2025-12-23 23:29:17 -05:00
feat: support peerDependencyRules for muting peer dep issues (#4212)
close #4183
This commit is contained in:
21
.changeset/famous-toys-provide.md
Normal file
21
.changeset/famous-toys-provide.md
Normal file
@@ -0,0 +1,21 @@
|
||||
---
|
||||
"pnpm": minor
|
||||
"@pnpm/plugin-commands-installation": minor
|
||||
---
|
||||
|
||||
In order to mute some types of peer dependency warnings, a new section in `package.json` may be used for declaring peer dependency warning rules. For example, the next configuration will turn off any warnings about missing `babel-loader` peer dependency and about `@angular/common`, when the wanted version of `@angular/common` is not v13.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "foo",
|
||||
"version": "0.0.0",
|
||||
"pnpm": {
|
||||
"peerDependencyRules": {
|
||||
"ignoreMissing": ["babel-loader"],
|
||||
"allowedVersions": {
|
||||
"@angular/common": "13"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
5
.changeset/itchy-berries-wink.md
Normal file
5
.changeset/itchy-berries-wink.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@pnpm/core": minor
|
||||
---
|
||||
|
||||
New optional option supported: `peerDependencyRules`. This setting allows to mute specific peer dependency warnings.
|
||||
5
.changeset/plenty-mayflies-hug.md
Normal file
5
.changeset/plenty-mayflies-hug.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@pnpm/types": minor
|
||||
---
|
||||
|
||||
New field added to package.json.pnpm section: peerDependencyRules.
|
||||
26
packages/core/src/install/createPeerDependencyPatcher.ts
Normal file
26
packages/core/src/install/createPeerDependencyPatcher.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { PeerDependencyRules, ReadPackageHook } from '@pnpm/types'
|
||||
import isEmpty from 'ramda/src/isEmpty'
|
||||
|
||||
export default function (
|
||||
peerDependencyRules: PeerDependencyRules
|
||||
): ReadPackageHook {
|
||||
const ignoreMissing = new Set(peerDependencyRules.ignoreMissing ?? [])
|
||||
return ((pkg) => {
|
||||
if (isEmpty(pkg.peerDependencies)) return pkg
|
||||
for (const [peerName, peerVersion] of Object.entries(pkg.peerDependencies ?? {})) {
|
||||
if (ignoreMissing.has(peerName) && !pkg.peerDependenciesMeta?.[peerName]?.optional) {
|
||||
pkg.peerDependenciesMeta = pkg.peerDependenciesMeta ?? {}
|
||||
pkg.peerDependenciesMeta[peerName] = {
|
||||
optional: true,
|
||||
}
|
||||
}
|
||||
if (
|
||||
peerDependencyRules.allowedVersions?.[peerName] &&
|
||||
peerVersion !== '*'
|
||||
) {
|
||||
pkg.peerDependencies![peerName] += ` || ${peerDependencyRules.allowedVersions[peerName]}`
|
||||
}
|
||||
}
|
||||
return pkg
|
||||
}) as ReadPackageHook
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import { WorkspacePackages } from '@pnpm/resolver-base'
|
||||
import { StoreController } from '@pnpm/store-controller-types'
|
||||
import {
|
||||
PackageExtension,
|
||||
PeerDependencyRules,
|
||||
ReadPackageHook,
|
||||
Registries,
|
||||
} from '@pnpm/types'
|
||||
@@ -80,6 +81,7 @@ export interface StrictInstallOptions {
|
||||
symlink: boolean
|
||||
enableModulesDir: boolean
|
||||
modulesCacheMaxAge: number
|
||||
peerDependencyRules: PeerDependencyRules
|
||||
|
||||
hoistPattern: string[] | undefined
|
||||
forceHoistPattern: boolean
|
||||
|
||||
@@ -49,6 +49,7 @@ import {
|
||||
DependenciesField,
|
||||
DependencyManifest,
|
||||
PackageExtension,
|
||||
PeerDependencyRules,
|
||||
ProjectManifest,
|
||||
ReadPackageHook,
|
||||
} from '@pnpm/types'
|
||||
@@ -68,6 +69,7 @@ import removeDeps from '../uninstall/removeDeps'
|
||||
import allProjectsAreUpToDate from './allProjectsAreUpToDate'
|
||||
import createPackageExtender from './createPackageExtender'
|
||||
import createVersionsOverrider from './createVersionsOverrider'
|
||||
import createPeerDependencyPatcher from './createPeerDependencyPatcher'
|
||||
import extendOptions, {
|
||||
InstallOptions,
|
||||
StrictInstallOptions,
|
||||
@@ -170,6 +172,7 @@ export async function mutateModules (
|
||||
overrides: opts.overrides,
|
||||
lockfileDir: opts.lockfileDir,
|
||||
packageExtensions: opts.packageExtensions,
|
||||
peerDependencyRules: opts.peerDependencyRules,
|
||||
})
|
||||
const ctx = await getContext(projects, opts)
|
||||
const pruneVirtualStore = ctx.modulesFile?.prunedAt && opts.modulesCacheMaxAge > 0
|
||||
@@ -483,11 +486,13 @@ export function createReadPackageHook (
|
||||
lockfileDir,
|
||||
overrides,
|
||||
packageExtensions,
|
||||
peerDependencyRules,
|
||||
readPackageHook,
|
||||
}: {
|
||||
lockfileDir: string
|
||||
overrides?: Record<string, string>
|
||||
packageExtensions?: Record<string, PackageExtension>
|
||||
peerDependencyRules?: PeerDependencyRules
|
||||
readPackageHook?: ReadPackageHook
|
||||
}
|
||||
): ReadPackageHook | undefined {
|
||||
@@ -498,6 +503,12 @@ export function createReadPackageHook (
|
||||
if (!isEmpty(packageExtensions ?? {})) {
|
||||
hooks.push(createPackageExtender(packageExtensions!))
|
||||
}
|
||||
if (
|
||||
peerDependencyRules != null &&
|
||||
(!isEmpty(peerDependencyRules.ignoreMissing) || !isEmpty(peerDependencyRules.allowedVersions))
|
||||
) {
|
||||
hooks.push(createPeerDependencyPatcher(peerDependencyRules))
|
||||
}
|
||||
if (hooks.length === 0) {
|
||||
return readPackageHook
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import createPeerDependencyPatcher from '@pnpm/core/lib/install/createPeerDependencyPatcher'
|
||||
|
||||
test('createPeerDependencyPatcher() ignores missing', () => {
|
||||
const patcher = createPeerDependencyPatcher({
|
||||
ignoreMissing: ['foo'],
|
||||
})
|
||||
const patchedPkg = patcher({
|
||||
peerDependencies: {
|
||||
foo: '*',
|
||||
bar: '*',
|
||||
},
|
||||
})
|
||||
expect(patchedPkg['peerDependenciesMeta']).toStrictEqual({
|
||||
foo: {
|
||||
optional: true,
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test('createPeerDependencyPatcher() extends peer ranges', () => {
|
||||
const patcher = createPeerDependencyPatcher({
|
||||
allowedVersions: {
|
||||
foo: '1',
|
||||
qar: '1',
|
||||
},
|
||||
})
|
||||
const patchedPkg = patcher({
|
||||
peerDependencies: {
|
||||
foo: '0',
|
||||
bar: '0',
|
||||
qar: '*',
|
||||
},
|
||||
})
|
||||
expect(patchedPkg['peerDependencies']).toStrictEqual({
|
||||
foo: '0 || 1',
|
||||
bar: '0',
|
||||
qar: '*',
|
||||
})
|
||||
})
|
||||
@@ -1,15 +1,26 @@
|
||||
import { ProjectManifest } from '@pnpm/types'
|
||||
import {
|
||||
PackageExtension,
|
||||
PeerDependencyRules,
|
||||
ProjectManifest,
|
||||
} from '@pnpm/types'
|
||||
|
||||
export default function getOptionsFromRootManifest (manifest: ProjectManifest) {
|
||||
export default function getOptionsFromRootManifest (manifest: ProjectManifest): {
|
||||
overrides?: Record<string, string>
|
||||
neverBuiltDependencies?: string[]
|
||||
packageExtensions?: Record<string, PackageExtension>
|
||||
peerDependencyRules?: PeerDependencyRules
|
||||
} {
|
||||
// We read Yarn's resolutions field for compatibility
|
||||
// but we really replace the version specs to any other version spec, not only to exact versions,
|
||||
// so we cannot call it resolutions
|
||||
const overrides = manifest.pnpm?.overrides ?? manifest.resolutions
|
||||
const neverBuiltDependencies = manifest.pnpm?.neverBuiltDependencies ?? []
|
||||
const packageExtensions = manifest.pnpm?.packageExtensions
|
||||
const peerDependencyRules = manifest.pnpm?.peerDependencyRules
|
||||
return {
|
||||
overrides,
|
||||
neverBuiltDependencies,
|
||||
packageExtensions,
|
||||
peerDependencyRules,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,11 +97,17 @@ export type DependencyManifest = BaseManifest & Required<Pick<BaseManifest, 'nam
|
||||
|
||||
export type PackageExtension = Pick<BaseManifest, 'dependencies' | 'optionalDependencies' | 'peerDependencies' | 'peerDependenciesMeta'>
|
||||
|
||||
export interface PeerDependencyRules {
|
||||
ignoreMissing?: string[]
|
||||
allowedVersions?: Record<string, string>
|
||||
}
|
||||
|
||||
export type ProjectManifest = BaseManifest & {
|
||||
pnpm?: {
|
||||
neverBuiltDependencies?: string[]
|
||||
overrides?: Record<string, string>
|
||||
packageExtensions?: Record<string, PackageExtension>
|
||||
peerDependencyRules?: PeerDependencyRules
|
||||
}
|
||||
private?: boolean
|
||||
resolutions?: Record<string, string>
|
||||
|
||||
Reference in New Issue
Block a user