-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpackage-manager.ts
More file actions
130 lines (119 loc) · 3.34 KB
/
package-manager.ts
File metadata and controls
130 lines (119 loc) · 3.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/**
* @fileoverview Package manager environment detection.
* Provides utilities to detect which package manager (npm/pnpm/yarn/bun) is running.
*/
import process from 'node:process'
import { getEnvValue } from './rewire'
/**
* Package manager type detected from environment.
*/
export type PackageManagerType = 'npm' | 'pnpm' | 'yarn' | 'bun' | null
/**
* Detect which package manager is currently running based on environment variables.
* Checks npm_config_user_agent which all package managers set.
*
* Detection priority:
* 1. npm_config_user_agent (most reliable, set by all package managers)
* 2. Binary path analysis (fallback for non-standard environments)
*
* @returns The detected package manager or null if unable to determine
*
* @example
* ```typescript
* // During: npm install
* detectPackageManager() // 'npm'
*
* // During: pnpm install
* detectPackageManager() // 'pnpm'
*
* // During: yarn install
* detectPackageManager() // 'yarn'
*
* // Outside package manager context
* detectPackageManager() // null
* ```
*/
/*@__NO_SIDE_EFFECTS__*/
export function detectPackageManager(): PackageManagerType {
const userAgent = getPackageManagerUserAgent()
if (userAgent) {
// User agent format: "pnpm/8.15.1 npm/? node/v20.11.0 darwin arm64"
// Extract the first part before the slash.
const match = userAgent.match(/^(npm|pnpm|yarn|bun)\//)
if (match) {
return match[1] as PackageManagerType
}
}
// Fallback: Check binary path patterns.
const argv0 = process.argv[0]
if (argv0) {
if (argv0.includes('/pnpm/') || argv0.includes('\\pnpm\\')) {
return 'pnpm'
}
if (
argv0.includes('/yarn/') ||
argv0.includes('\\yarn\\') ||
argv0.includes('/.yarn/') ||
argv0.includes('\\.yarn\\')
) {
return 'yarn'
}
if (argv0.includes('/bun/') || argv0.includes('\\bun\\')) {
return 'bun'
}
// If in node_modules but no other match, assume npm.
if (
argv0.includes('/node_modules/') ||
argv0.includes('\\node_modules\\')
) {
return 'npm'
}
}
return null
}
/**
* Get the package manager name and version from user agent.
*
* @returns Object with name and version, or null if not available
* @example
* ```typescript
* getPackageManagerInfo()
* // { name: 'pnpm', version: '8.15.1' }
* ```
*/
/*@__NO_SIDE_EFFECTS__*/
export function getPackageManagerInfo(): {
name: string
version: string
} | null {
const userAgent = getPackageManagerUserAgent()
if (!userAgent) {
return null
}
// Parse "pnpm/8.15.1 npm/? node/v20.11.0 darwin arm64".
const match = userAgent.match(/^([^/]+)\/([^\s]+)/)
if (match?.[1] && match[2]) {
return {
name: match[1],
version: match[2],
}
}
return null
}
/**
* Get the package manager user agent from environment.
* Package managers set npm_config_user_agent with format: "npm/8.19.2 node/v18.12.0 darwin arm64"
*
* @returns The user agent string or undefined
* @example
* ```typescript
* getPackageManagerUserAgent()
* // npm: "npm/10.2.4 node/v20.11.0 darwin arm64 workspaces/false"
* // pnpm: "pnpm/8.15.1 npm/? node/v20.11.0 darwin arm64"
* // yarn: "yarn/1.22.19 npm/? node/v20.11.0 darwin arm64"
* ```
*/
/*@__NO_SIDE_EFFECTS__*/
export function getPackageManagerUserAgent(): string | undefined {
return getEnvValue('npm_config_user_agent')
}