From 9bee93dd72cdf64353c1d8eb601ca8622ebac93e Mon Sep 17 00:00:00 2001 From: Ezira Ashenafi Date: Fri, 22 Nov 2024 10:38:32 +0300 Subject: [PATCH 1/2] feat: implement runtime package manager detection --- src/cli.ts | 19 ++++++++++++++- src/package-manager.ts | 53 ++++++++++++++++++++++++++++++++++++------ src/types.ts | 1 + 3 files changed, 65 insertions(+), 8 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index 0ba8094..bd1c310 100755 --- a/src/cli.ts +++ b/src/cli.ts @@ -4,7 +4,7 @@ import { resolve } from "pathe"; 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"; const operationArgs = { cwd: { @@ -94,6 +94,22 @@ const detect = defineCommand({ }, }); +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}\``, + ); + } +}) + const main = defineCommand({ meta: { name, @@ -109,6 +125,7 @@ const main = defineCommand({ uninstall: remove, un: remove, detect, + 'detect-runner': detectRunner }, }); diff --git a/src/package-manager.ts b/src/package-manager.ts index 7f3a6cf..c851ceb 100644 --- a/src/package-manager.ts +++ b/src/package-manager.ts @@ -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"; @@ -27,8 +28,13 @@ export type DetectPackageManagerOptions = { 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; }; @@ -37,23 +43,27 @@ export const packageManagers: PackageManager[] = [ 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", @@ -61,6 +71,7 @@ export const packageManagers: PackageManager[] = [ majorVersion: "3", lockFile: "yarn.lock", files: [".yarnrc.yml"], + packageRunner: "yarn dlx" }, ] as const; @@ -127,10 +138,39 @@ export async function detectPackageManager( }, ); - if (!detected && !options.ignoreArgv) { - // 3. Try to detect based on dlx/exec command + if (!detected && !options.ignoreRuntime) { + return detectRuntimePackageManager(options) + } + + return detected; +} + +export function detectRuntimePackageManager(options: DetectPackageManagerOptions = {}): PackageManager | undefined { + const userAgent = env['npm_config_user_agent'] + + const engine = userAgent?.split(' ')?.[0] ?? '' + + const [name, version = '0.0.0'] = engine.split('/') + + 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) { + // Fallback to detecting based on argv // https://github.com/unjs/nypm/issues/116 - const scriptArg = process.argv[1]; + const scriptArg = process.argv?.[1]; if (scriptArg) { for (const packageManager of packageManagers) { // Check /.[name] or /[name] in path @@ -142,5 +182,4 @@ export async function detectPackageManager( } } - return detected; -} +} \ No newline at end of file diff --git a/src/types.ts b/src/types.ts index b0441a9..8e6a605 100644 --- a/src/types.ts +++ b/src/types.ts @@ -3,6 +3,7 @@ export type PackageManagerName = "npm" | "yarn" | "pnpm" | "bun"; export type PackageManager = { name: PackageManagerName; command: string; + packageRunner?: string; version?: string; majorVersion?: string; lockFile?: string | string[]; From 4659623a92429f4c871a830e1949f25ca75a47a1 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Fri, 22 Nov 2024 10:04:24 +0000 Subject: [PATCH 2/2] chore: apply automated lint fixes --- src/cli.ts | 13 ++++++++----- src/package-manager.ts | 31 ++++++++++++++++--------------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index bd1c310..90ecb2e 100755 --- a/src/cli.ts +++ b/src/cli.ts @@ -4,7 +4,10 @@ import { resolve } from "pathe"; import { consola } from "consola"; import { name, version, description } from "../package.json"; import { addDependency, installDependencies, removeDependency } from "./api"; -import { detectPackageManager, detectRuntimePackageManager } from "./package-manager"; +import { + detectPackageManager, + detectRuntimePackageManager, +} from "./package-manager"; const operationArgs = { cwd: { @@ -99,7 +102,7 @@ const detectRunner = defineCommand({ description: "Detect the current package runner using runtime checks", }, run: () => { - const packageManager = detectRuntimePackageManager() + const packageManager = detectRuntimePackageManager(); if (!packageManager) { consola.error(`Cannot detect package runner`); return process.exit(1); @@ -107,8 +110,8 @@ const detectRunner = defineCommand({ consola.log( `Detected package runner \`${packageManager.name}@${packageManager.version}\``, ); - } -}) + }, +}); const main = defineCommand({ meta: { @@ -125,7 +128,7 @@ const main = defineCommand({ uninstall: remove, un: remove, detect, - 'detect-runner': detectRunner + "detect-runner": detectRunner, }, }); diff --git a/src/package-manager.ts b/src/package-manager.ts index c851ceb..24be3c1 100644 --- a/src/package-manager.ts +++ b/src/package-manager.ts @@ -29,12 +29,12 @@ export type DetectPackageManagerOptions = { /** * 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` - */ + * Whether to ignore argv[1] to detect package manager or script runner, implied if `ignoreRuntimeChecks` is `true` + */ ignoreArgv?: boolean; }; @@ -43,27 +43,27 @@ export const packageManagers: PackageManager[] = [ name: "npm", command: "npm", lockFile: "package-lock.json", - packageRunner: "npx" + packageRunner: "npx", }, { name: "pnpm", command: "pnpm", lockFile: "pnpm-lock.yaml", files: ["pnpm-workspace.yaml"], - packageRunner: "pnpm dlx" + packageRunner: "pnpm dlx", }, { name: "bun", command: "bun", lockFile: ["bun.lockb", "bun.lock"], - packageRunner: "bunx" + packageRunner: "bunx", }, { name: "yarn", command: "yarn", majorVersion: "1", lockFile: "yarn.lock", - packageRunner: undefined + packageRunner: undefined, }, { name: "yarn", @@ -71,7 +71,7 @@ export const packageManagers: PackageManager[] = [ majorVersion: "3", lockFile: "yarn.lock", files: [".yarnrc.yml"], - packageRunner: "yarn dlx" + packageRunner: "yarn dlx", }, ] as const; @@ -139,18 +139,20 @@ export async function detectPackageManager( ); if (!detected && !options.ignoreRuntime) { - return detectRuntimePackageManager(options) + return detectRuntimePackageManager(options); } return detected; } -export function detectRuntimePackageManager(options: DetectPackageManagerOptions = {}): PackageManager | undefined { - const userAgent = env['npm_config_user_agent'] +export function detectRuntimePackageManager( + options: DetectPackageManagerOptions = {}, +): PackageManager | undefined { + const userAgent = env["npm_config_user_agent"]; - const engine = userAgent?.split(' ')?.[0] ?? '' + const engine = userAgent?.split(" ")?.[0] ?? ""; - const [name, version = '0.0.0'] = engine.split('/') + const [name, version = "0.0.0"] = engine.split("/"); if (name) { const majorVersion = version.split(".")[0]; @@ -181,5 +183,4 @@ export function detectRuntimePackageManager(options: DetectPackageManagerOptions } } } - -} \ No newline at end of file +}