Skip to content

Commit 9d326bf

Browse files
fix: improve package manager detection logic
1 parent e082d66 commit 9d326bf

File tree

4 files changed

+60
-23
lines changed

4 files changed

+60
-23
lines changed

src/bin.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@ import * as kl from "kolorist";
33
import * as fs from "node:fs";
44
import * as path from "node:path";
55
import { parseArgs } from "node:util";
6-
import { install, remove, setupNpmRc } from "./commands";
7-
import { JsrPackage, findLockFile, setDebug } from "./utils";
8-
import { detectPackageManager } from "./pkg_manager";
6+
import { install, remove } from "./commands";
7+
import { JsrPackage, setDebug } from "./utils";
98

109
const args = process.argv.slice(2);
1110

src/commands.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as path from "node:path";
22
import * as fs from "node:fs";
3-
import { JsrPackage, findLockFile } from "./utils";
4-
import { detectPackageManager } from "./pkg_manager";
3+
import { JsrPackage } from "./utils";
4+
import { detectPackageManager, getProjectDir } from "./pkg_manager";
55

66
const JSR_NPMRC = `@jsr:registry=https://npm.jsr.io\n`;
77

@@ -27,16 +27,15 @@ export interface InstallOptions {
2727
}
2828

2929
export async function install(packages: JsrPackage[], options: InstallOptions) {
30-
const lockFilePath = await findLockFile(process.cwd());
31-
const projectDir = path.dirname(lockFilePath);
30+
const { projectDir, lockFilePath } = await getProjectDir(process.cwd());
3231
await setupNpmRc(projectDir);
3332

34-
const pkgManager = await detectPackageManager(lockFilePath);
33+
const pkgManager = await detectPackageManager(lockFilePath, projectDir);
3534
await pkgManager.install(packages, options);
3635
}
3736

3837
export async function remove(packages: JsrPackage[]) {
39-
const lockFilePath = await findLockFile(process.cwd());
40-
const pkgManager = await detectPackageManager(lockFilePath);
38+
const { projectDir, lockFilePath } = await getProjectDir(process.cwd());
39+
const pkgManager = await detectPackageManager(lockFilePath, projectDir);
4140
await pkgManager.remove(packages);
4241
}

src/pkg_manager.ts

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { promisify } from "node:util";
22
import * as path from "node:path";
33
import { InstallOptions } from "./commands";
4-
import { JsrPackage, logDebug } from "./utils";
4+
import { JsrPackage, findLockFile, findPackageJson, logDebug } from "./utils";
55
import * as cp from "node:child_process";
66

77
const execAsync = promisify(cp.exec);
@@ -84,17 +84,40 @@ class Pnpm implements PackageManager {
8484
}
8585
}
8686

87-
export function detectPackageManager(lockfilePath: string): PackageManager {
88-
const filename = path.basename(lockfilePath);
89-
const cwd = path.dirname(lockfilePath);
87+
export async function getProjectDir(cwd: string): Promise<{
88+
projectDir: string;
89+
lockFilePath: string | null;
90+
}> {
91+
const lockFilePath = await findLockFile(cwd);
92+
if (lockFilePath !== null) {
93+
const projectDir = path.dirname(lockFilePath);
94+
return { lockFilePath, projectDir };
95+
}
96+
97+
const pkgJsonPath = await findPackageJson(cwd);
98+
if (pkgJsonPath !== null) {
99+
const projectDir = path.dirname(pkgJsonPath);
100+
return { lockFilePath: null, projectDir };
101+
}
102+
103+
return { lockFilePath: null, projectDir: cwd };
104+
}
90105

91-
if (filename === "package-lock.json") {
92-
return new Npm(cwd);
93-
} else if (filename === "yarn.lock") {
94-
return new Yarn(cwd);
95-
} else if (filename === "pnpm-lock.yml") {
96-
return new Pnpm(cwd);
106+
export function detectPackageManager(
107+
lockFilePath: string | null,
108+
projectDir: string
109+
): PackageManager {
110+
if (lockFilePath !== null) {
111+
const filename = path.basename(lockFilePath);
112+
if (filename === "package-lock.json") {
113+
return new Npm(projectDir);
114+
} else if (filename === "yarn.lock") {
115+
return new Yarn(projectDir);
116+
} else if (filename === "pnpm-lock.yml") {
117+
return new Pnpm(projectDir);
118+
}
97119
}
98120

99-
throw new Error("Could not determine package manager");
121+
// Fall back to npm if no lockfile is present.
122+
return new Npm(projectDir);
100123
}

src/utils.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,23 @@ async function fileExists(file: string): Promise<boolean> {
5353
}
5454
}
5555

56-
export async function findLockFile(dir: string): Promise<string> {
56+
export async function findPackageJson(dir: string): Promise<string | null> {
57+
const file = path.join(dir, "package.json");
58+
59+
if (await fileExists(file)) {
60+
return file;
61+
}
62+
63+
const prev = dir;
64+
dir = path.dirname(dir);
65+
if (dir === prev) {
66+
return null;
67+
}
68+
69+
return findPackageJson(dir);
70+
}
71+
72+
export async function findLockFile(dir: string): Promise<string | null> {
5773
const npmLockfile = path.join(dir, "package-lock.json");
5874
if (await fileExists(npmLockfile)) {
5975
logDebug("Using npm package manager");
@@ -75,7 +91,7 @@ export async function findLockFile(dir: string): Promise<string> {
7591
const prev = dir;
7692
dir = path.dirname(dir);
7793
if (dir === prev) {
78-
throw new Error(`Could not find lockfile.`);
94+
return null;
7995
}
8096

8197
return findLockFile(dir);

0 commit comments

Comments
 (0)