Skip to content

Commit

Permalink
feat: add pnpm dedupe command
Browse files Browse the repository at this point in the history
  • Loading branch information
gluxon committed Jan 23, 2023
1 parent b78774e commit 7ab4221
Show file tree
Hide file tree
Showing 16 changed files with 434 additions and 3 deletions.
7 changes: 7 additions & 0 deletions .changeset/giant-crews-push.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@pnpm/plugin-commands-installation": minor
"@pnpm/core": minor
pnpm: minor
---

Add a `pnpm dedupe` command that removes dependencies from the lockfile by re-resolving the dependency graph. This work similar to yarn's [`yarn dedupe --strategy highest`](https://yarnpkg.com/cli/dedupe) command.
1 change: 1 addition & 0 deletions __fixtures__/workspace-with-lockfile-dupes/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "bar",
"dependencies": {
"ajv": "^6.10.2"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "foo",
"dependencies": {
"ajv": "^6.12.5"
}
}
80 changes: 80 additions & 0 deletions __fixtures__/workspace-with-lockfile-dupes/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
packages:
- 'packages/**'
1 change: 1 addition & 0 deletions pkg-manager/core/src/install/extendInstallOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export interface StrictInstallOptions {
linkWorkspacePackagesDepth: number
lockfileOnly: boolean
fixLockfile: boolean
dedupe: boolean
ignoreCompatibilityDb: boolean
ignoreDepScripts: boolean
ignorePackageManifest: boolean
Expand Down
31 changes: 31 additions & 0 deletions pkg-manager/core/src/install/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ export async function mutateModules (
!ctx.lockfileHadConflicts &&
!opts.update &&
!opts.fixLockfile &&
!opts.dedupe &&
installsOnly &&
(
frozenLockfile && !opts.lockfileOnly ||
Expand Down Expand Up @@ -644,6 +645,27 @@ function forgetResolutionsOfPrevWantedDeps (importer: ProjectSnapshot, wantedDep
}
}

function forgetResolutionsOfAllPrevWantedDeps (wantedLockfile: Lockfile) {
// Similar to the forgetResolutionsOfPrevWantedDeps function above, we can
// delete existing resolutions in importers to make sure they're resolved
// again.
if ((wantedLockfile.importers != null) && !isEmpty(wantedLockfile.importers)) {
wantedLockfile.importers = mapValues(
({ dependencies, devDependencies, optionalDependencies, ...rest }) => rest,
wantedLockfile.importers)
}

// The resolveDependencies function looks at previous PackageSnapshot
// dependencies/optionalDependencies blocks and merges them with new resolved
// deps. Clear the previous PackageSnapshot fields so the newly resolved deps
// are always used.
if ((wantedLockfile.packages != null) && !isEmpty(wantedLockfile.packages)) {
wantedLockfile.packages = mapValues(
({ dependencies, optionalDependencies, ...rest }) => rest,
wantedLockfile.packages)
}
}

export async function addDependenciesToPackage (
manifest: ProjectManifest,
dependencySelectors: string[],
Expand Down Expand Up @@ -798,6 +820,15 @@ const _installInContext: InstallFunction = async (projects, ctx, opts) => {
}), ctx.wantedLockfile.packages)
}

if (opts.dedupe) {
// Deleting recorded version resolutions from importers and packages. These
// fields will be regenerated using the preferred versions computed above.
//
// This is a bit different from a "full resolution", which completely
// ignores preferred versions from the lockfile.
forgetResolutionsOfAllPrevWantedDeps(ctx.wantedLockfile)
}

let {
dependenciesGraph,
dependenciesByProjectId,
Expand Down
37 changes: 37 additions & 0 deletions pkg-manager/plugin-commands-installation/src/dedupe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { docsUrl } from '@pnpm/cli-utils'
import { UNIVERSAL_OPTIONS } from '@pnpm/common-cli-options-help'
import renderHelp from 'render-help'
import * as install from './install'

export const rcOptionsTypes = cliOptionsTypes

export function cliOptionsTypes () {
return {}
}

export const commandNames = ['dedupe']

export function help () {
return renderHelp({
description: 'Perform an install removing older dependencies in the lockfile if a newer version can be used.',
descriptionLists: [
{
title: 'Options',
list: [
...UNIVERSAL_OPTIONS,
],
},
],
url: docsUrl('dedupe'),
usages: ['pnpm dedupe'],
})
}

export async function handler (
opts: install.InstallCommandOptions
) {
return install.handler({
...opts,
dedupe: true,
})
}
3 changes: 2 additions & 1 deletion pkg-manager/plugin-commands-installation/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as add from './add'
import * as dedupe from './dedupe'
import * as install from './install'
import * as fetch from './fetch'
import * as link from './link'
Expand All @@ -8,4 +9,4 @@ import * as unlink from './unlink'
import * as update from './update'
import * as importCommand from './import'

export { add, fetch, install, link, prune, remove, unlink, update, importCommand }
export { add, dedupe, fetch, install, link, prune, remove, unlink, update, importCommand }
1 change: 1 addition & 0 deletions pkg-manager/plugin-commands-installation/src/install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ export type InstallCommandOptions = Pick<Config,
pruneDirectDependencies?: boolean
pruneStore?: boolean
recursive?: boolean
dedupe?: boolean
saveLockfile?: boolean
workspace?: boolean
} & Partial<Pick<Config, 'modulesCacheMaxAge' | 'pnpmHomeDir' | 'preferWorkspacePackages'>>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export type InstallDepsOptions = Pick<Config,
updatePackageManifest?: boolean
useBetaCli?: boolean
recursive?: boolean
dedupe?: boolean
workspace?: boolean
} & Partial<Pick<Config, 'pnpmHomeDir'>>

Expand Down

0 comments on commit 7ab4221

Please sign in to comment.