feat: add corepack packageManager field support

This commit is contained in:
2026-03-09 15:42:53 +02:00
parent df2057230a
commit 96530745b3
2 changed files with 66 additions and 0 deletions

View File

@@ -206,6 +206,44 @@ func TestResolvePM_FromUserSettings(t *testing.T) {
}
}
// --- package.json packageManager field ---
func TestResolvePM_FromPackageJSON(t *testing.T) {
isolatePMDetectionToDefault(t)
ws := t.TempDir()
// No .vscode/settings.json, but package.json has packageManager
writeFile(t, filepath.Join(ws, "package.json"), `{"packageManager":"pnpm@8.15.0"}`)
tk := tasks.Task{Type: "npm", Script: "build"}
cmd, _, err := buildCmd(tk, ws, os.Environ())
if err != nil {
t.Fatalf("buildCmd err: %v", err)
}
if got, want := filepath.Base(cmd.Args[0]), "pnpm"; got != want {
t.Fatalf("exe=%q, want %q (packageManager field)", got, want)
}
}
func TestResolvePM_SettingsOverridesPackageJSON(t *testing.T) {
isolatePMDetectionToDefault(t)
ws := t.TempDir()
// VS Code settings say yarn, but package.json says pnpm
writeFile(t, filepath.Join(ws, ".vscode", "settings.json"), `{"npm.packageManager":"yarn"}`)
writeFile(t, filepath.Join(ws, "package.json"), `{"packageManager":"pnpm@8.15.0"}`)
tk := tasks.Task{Type: "npm", Script: "build"}
cmd, _, err := buildCmd(tk, ws, os.Environ())
if err != nil {
t.Fatalf("buildCmd err: %v", err)
}
// VS Code settings should win
if got, want := filepath.Base(cmd.Args[0]), "yarn"; got != want {
t.Fatalf("exe=%q, want %q (settings should override packageManager)", got, want)
}
}
// --- builtin detector ---
func TestIsNpmBuiltin(t *testing.T) {

View File

@@ -150,10 +150,38 @@ func normalizePM(v string) (string, bool) {
}
}
// detectPackageManagerFromPackageJSON reads the "packageManager" field from
// package.json (the corepack standard, e.g. "pnpm@8.15.0") and returns the
// executable name if recognized.
func detectPackageManagerFromPackageJSON(cwd string) (string, bool) {
path := filepath.Join(cwd, "package.json")
b, err := os.ReadFile(path)
if err != nil {
return "", false
}
var pkg struct {
PackageManager string `json:"packageManager"`
}
if err := json.Unmarshal(b, &pkg); err != nil {
return "", false
}
// The field value is "name@version", e.g. "pnpm@8.15.0" or just "pnpm".
name := strings.TrimSpace(pkg.PackageManager)
if i := strings.IndexByte(name, '@'); i > 0 {
name = name[:i]
}
return normalizePM(name)
}
func ResolvePackageManagerExecutable(cwd string, defaultExe string) string {
// 1) VS Code settings take highest priority (explicit user preference).
if exe, ok := detectPackageManagerFromSettings(cwd); ok {
return exe
}
// 2) package.json "packageManager" field (corepack standard).
if exe, ok := detectPackageManagerFromPackageJSON(cwd); ok {
return exe
}
if defaultExe == "" {
defaultExe = "npm"
}