Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement runtime package manager detection #164

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
import { consola } from "consola";
import { name, version, description } from "../package.json";
import { addDependency, installDependencies, removeDependency } from "./api";
import { detectPackageManager } from "./package-manager";
import {
detectPackageManager,
detectRuntimePackageManager,
} from "./package-manager";

Check warning on line 10 in src/cli.ts

View check run for this annotation

Codecov / codecov/patch

src/cli.ts#L10

Added line #L10 was not covered by tests

const operationArgs = {
cwd: {
Expand Down Expand Up @@ -94,6 +97,22 @@
},
});

const detectRunner = defineCommand({
meta: {
description: "Detect the current package runner using runtime checks",
},
run: () => {
const packageManager = detectRuntimePackageManager();
if (!packageManager) {
consola.error(`Cannot detect package runner`);
return process.exit(1);
}
consola.log(
`Detected package runner \`${packageManager.name}@${packageManager.version}\``,
);
},
});

Check warning on line 114 in src/cli.ts

View check run for this annotation

Codecov / codecov/patch

src/cli.ts#L100-L114

Added lines #L100 - L114 were not covered by tests

const main = defineCommand({
meta: {
name,
Expand All @@ -109,6 +128,7 @@
uninstall: remove,
un: remove,
detect,
"detect-runner": detectRunner,

Check warning on line 131 in src/cli.ts

View check run for this annotation

Codecov / codecov/patch

src/cli.ts#L131

Added line #L131 was not covered by tests
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice if we simplify to have nypm detect that displays both detection results.

},
});

Expand Down
52 changes: 46 additions & 6 deletions src/package-manager.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { existsSync } from "node:fs";
import { readFile } from "node:fs/promises";
import { join, resolve } from "pathe";
import { env, process } from "std-env";
import { findup } from "./_utils";
import type { PackageManager } from "./types";

Expand All @@ -27,7 +28,12 @@
includeParentDirs?: boolean;

/**
* Weather to ignore argv[1] to detect script
* Weather to ignore runtime checks to detect package manager or script runner
*/
ignoreRuntime?: boolean;

/**
* Whether to ignore argv[1] to detect package manager or script runner, implied if `ignoreRuntimeChecks` is `true`
*/
ignoreArgv?: boolean;
};
Expand All @@ -37,30 +43,35 @@
name: "npm",
command: "npm",
lockFile: "package-lock.json",
packageRunner: "npx",
},
{
name: "pnpm",
command: "pnpm",
lockFile: "pnpm-lock.yaml",
files: ["pnpm-workspace.yaml"],
packageRunner: "pnpm dlx",
},
{
name: "bun",
command: "bun",
lockFile: ["bun.lockb", "bun.lock"],
packageRunner: "bunx",
},
{
name: "yarn",
command: "yarn",
majorVersion: "1",
lockFile: "yarn.lock",
packageRunner: undefined,
},
{
name: "yarn",
command: "yarn",
majorVersion: "3",
lockFile: "yarn.lock",
files: [".yarnrc.yml"],
packageRunner: "yarn dlx",
},
{
name: "deno",
Expand Down Expand Up @@ -138,10 +149,41 @@
},
);

if (!detected && !options.ignoreArgv) {
// 3. Try to detect based on dlx/exec command
if (!detected && !options.ignoreRuntime) {
return detectRuntimePackageManager(options);
}

Check warning on line 154 in src/package-manager.ts

View check run for this annotation

Codecov / codecov/patch

src/package-manager.ts#L153-L154

Added lines #L153 - L154 were not covered by tests

return detected;
}

export function detectRuntimePackageManager(
options: DetectPackageManagerOptions = {},
): PackageManager | undefined {
const userAgent = env["npm_config_user_agent"];

Check warning on line 162 in src/package-manager.ts

View check run for this annotation

Codecov / codecov/patch

src/package-manager.ts#L160-L162

Added lines #L160 - L162 were not covered by tests

const engine = userAgent?.split(" ")?.[0] ?? "";

Check warning on line 164 in src/package-manager.ts

View check run for this annotation

Codecov / codecov/patch

src/package-manager.ts#L164

Added line #L164 was not covered by tests

const [name, version = "0.0.0"] = engine.split("/");

Check warning on line 166 in src/package-manager.ts

View check run for this annotation

Codecov / codecov/patch

src/package-manager.ts#L166

Added line #L166 was not covered by tests

if (name) {
const majorVersion = version.split(".")[0];
const packageManager =
packageManagers.find(
(pm) => pm.name === name && pm.majorVersion === majorVersion,
) || packageManagers.find((pm) => pm.name === name);
if (packageManager) {
return {
...packageManager,
command: name,
version,
majorVersion,
};
}
}
if (!options.ignoreArgv) {

Check warning on line 183 in src/package-manager.ts

View check run for this annotation

Codecov / codecov/patch

src/package-manager.ts#L168-L183

Added lines #L168 - L183 were not covered by tests
// Fallback to detecting based on argv
// https://github.com/unjs/nypm/issues/116
const scriptArg = process.argv[1];
const scriptArg = process.argv?.[1];

Check warning on line 186 in src/package-manager.ts

View check run for this annotation

Codecov / codecov/patch

src/package-manager.ts#L186

Added line #L186 was not covered by tests
if (scriptArg) {
for (const packageManager of packageManagers) {
// Check /.[name] or /[name] in path
Expand All @@ -152,6 +194,4 @@
}
}
}

return detected;
}
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export type PackageManagerName = "npm" | "yarn" | "pnpm" | "bun" | "deno";
export type PackageManager = {
name: PackageManagerName;
command: string;
packageRunner?: string;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might make it an array. It is a map of known args => package runner

version?: string;
majorVersion?: string;
lockFile?: string | string[];
Expand Down
Loading