or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.md

index.mddocs/

0

# PNPM Lockfile Pruner

1

2

PNPM Lockfile Pruner provides functionality for pruning pnpm lockfiles (pnpm-lock.yaml files) by removing unused dependencies and packages from the dependency graph. It offers two main functions for pruning shared lockfiles across multiple workspace projects and individual project lockfiles, while maintaining lockfile integrity and handling optional dependencies appropriately.

3

4

## Package Information

5

6

- **Package Name**: @pnpm/lockfile.pruner

7

- **Package Type**: npm

8

- **Language**: TypeScript

9

- **Installation**: `pnpm add @pnpm/lockfile.pruner`

10

11

## Core Imports

12

13

```typescript

14

import { pruneSharedLockfile, pruneLockfile } from "@pnpm/lockfile.pruner";

15

```

16

17

For CommonJS:

18

19

```javascript

20

const { pruneSharedLockfile, pruneLockfile } = require("@pnpm/lockfile.pruner");

21

```

22

23

All types from @pnpm/lockfile.types are also re-exported:

24

25

```typescript

26

import {

27

Lockfile,

28

PackageSnapshots,

29

ProjectSnapshot,

30

ResolvedDependencies

31

} from "@pnpm/lockfile.pruner";

32

```

33

34

## Basic Usage

35

36

```typescript

37

import { pruneLockfile, pruneSharedLockfile, type Lockfile } from "@pnpm/lockfile.pruner";

38

import { type PackageManifest, type ProjectId } from "@pnpm/types";

39

40

// Prune a lockfile for a specific project

41

const prunedLockfile = pruneLockfile(

42

lockfile, // The lockfile to prune

43

packageManifest, // The project's package.json content

44

'.' as ProjectId, // Project identifier (usually '.' for root)

45

{

46

warn: (msg: string) => console.warn(msg)

47

}

48

);

49

50

// Prune a shared lockfile (removes unused packages across all projects)

51

const prunedSharedLockfile = pruneSharedLockfile(lockfile, {

52

warn: (msg: string) => console.warn(msg)

53

});

54

```

55

56

## Capabilities

57

58

### Project-Specific Lockfile Pruning

59

60

Prunes a lockfile for a specific project/importer by removing packages not needed by that project while preserving necessary dependencies.

61

62

```typescript { .api }

63

/**

64

* Prunes a lockfile for a specific project/importer by removing packages

65

* not needed by that importer

66

* @param lockfile - The lockfile to prune

67

* @param pkg - The package.json manifest for the project

68

* @param importerId - The project ID (path identifier)

69

* @param opts - Pruning options

70

* @returns Pruned lockfile with unused packages removed

71

*/

72

function pruneLockfile(

73

lockfile: Lockfile,

74

pkg: PackageManifest,

75

importerId: ProjectId,

76

opts: {

77

warn?: (msg: string) => void;

78

dependenciesGraph?: DependenciesGraph;

79

}

80

): Lockfile;

81

```

82

83

### Shared Lockfile Pruning

84

85

Prunes shared lockfiles by removing unused packages while preserving packages needed by any importer in a workspace.

86

87

```typescript { .api }

88

/**

89

* Prunes shared lockfiles by removing unused packages while preserving

90

* packages needed by any importer

91

* @param lockfile - The lockfile to prune

92

* @param opts - Pruning options

93

* @returns Pruned lockfile with unused packages removed

94

*/

95

function pruneSharedLockfile(

96

lockfile: Lockfile,

97

opts?: {

98

dependenciesGraph?: DependenciesGraph;

99

warn?: (msg: string) => void;

100

}

101

): Lockfile;

102

```

103

104

## Types

105

106

### Core Lockfile Types

107

108

```typescript { .api }

109

interface Lockfile {

110

importers: Record<ProjectId, ProjectSnapshot>;

111

lockfileVersion: string;

112

packages?: PackageSnapshots;

113

time?: Record<string, string>;

114

catalogs?: CatalogSnapshots;

115

overrides?: Record<string, string>;

116

packageExtensionsChecksum?: string;

117

ignoredOptionalDependencies?: string[];

118

patchedDependencies?: Record<string, PatchFile>;

119

pnpmfileChecksum?: string;

120

settings?: LockfileSettings;

121

}

122

123

interface ProjectSnapshot {

124

specifiers: ResolvedDependencies;

125

dependencies?: ResolvedDependencies;

126

optionalDependencies?: ResolvedDependencies;

127

devDependencies?: ResolvedDependencies;

128

dependenciesMeta?: DependenciesMeta;

129

publishDirectory?: string;

130

}

131

132

interface PackageSnapshots {

133

[packagePath: DepPath]: PackageSnapshot;

134

}

135

136

interface PackageSnapshot {

137

resolution: LockfileResolution;

138

id?: string;

139

optional?: true;

140

patched?: true;

141

hasBin?: true;

142

name?: string;

143

version?: string;

144

dependencies?: ResolvedDependencies;

145

optionalDependencies?: ResolvedDependencies;

146

peerDependencies?: Record<string, string>;

147

peerDependenciesMeta?: Record<string, { optional: true }>;

148

transitivePeerDependencies?: string[];

149

bundledDependencies?: string[] | boolean;

150

engines?: Record<string, string> & { node: string };

151

os?: string[];

152

cpu?: string[];

153

libc?: string[];

154

deprecated?: string;

155

}

156

157

type ResolvedDependencies = Record<string, string>;

158

```

159

160

### Resolution Types

161

162

```typescript { .api }

163

type LockfileResolution = Resolution | { integrity: string };

164

165

type Resolution =

166

| TarballResolution

167

| GitRepositoryResolution

168

| DirectoryResolution;

169

170

interface TarballResolution {

171

type?: undefined;

172

tarball: string;

173

integrity?: string;

174

path?: string;

175

}

176

177

interface GitRepositoryResolution {

178

type: "git";

179

repo: string;

180

commit: string;

181

path?: string;

182

}

183

184

interface DirectoryResolution {

185

type: "directory";

186

directory: string;

187

}

188

```

189

190

### Supporting Types

191

192

```typescript { .api }

193

interface CatalogSnapshots {

194

[catalogName: string]: { [dependencyName: string]: ResolvedCatalogEntry };

195

}

196

197

interface ResolvedCatalogEntry {

198

readonly specifier: string; // The ^1.2.3 portion of catalog entry

199

readonly version: string; // The concrete resolved version: 1.2.3

200

}

201

202

interface LockfileSettings {

203

autoInstallPeers?: boolean;

204

excludeLinksFromLockfile?: boolean;

205

peersSuffixMaxLength?: number;

206

}

207

208

interface DependenciesMeta {

209

[dependencyName: string]: {

210

injected?: boolean;

211

node?: string;

212

patch?: string;

213

};

214

}

215

216

type DependenciesGraph = Record<DepPath, { optional?: boolean }>;

217

```

218

219

### Imported Types

220

221

```typescript { .api }

222

// From @pnpm/types

223

type DepPath = string & { __brand: "DepPath" };

224

type ProjectId = string & { __brand: "ProjectId" };

225

226

interface PackageManifest {

227

name?: string;

228

version?: string;

229

dependencies?: Record<string, string>;

230

devDependencies?: Record<string, string>;

231

optionalDependencies?: Record<string, string>;

232

peerDependencies?: Record<string, string>;

233

bundledDependencies?: string[];

234

// ... other package.json fields

235

}

236

237

// From @pnpm/patching.types (re-exported)

238

interface PatchFile {

239

path: string;

240

hash: string;

241

}

242

```

243

244

## Error Handling

245

246

Both pruning functions accept an optional `warn` callback that will be called when:

247

- A package resolution cannot be found in the lockfile

248

- Missing dependencies are encountered during pruning

249

- Inconsistencies in the dependency graph are detected

250

251

```typescript

252

const result = pruneLockfile(lockfile, pkg, importerId, {

253

warn: (message: string) => {

254

console.warn(`Pruning warning: ${message}`);

255

// Log to external system, accumulate errors, etc.

256

}

257

});

258

```

259

260

## Usage Patterns

261

262

### Removing Unused Dependencies

263

264

The primary use case is removing packages that are no longer referenced:

265

266

```typescript

267

import { pruneLockfile } from "@pnpm/lockfile.pruner";

268

269

// Remove packages not needed by the current project

270

const cleaned = pruneLockfile(lockfile, packageJson, '.' as ProjectId, {

271

warn: console.warn

272

});

273

```

274

275

### Workspace Pruning

276

277

For monorepos, use `pruneSharedLockfile` to remove packages not needed by any project:

278

279

```typescript

280

import { pruneSharedLockfile } from "@pnpm/lockfile.pruner";

281

282

// Remove packages not needed by any workspace project

283

const cleanedWorkspace = pruneSharedLockfile(lockfile, {

284

warn: console.warn

285

});

286

```

287

288

### Optional Dependency Handling

289

290

The pruning functions correctly handle optional dependencies:

291

- Optional packages are marked with `optional: true`

292

- Packages used both optionally and required are marked as required

293

- Optional-only packages maintain their optional status

294

295

```typescript

296

// The pruning functions automatically handle cases like:

297

// - Package used as both optional and regular dependency

298

// - Transitive optional dependencies

299

// - Optional dependencies that become required through other paths

300

```

301

302

### Linked Dependencies

303

304

Local linked dependencies (using `link:` protocol) are preserved even if not explicitly declared in package.json, maintaining workspace functionality:

305

306

```typescript

307

// Linked dependencies like "my-pkg": "link:../my-pkg" are preserved

308

// during pruning to maintain local workspace connections

309

```