or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mdcore-publishing.mdgit-operations.mdindex.mdnpm-operations.mdpackage-manager.mdutilities.mdversion-management.md

package-manager.mddocs/

0

# Package Manager Support

1

2

Multi-package-manager abstraction supporting npm, Yarn (Classic/Berry), pnpm, and Bun with unified configuration and command generation.

3

4

## Capabilities

5

6

### Package Manager Detection

7

8

Functions for detecting and configuring package managers.

9

10

```javascript { .api }

11

/**

12

* Get package manager configuration for a project

13

* @param rootDirectory - Project root directory

14

* @param package_ - Package.json object

15

* @returns Package manager configuration object

16

*/

17

function getPackageManagerConfig(

18

rootDirectory: string,

19

package_: {packageManager?: string}

20

): PackageManagerConfig;

21

22

/**

23

* Find lockfile for a specific package manager

24

* @param rootDirectory - Project root directory

25

* @param config - Package manager configuration

26

* @returns Lockfile path or undefined if not found

27

*/

28

function findLockfile(

29

rootDirectory: string,

30

config: PackageManagerConfig

31

): string | undefined;

32

33

/**

34

* Format command for display purposes

35

* @param command - Command tuple [cli, arguments]

36

* @returns Formatted command string

37

*/

38

function printCommand([cli, arguments_]: [string, string[]]): string;

39

```

40

41

**Usage Examples:**

42

43

```javascript

44

import { getPackageManagerConfig, findLockfile, printCommand } from "np/source/package-manager/index.js";

45

46

// Detect package manager

47

const packageManager = getPackageManagerConfig(process.cwd(), packageJson);

48

console.log(`Using package manager: ${packageManager.id}`);

49

50

// Find lockfile

51

const lockfile = findLockfile(process.cwd(), packageManager);

52

if (lockfile) {

53

console.log(`Found lockfile: ${lockfile}`);

54

}

55

56

// Format command for display

57

const installCmd = packageManager.installCommand;

58

console.log(`Install command: ${printCommand(installCmd)}`);

59

```

60

61

### Package Manager Configuration Interface

62

63

Unified configuration interface for all supported package managers.

64

65

```javascript { .api }

66

interface PackageManagerConfig {

67

/** Package manager identifier */

68

id: 'npm' | 'yarn' | 'pnpm' | 'bun';

69

70

/** CLI command name */

71

cli: string;

72

73

/** Install command with lockfile */

74

installCommand: [string, string[]];

75

76

/** Install command without lockfile */

77

installCommandNoLockfile: [string, string[]];

78

79

/** Generate version bump command */

80

versionCommand(input: string): [string, string[]];

81

82

/** Custom publish command (optional) */

83

publishCommand?: (args: string[]) => [string, string[]];

84

85

/** Whether to throw error on external registries */

86

throwOnExternalRegistry?: boolean;

87

}

88

```

89

90

### Supported Package Managers

91

92

Configuration objects for each supported package manager.

93

94

```javascript { .api }

95

/**

96

* NPM package manager configuration

97

*/

98

const npmConfig: PackageManagerConfig = {

99

id: 'npm',

100

cli: 'npm',

101

installCommand: ['npm', ['ci']],

102

installCommandNoLockfile: ['npm', ['install']],

103

versionCommand: (input) => ['npm', ['version', input]],

104

throwOnExternalRegistry: false

105

};

106

107

/**

108

* PNPM package manager configuration

109

*/

110

const pnpmConfig: PackageManagerConfig = {

111

id: 'pnpm',

112

cli: 'pnpm',

113

installCommand: ['pnpm', ['install', '--frozen-lockfile']],

114

installCommandNoLockfile: ['pnpm', ['install', '--no-lockfile']],

115

versionCommand: (input) => ['pnpm', ['version', input]],

116

throwOnExternalRegistry: true

117

};

118

119

/**

120

* Yarn Classic package manager configuration

121

*/

122

const yarnConfig: PackageManagerConfig = {

123

id: 'yarn',

124

cli: 'yarn',

125

installCommand: ['yarn', ['install', '--frozen-lockfile']],

126

installCommandNoLockfile: ['yarn', ['install', '--no-lockfile']],

127

versionCommand: (input) => ['yarn', ['version', '--new-version', input]],

128

throwOnExternalRegistry: false

129

};

130

131

/**

132

* Yarn Berry package manager configuration

133

*/

134

const yarnBerryConfig: PackageManagerConfig = {

135

id: 'yarn',

136

cli: 'yarn',

137

installCommand: ['yarn', ['install', '--immutable']],

138

installCommandNoLockfile: ['yarn', ['install']],

139

versionCommand: (input) => ['yarn', ['version', input]],

140

publishCommand: (args) => ['yarn', ['npm', 'publish', ...args]],

141

throwOnExternalRegistry: false

142

};

143

144

/**

145

* Bun package manager configuration

146

*/

147

const bunConfig: PackageManagerConfig = {

148

id: 'bun',

149

cli: 'bun',

150

installCommand: ['bun', ['install', '--frozen-lockfile']],

151

installCommandNoLockfile: ['bun', ['install', '--no-save']],

152

versionCommand: (input) => ['npm', ['version', input]], // Bun uses npm for versioning

153

throwOnExternalRegistry: false

154

};

155

```

156

157

**Usage Examples:**

158

159

```javascript

160

import { npmConfig, pnpmConfig, yarnConfig } from "np/source/package-manager/configs.js";

161

162

// Use specific package manager

163

const config = pnpmConfig;

164

const [cli, args] = config.versionCommand('patch');

165

console.log(`Version command: ${cli} ${args.join(' ')}`);

166

167

// Check external registry support

168

if (config.throwOnExternalRegistry && isExternalRegistry(packageJson)) {

169

throw new Error(`External registry not supported with ${config.id}`);

170

}

171

```

172

173

## Package Manager Detection

174

175

### Detection Priority

176

177

Package manager detection follows this priority:

178

179

1. **CLI flag**: `--package-manager` option

180

2. **Package.json field**: `packageManager` field specification

181

3. **Lockfile detection**: Based on existing lockfiles

182

4. **Default**: Falls back to npm

183

184

### PackageManager Field

185

186

Support for package.json `packageManager` field:

187

188

```json

189

{

190

"packageManager": "pnpm@8.5.0",

191

"packageManager": "yarn@3.4.1",

192

"packageManager": "npm@9.0.0"

193

}

194

```

195

196

### Lockfile Detection

197

198

Automatic detection based on lockfiles:

199

200

```javascript

201

// Lockfile to package manager mapping

202

const lockfileMap = {

203

'package-lock.json': 'npm',

204

'yarn.lock': 'yarn',

205

'pnpm-lock.yaml': 'pnpm',

206

'bun.lockb': 'bun'

207

};

208

209

// Detection logic

210

function detectFromLockfile(rootDirectory) {

211

for (const [lockfile, manager] of Object.entries(lockfileMap)) {

212

if (fs.existsSync(path.join(rootDirectory, lockfile))) {

213

return manager;

214

}

215

}

216

return 'npm'; // Default fallback

217

}

218

```

219

220

## Command Generation

221

222

### Install Commands

223

224

Different install behavior based on lockfile presence:

225

226

```javascript

227

// With lockfile (exact dependencies)

228

config.installCommand // ['pnpm', ['install', '--frozen-lockfile']]

229

230

// Without lockfile (resolve latest)

231

config.installCommandNoLockfile // ['pnpm', ['install', '--no-lockfile']]

232

```

233

234

### Version Commands

235

236

Version bump commands vary by package manager:

237

238

```javascript

239

// NPM

240

npmConfig.versionCommand('patch') // ['npm', ['version', 'patch']]

241

242

// Yarn Classic

243

yarnConfig.versionCommand('patch') // ['yarn', ['version', '--new-version', 'patch']]

244

245

// PNPM

246

pnpmConfig.versionCommand('patch') // ['pnpm', ['version', 'patch']]

247

248

// Bun (uses npm for versioning)

249

bunConfig.versionCommand('patch') // ['npm', ['version', 'patch']]

250

```

251

252

### Publish Commands

253

254

Publishing commands with custom handling:

255

256

```javascript

257

// Standard (npm, pnpm, yarn classic)

258

const args = ['publish', '--tag', 'beta'];

259

// Uses: npm publish --tag beta

260

261

// Yarn Berry (custom publish command)

262

yarnBerryConfig.publishCommand(args) // ['yarn', ['npm', 'publish', '--tag', 'beta']]

263

```

264

265

## Package Manager Specific Features

266

267

### NPM Features

268

269

- **Registry support**: Full external registry support

270

- **2FA integration**: Native 2FA support

271

- **Scoped packages**: Built-in scoped package handling

272

- **Dist-tags**: Full dist-tag management

273

274

### Yarn Features

275

276

#### Yarn Classic

277

- **Workspace support**: Monorepo workspace detection

278

- **Registry config**: Custom registry via .yarnrc

279

- **Version handling**: Different version command syntax

280

- **Publish workflow**: Standard npm publish compatibility

281

282

#### Yarn Berry

283

- **Plugin system**: Modern plugin architecture

284

- **Workspace protocols**: Advanced workspace linking

285

- **Custom publish**: Uses `yarn npm publish` command

286

- **Configuration**: .yarnrc.yml configuration format

287

288

### PNPM Features

289

290

- **External registry restriction**: Throws on external registries

291

- **Workspace support**: Built-in monorepo support

292

- **Strict lockfile**: Immutable lockfile enforcement

293

- **Space efficiency**: Content-addressable storage

294

295

### Bun Features

296

297

- **Fast installs**: Ultra-fast package installation

298

- **Version delegation**: Uses npm for version bumping

299

- **Binary lockfile**: Compact binary lockfile format

300

- **Runtime integration**: Built-in JavaScript runtime

301

302

## Workspace Support

303

304

### Monorepo Detection

305

306

Package managers handle monorepos differently:

307

308

```javascript

309

// Yarn workspaces

310

{

311

"workspaces": [

312

"packages/*",

313

"apps/*"

314

]

315

}

316

317

// PNPM workspaces (pnpm-workspace.yaml)

318

packages:

319

- 'packages/*'

320

- 'apps/*'

321

322

// NPM workspaces

323

{

324

"workspaces": [

325

"packages/*"

326

]

327

}

328

```

329

330

### Workspace Publishing

331

332

Publishing from workspace packages:

333

334

```javascript

335

// Detect if in workspace

336

const isWorkspace = packageJson.workspaces ||

337

fs.existsSync('pnpm-workspace.yaml');

338

339

// Adjust commands for workspace context

340

if (isWorkspace) {

341

// Use workspace-aware commands

342

const publishCmd = config.publishCommand || defaultPublishCommand;

343

}

344

```

345

346

## Configuration Integration

347

348

### CLI Integration

349

350

Package manager selection in CLI:

351

352

```bash

353

# Force specific package manager

354

np --package-manager pnpm

355

356

# Auto-detect from lockfile

357

np # Uses detected package manager

358

359

# Override packageManager field

360

np --package-manager yarn

361

```

362

363

### Programmatic Usage

364

365

```javascript

366

// Force specific package manager

367

const options = {

368

packageManager: 'pnpm'

369

};

370

371

// Let np auto-detect

372

const packageManager = getPackageManagerConfig(rootDirectory, packageJson);

373

374

// Use in publishing

375

await np('patch', {...options, packageManager}, context);

376

```

377

378

## Error Handling

379

380

### Package Manager Errors

381

382

**Detection Errors:**

383

- Multiple lockfiles present

384

- Unknown package manager specified

385

- Package manager not installed

386

387

**Command Errors:**

388

- Invalid command syntax

389

- Package manager version incompatibility

390

- Missing dependencies

391

392

**Registry Errors:**

393

- External registry not supported (pnpm)

394

- Authentication failures

395

- Network connectivity issues

396

397

### Error Recovery

398

399

Package manager error handling strategies:

400

401

```javascript

402

// Package manager not found

403

if (error.code === 'ENOENT') {

404

throw new Error(`Package manager '${config.id}' not found. Please install it first.`);

405

}

406

407

// External registry restriction

408

if (config.throwOnExternalRegistry && isExternalRegistry(package_)) {

409

throw new Error(`External registry not supported with ${config.id}`);

410

}

411

412

// Version mismatch

413

if (error.message.includes('version')) {

414

console.warn(`${config.id} version may be incompatible. Consider upgrading.`);

415

}

416

```

417

418

### Compatibility Matrix

419

420

Package manager compatibility with np features:

421

422

| Feature | npm | Yarn Classic | Yarn Berry | pnpm | Bun |

423

|---------|-----|-------------|------------|------|-----|

424

| External Registry ||||||

425

| 2FA Setup ||||||

426

| Workspaces ||||||

427

| Custom Publish ||||||

428

| Version Bumping ||||| ➡️ npm |

429

430

✅ Full support, ❌ Not supported, ➡️ Delegates to another tool