+75
-71
@@ -0,53 +1,55 @@ | ||
| //#region src/types.d.ts | ||
| type PackageManagerName = "npm" | "yarn" | "pnpm" | "bun" | "deno"; | ||
| type PackageManager = { | ||
| name: PackageManagerName; | ||
| command: string; | ||
| version?: string; | ||
| buildMeta?: string; | ||
| majorVersion?: string; | ||
| lockFile?: string | string[]; | ||
| files?: string[]; | ||
| name: PackageManagerName; | ||
| command: string; | ||
| version?: string; | ||
| buildMeta?: string; | ||
| majorVersion?: string; | ||
| lockFile?: string | string[]; | ||
| files?: string[]; | ||
| }; | ||
| type OperationOptions = { | ||
| cwd?: string; | ||
| env?: Record<string, string>; | ||
| silent?: boolean; | ||
| packageManager?: PackageManager | PackageManagerName; | ||
| installPeerDependencies?: boolean; | ||
| dev?: boolean; | ||
| workspace?: boolean | string; | ||
| global?: boolean; | ||
| /** Do not execute actual command */ | ||
| dry?: boolean; | ||
| cwd?: string; | ||
| env?: Record<string, string>; | ||
| silent?: boolean; | ||
| packageManager?: PackageManager | PackageManagerName; | ||
| installPeerDependencies?: boolean; | ||
| dev?: boolean; | ||
| workspace?: boolean | string; | ||
| global?: boolean; | ||
| corepack?: boolean; /** Do not execute actual command */ | ||
| dry?: boolean; | ||
| }; | ||
| type OperationResult = { | ||
| exec?: { | ||
| command: string; | ||
| args: string[]; | ||
| }; | ||
| exec?: { | ||
| command: string; | ||
| args: string[]; | ||
| }; | ||
| }; | ||
| //#endregion | ||
| //#region src/package-manager.d.ts | ||
| type DetectPackageManagerOptions = { | ||
| /** | ||
| * Whether to ignore the lock file | ||
| * | ||
| * @default false | ||
| */ | ||
| ignoreLockFile?: boolean; | ||
| /** | ||
| * Whether to ignore the package.json file | ||
| * | ||
| * @default false | ||
| */ | ||
| ignorePackageJSON?: boolean; | ||
| /** | ||
| * Whether to include parent directories | ||
| * | ||
| * @default false | ||
| */ | ||
| includeParentDirs?: boolean; | ||
| /** | ||
| * Weather to ignore argv[1] to detect script | ||
| */ | ||
| ignoreArgv?: boolean; | ||
| /** | ||
| * Whether to ignore the lock file | ||
| * | ||
| * @default false | ||
| */ | ||
| ignoreLockFile?: boolean; | ||
| /** | ||
| * Whether to ignore the package.json file | ||
| * | ||
| * @default false | ||
| */ | ||
| ignorePackageJSON?: boolean; | ||
| /** | ||
| * Whether to include parent directories | ||
| * | ||
| * @default false | ||
| */ | ||
| includeParentDirs?: boolean; | ||
| /** | ||
| * Weather to ignore argv[1] to detect script | ||
| */ | ||
| ignoreArgv?: boolean; | ||
| }; | ||
@@ -63,5 +65,6 @@ declare const packageManagers: PackageManager[]; | ||
| declare function detectPackageManager(cwd: string, options?: DetectPackageManagerOptions): Promise<(PackageManager & { | ||
| warnings?: string[]; | ||
| warnings?: string[]; | ||
| }) | undefined>; | ||
| //#endregion | ||
| //#region src/api.d.ts | ||
| /** | ||
@@ -76,4 +79,5 @@ * Installs project dependencies. | ||
| */ | ||
| declare function installDependencies(options?: Pick<OperationOptions, "cwd" | "silent" | "packageManager" | "dry"> & { | ||
| frozenLockFile?: boolean; | ||
| declare function installDependencies(options?: Pick<OperationOptions, "cwd" | "silent" | "packageManager" | "dry" | "corepack"> & { | ||
| frozenLockFile?: boolean; | ||
| ignoreWorkspace?: boolean; | ||
| }): Promise<OperationResult>; | ||
@@ -138,4 +142,4 @@ /** | ||
| */ | ||
| declare function dedupeDependencies(options?: Pick<OperationOptions, "cwd" | "silent" | "packageManager" | "dry"> & { | ||
| recreateLockfile?: boolean; | ||
| declare function dedupeDependencies(options?: Pick<OperationOptions, "cwd" | "silent" | "packageManager" | "dry" | "corepack"> & { | ||
| recreateLockfile?: boolean; | ||
| }): Promise<OperationResult>; | ||
@@ -153,4 +157,4 @@ /** | ||
| */ | ||
| declare function runScript(name: string, options?: Pick<OperationOptions, "cwd" | "env" | "silent" | "packageManager" | "dry"> & { | ||
| args?: string[]; | ||
| declare function runScript(name: string, options?: Pick<OperationOptions, "cwd" | "env" | "silent" | "packageManager" | "dry" | "corepack"> & { | ||
| args?: string[]; | ||
| }): Promise<OperationResult>; | ||
@@ -170,8 +174,9 @@ /** | ||
| */ | ||
| declare function dlx(name: string, options?: Pick<OperationOptions, "cwd" | "env" | "silent" | "packageManager" | "dry"> & { | ||
| args?: string[]; | ||
| short?: boolean; | ||
| packages?: string[]; | ||
| declare function dlx(name: string, options?: Pick<OperationOptions, "cwd" | "env" | "silent" | "packageManager" | "dry" | "corepack"> & { | ||
| args?: string[]; | ||
| short?: boolean; | ||
| packages?: string[]; | ||
| }): Promise<OperationResult>; | ||
| //#endregion | ||
| //#region src/cmd.d.ts | ||
| /** | ||
@@ -181,4 +186,4 @@ * Get the command to install dependencies with the package manager. | ||
| declare function installDependenciesCommand(packageManager: PackageManagerName, options?: { | ||
| short?: boolean; | ||
| frozenLockFile?: boolean; | ||
| short?: boolean; | ||
| frozenLockFile?: boolean; | ||
| }): string; | ||
@@ -189,7 +194,7 @@ /** | ||
| declare function addDependencyCommand(packageManager: PackageManagerName, name: string | string[], options?: { | ||
| dev?: boolean; | ||
| global?: boolean; | ||
| yarnBerry?: boolean; | ||
| workspace?: boolean | string; | ||
| short?: boolean; | ||
| dev?: boolean; | ||
| global?: boolean; | ||
| yarnBerry?: boolean; | ||
| workspace?: boolean | string; | ||
| short?: boolean; | ||
| }): string; | ||
@@ -200,3 +205,3 @@ /** | ||
| declare function runScriptCommand(packageManager: PackageManagerName, name: string, options?: { | ||
| args?: string[]; | ||
| args?: string[]; | ||
| }): string; | ||
@@ -207,8 +212,7 @@ /** | ||
| declare function dlxCommand(packageManager: PackageManagerName, name: string, options?: { | ||
| args?: string[]; | ||
| short?: boolean; | ||
| packages?: string[]; | ||
| args?: string[]; | ||
| short?: boolean; | ||
| packages?: string[]; | ||
| }): string; | ||
| export { addDependency, addDependencyCommand, addDevDependency, dedupeDependencies, detectPackageManager, dlx, dlxCommand, ensureDependencyInstalled, installDependencies, installDependenciesCommand, packageManagers, removeDependency, runScript, runScriptCommand }; | ||
| export type { DetectPackageManagerOptions, OperationOptions, OperationResult, PackageManager, PackageManagerName }; | ||
| //#endregion | ||
| export { DetectPackageManagerOptions, OperationOptions, OperationResult, PackageManager, PackageManagerName, addDependency, addDependencyCommand, addDevDependency, dedupeDependencies, detectPackageManager, dlx, dlxCommand, ensureDependencyInstalled, installDependencies, installDependenciesCommand, packageManagers, removeDependency, runScript, runScriptCommand }; |
+541
-7
@@ -1,7 +0,541 @@ | ||
| export { a as addDependency, j as addDependencyCommand, b as addDevDependency, c as dedupeDependencies, d as detectPackageManager, g as dlx, l as dlxCommand, e as ensureDependencyInstalled, i as installDependencies, h as installDependenciesCommand, p as packageManagers, r as removeDependency, f as runScript, k as runScriptCommand } from './shared/nypm.CLjaS_sz.mjs'; | ||
| import 'pkg-types'; | ||
| import 'node:module'; | ||
| import 'pathe'; | ||
| import 'tinyexec'; | ||
| import 'node:fs'; | ||
| import 'node:fs/promises'; | ||
| import { createRequire } from "node:module"; | ||
| import * as fs from "node:fs"; | ||
| import { existsSync } from "node:fs"; | ||
| import { readFile } from "node:fs/promises"; | ||
| import { join, normalize, resolve } from "pathe"; | ||
| import { x } from "tinyexec"; | ||
| import { join as join$1 } from "node:path"; | ||
| //#region src/_utils.ts | ||
| async function findup(cwd, match, options = {}) { | ||
| const segments = normalize(cwd).split("/"); | ||
| while (segments.length > 0) { | ||
| const result = await match(segments.join("/") || "/"); | ||
| if (result || !options.includeParentDirs) return result; | ||
| segments.pop(); | ||
| } | ||
| } | ||
| async function readPackageJSON(cwd) { | ||
| return findup(cwd, (p) => { | ||
| const pkgPath = join$1(p, "package.json"); | ||
| if (existsSync(pkgPath)) return readFile(pkgPath, "utf8").then((data) => JSON.parse(data)); | ||
| }); | ||
| } | ||
| function cached(fn) { | ||
| let v; | ||
| return () => { | ||
| if (v === void 0) v = fn().then((r) => { | ||
| v = r; | ||
| return v; | ||
| }); | ||
| return v; | ||
| }; | ||
| } | ||
| const hasCorepack = cached(async () => { | ||
| if (globalThis.process?.versions?.webcontainer) return false; | ||
| try { | ||
| const { exitCode } = await x("corepack", ["--version"]); | ||
| return exitCode === 0; | ||
| } catch { | ||
| return false; | ||
| } | ||
| }); | ||
| async function executeCommand(command, args, options = {}) { | ||
| const xArgs = command !== "npm" && command !== "bun" && command !== "deno" && options.corepack !== false && await hasCorepack() ? ["corepack", [command, ...args]] : [command, args]; | ||
| const { exitCode, stdout, stderr } = await x(xArgs[0], xArgs[1], { nodeOptions: { | ||
| cwd: resolve(options.cwd || process.cwd()), | ||
| env: options.env, | ||
| stdio: options.silent ? "pipe" : "inherit" | ||
| } }); | ||
| if (exitCode !== 0) throw new Error(`\`${xArgs.flat().join(" ")}\` failed.${options.silent ? [ | ||
| "", | ||
| stdout, | ||
| stderr | ||
| ].join("\n") : ""}`); | ||
| } | ||
| const NO_PACKAGE_MANAGER_DETECTED_ERROR_MSG = "No package manager auto-detected."; | ||
| async function resolveOperationOptions(options = {}) { | ||
| const cwd = options.cwd || process.cwd(); | ||
| const env = { | ||
| ...process.env, | ||
| ...options.env | ||
| }; | ||
| const packageManager = (typeof options.packageManager === "string" ? packageManagers.find((pm) => pm.name === options.packageManager) : options.packageManager) || await detectPackageManager(options.cwd || process.cwd()); | ||
| if (!packageManager) throw new Error(NO_PACKAGE_MANAGER_DETECTED_ERROR_MSG); | ||
| return { | ||
| cwd, | ||
| env, | ||
| silent: options.silent ?? false, | ||
| packageManager, | ||
| dev: options.dev ?? false, | ||
| workspace: options.workspace, | ||
| global: options.global ?? false, | ||
| dry: options.dry ?? false, | ||
| corepack: options.corepack ?? true | ||
| }; | ||
| } | ||
| function getWorkspaceArgs(options) { | ||
| if (!options.workspace) return []; | ||
| const workspacePkg = typeof options.workspace === "string" && options.workspace !== "" ? options.workspace : void 0; | ||
| if (options.packageManager.name === "pnpm") return workspacePkg ? ["--filter", workspacePkg] : ["--workspace-root"]; | ||
| if (options.packageManager.name === "npm") return workspacePkg ? ["-w", workspacePkg] : ["--workspaces"]; | ||
| if (options.packageManager.name === "yarn") if (!options.packageManager.majorVersion || options.packageManager.majorVersion === "1") return workspacePkg ? ["--cwd", workspacePkg] : ["-W"]; | ||
| else return workspacePkg ? ["workspace", workspacePkg] : []; | ||
| return []; | ||
| } | ||
| function getWorkspaceArgs2(options) { | ||
| if (!options.workspace) return []; | ||
| const workspacePkg = typeof options.workspace === "string" && options.workspace !== "" ? options.workspace : void 0; | ||
| if (options.packageManager === "pnpm") return workspacePkg ? ["--filter", workspacePkg] : ["--workspace-root"]; | ||
| if (options.packageManager === "npm") return workspacePkg ? ["-w", workspacePkg] : ["--workspaces"]; | ||
| if (options.packageManager === "yarn") if (options.yarnBerry) return workspacePkg ? ["workspace", workspacePkg] : []; | ||
| else return workspacePkg ? ["--cwd", workspacePkg] : ["-W"]; | ||
| return []; | ||
| } | ||
| function fmtCommand(args) { | ||
| return args.filter(Boolean).map((arg, i) => i > 0 && arg.includes(" ") ? `"${arg}"` : arg).join(" "); | ||
| } | ||
| function doesDependencyExist(name, options) { | ||
| const require = createRequire(options.cwd.endsWith("/") ? options.cwd : options.cwd + "/"); | ||
| try { | ||
| return require.resolve(name).startsWith(options.cwd); | ||
| } catch { | ||
| return false; | ||
| } | ||
| } | ||
| function parsePackageManagerField(packageManager) { | ||
| const [name, _version] = (packageManager || "").split("@"); | ||
| const [version, buildMeta] = _version?.split("+") || []; | ||
| if (name && name !== "-" && /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(name)) return { | ||
| name, | ||
| version, | ||
| buildMeta | ||
| }; | ||
| const sanitized = (name || "").replace(/\W+/g, ""); | ||
| return { | ||
| name: sanitized, | ||
| version, | ||
| buildMeta, | ||
| warnings: [`Abnormal characters found in \`packageManager\` field, sanitizing from \`${name}\` to \`${sanitized}\``] | ||
| }; | ||
| } | ||
| //#endregion | ||
| //#region src/package-manager.ts | ||
| const packageManagers = [ | ||
| { | ||
| name: "npm", | ||
| command: "npm", | ||
| lockFile: "package-lock.json" | ||
| }, | ||
| { | ||
| name: "pnpm", | ||
| command: "pnpm", | ||
| lockFile: "pnpm-lock.yaml", | ||
| files: ["pnpm-workspace.yaml"] | ||
| }, | ||
| { | ||
| name: "bun", | ||
| command: "bun", | ||
| lockFile: ["bun.lockb", "bun.lock"] | ||
| }, | ||
| { | ||
| name: "yarn", | ||
| command: "yarn", | ||
| lockFile: "yarn.lock", | ||
| files: [".yarnrc.yml"] | ||
| }, | ||
| { | ||
| name: "deno", | ||
| command: "deno", | ||
| lockFile: "deno.lock", | ||
| files: ["deno.json"] | ||
| } | ||
| ]; | ||
| /** | ||
| * Detect the package manager used in a directory (and up) by checking various sources: | ||
| * | ||
| * 1. Use `packageManager` field from package.json | ||
| * | ||
| * 2. Known lock files and other files | ||
| */ | ||
| async function detectPackageManager(cwd, options = {}) { | ||
| const detected = await findup(resolve(cwd || "."), async (path) => { | ||
| if (!options.ignorePackageJSON) { | ||
| const packageJSONPath = join(path, "package.json"); | ||
| if (existsSync(packageJSONPath)) { | ||
| const packageJSON = JSON.parse(await readFile(packageJSONPath, "utf8")); | ||
| if (packageJSON?.packageManager) { | ||
| const { name, version = "0.0.0", buildMeta, warnings } = parsePackageManagerField(packageJSON.packageManager); | ||
| if (name) { | ||
| const majorVersion = version.split(".")[0]; | ||
| const packageManager = packageManagers.find((pm) => pm.name === name && pm.majorVersion === majorVersion) || packageManagers.find((pm) => pm.name === name); | ||
| return { | ||
| name, | ||
| command: name, | ||
| version, | ||
| majorVersion, | ||
| buildMeta, | ||
| warnings, | ||
| files: packageManager?.files, | ||
| lockFile: packageManager?.lockFile | ||
| }; | ||
| } | ||
| } | ||
| } | ||
| if (existsSync(join(path, "deno.json"))) return packageManagers.find((pm) => pm.name === "deno"); | ||
| } | ||
| if (!options.ignoreLockFile) { | ||
| for (const packageManager of packageManagers) if ([packageManager.lockFile, packageManager.files].flat().filter(Boolean).some((file) => existsSync(resolve(path, file)))) return { ...packageManager }; | ||
| } | ||
| }, { includeParentDirs: options.includeParentDirs ?? true }); | ||
| if (!detected && !options.ignoreArgv) { | ||
| const scriptArg = process.argv[1]; | ||
| if (scriptArg) { | ||
| for (const packageManager of packageManagers) if ((/* @__PURE__ */ new RegExp(`[/\\\\]\\.?${packageManager.command}`)).test(scriptArg)) return packageManager; | ||
| } | ||
| } | ||
| return detected; | ||
| } | ||
| //#endregion | ||
| //#region src/cmd.ts | ||
| /** | ||
| * Get the command to install dependencies with the package manager. | ||
| */ | ||
| function installDependenciesCommand(packageManager, options = {}) { | ||
| const installCmd = options.short ? "i" : "install"; | ||
| const pmToFrozenLockfileInstallCommand = { | ||
| npm: ["ci"], | ||
| yarn: [installCmd, "--immutable"], | ||
| bun: [installCmd, "--frozen-lockfile"], | ||
| pnpm: [installCmd, "--frozen-lockfile"], | ||
| deno: [installCmd, "--frozen"] | ||
| }; | ||
| return fmtCommand([packageManager, ...options.frozenLockFile ? pmToFrozenLockfileInstallCommand[packageManager] : [installCmd]]); | ||
| } | ||
| /** | ||
| * Get the command to add a dependency with the package manager. | ||
| */ | ||
| function addDependencyCommand(packageManager, name, options = {}) { | ||
| const names = Array.isArray(name) ? name : [name]; | ||
| if (packageManager === "deno") { | ||
| for (let i = 0; i < names.length; i++) if (!/^(npm|jsr|file):.+$/.test(names[i])) names[i] = `npm:${names[i]}`; | ||
| } | ||
| return fmtCommand([packageManager, ...(packageManager === "yarn" ? [ | ||
| ...getWorkspaceArgs2({ | ||
| packageManager, | ||
| ...options | ||
| }), | ||
| options.global && !options.yarnBerry ? "global" : "", | ||
| "add", | ||
| options.dev ? options.short ? "-D" : "--dev" : "", | ||
| ...names | ||
| ] : [ | ||
| packageManager === "npm" ? options.short ? "i" : "install" : "add", | ||
| ...getWorkspaceArgs2({ | ||
| packageManager, | ||
| ...options | ||
| }), | ||
| options.dev ? options.short ? "-D" : "--dev" : "", | ||
| options.global ? "-g" : "", | ||
| ...names | ||
| ]).filter(Boolean)]); | ||
| } | ||
| /** | ||
| * Get the command to run a script with the package manager. | ||
| */ | ||
| function runScriptCommand(packageManager, name, options = {}) { | ||
| return fmtCommand([packageManager, ...[ | ||
| packageManager === "deno" ? "task" : "run", | ||
| name, | ||
| ...options.args || [] | ||
| ]]); | ||
| } | ||
| /** | ||
| * Get the command to download and execute a package with the package manager. | ||
| */ | ||
| function dlxCommand(packageManager, name, options = {}) { | ||
| const command = { | ||
| npm: options.short ? "npx" : "npm exec", | ||
| yarn: "yarn dlx", | ||
| pnpm: options.short ? "pnpx" : "pnpm dlx", | ||
| bun: options.short ? "bunx" : "bun x", | ||
| deno: "deno run -A" | ||
| }[packageManager]; | ||
| let packages = options.packages || []; | ||
| if (packageManager === "deno") { | ||
| if (!name.startsWith("npm:")) name = `npm:${name}`; | ||
| packages = packages.map((pkg) => pkg.startsWith("npm:") ? pkg : `npm:${pkg}`); | ||
| } | ||
| const packageArgs = []; | ||
| if (packages.length > 0 && packageManager !== "deno") { | ||
| const packageFlag = options.short && /^npm|yarn$/.test(packageManager) ? "-p" : "--package"; | ||
| for (const pkg of packages) packageArgs.push(`${packageFlag}=${pkg}`); | ||
| } | ||
| const argSep = packageManager === "npm" && !options.short ? "--" : ""; | ||
| return fmtCommand([ | ||
| command, | ||
| ...packageArgs, | ||
| name, | ||
| argSep, | ||
| ...options.args || [] | ||
| ]); | ||
| } | ||
| //#endregion | ||
| //#region src/api.ts | ||
| /** | ||
| * Installs project dependencies. | ||
| * | ||
| * @param options - Options to pass to the API call. | ||
| * @param options.cwd - The directory to run the command in. | ||
| * @param options.silent - Whether to run the command in silent mode. | ||
| * @param options.packageManager - The package manager info to use (auto-detected). | ||
| * @param options.frozenLockFile - Whether to install dependencies with frozen lock file. | ||
| */ | ||
| async function installDependencies(options = {}) { | ||
| const resolvedOptions = await resolveOperationOptions(options); | ||
| const commandArgs = options.frozenLockFile ? { | ||
| npm: ["ci"], | ||
| yarn: ["install", "--immutable"], | ||
| bun: ["install", "--frozen-lockfile"], | ||
| pnpm: ["install", "--frozen-lockfile"], | ||
| deno: ["install", "--frozen"] | ||
| }[resolvedOptions.packageManager.name] : ["install"]; | ||
| if (options.ignoreWorkspace && resolvedOptions.packageManager.name === "pnpm") commandArgs.push("--ignore-workspace"); | ||
| if (!resolvedOptions.dry) await executeCommand(resolvedOptions.packageManager.command, commandArgs, { | ||
| cwd: resolvedOptions.cwd, | ||
| silent: resolvedOptions.silent, | ||
| corepack: resolvedOptions.corepack | ||
| }); | ||
| return { exec: { | ||
| command: resolvedOptions.packageManager.command, | ||
| args: commandArgs | ||
| } }; | ||
| } | ||
| /** | ||
| * Adds dependency to the project. | ||
| * | ||
| * @param name - Name of the dependency to add. | ||
| * @param options - Options to pass to the API call. | ||
| * @param options.cwd - The directory to run the command in. | ||
| * @param options.silent - Whether to run the command in silent mode. | ||
| * @param options.packageManager - The package manager info to use (auto-detected). | ||
| * @param options.dev - Whether to add the dependency as dev dependency. | ||
| * @param options.workspace - The name of the workspace to use. | ||
| * @param options.global - Whether to run the command in global mode. | ||
| */ | ||
| async function addDependency(name, options = {}) { | ||
| const resolvedOptions = await resolveOperationOptions(options); | ||
| const names = Array.isArray(name) ? name : [name]; | ||
| if (resolvedOptions.packageManager.name === "deno") { | ||
| for (let i = 0; i < names.length; i++) if (!/^(npm|jsr|file):.+$/.test(names[i] || "")) names[i] = `npm:${names[i]}`; | ||
| } | ||
| if (names.length === 0) return {}; | ||
| const args = (resolvedOptions.packageManager.name === "yarn" ? [ | ||
| ...getWorkspaceArgs(resolvedOptions), | ||
| resolvedOptions.global && resolvedOptions.packageManager.majorVersion === "1" ? "global" : "", | ||
| "add", | ||
| resolvedOptions.dev ? "-D" : "", | ||
| ...names | ||
| ] : [ | ||
| resolvedOptions.packageManager.name === "npm" ? "install" : "add", | ||
| ...getWorkspaceArgs(resolvedOptions), | ||
| resolvedOptions.dev ? "-D" : "", | ||
| resolvedOptions.global ? "-g" : "", | ||
| ...names | ||
| ]).filter(Boolean); | ||
| if (!resolvedOptions.dry) await executeCommand(resolvedOptions.packageManager.command, args, { | ||
| cwd: resolvedOptions.cwd, | ||
| silent: resolvedOptions.silent, | ||
| corepack: resolvedOptions.corepack | ||
| }); | ||
| if (!resolvedOptions.dry && options.installPeerDependencies) { | ||
| const existingPkg = await readPackageJSON(resolvedOptions.cwd); | ||
| const peerDeps = []; | ||
| const peerDevDeps = []; | ||
| for (const _name of names) { | ||
| const pkgName = _name.match(/^(.[^@]+)/)?.[0]; | ||
| const pkg = createRequire(join$1(resolvedOptions.cwd, "/_.js"))(`${pkgName}/package.json`); | ||
| if (!pkg.peerDependencies || pkg.name !== pkgName) continue; | ||
| for (const [peerDependency, version] of Object.entries(pkg.peerDependencies)) { | ||
| if (pkg.peerDependenciesMeta?.[peerDependency]?.optional) continue; | ||
| if (existingPkg?.dependencies?.[peerDependency] || existingPkg?.devDependencies?.[peerDependency]) continue; | ||
| (pkg.peerDependenciesMeta?.[peerDependency]?.dev ? peerDevDeps : peerDeps).push(`${peerDependency}@${version}`); | ||
| } | ||
| } | ||
| if (peerDeps.length > 0) await addDependency(peerDeps, { ...resolvedOptions }); | ||
| if (peerDevDeps.length > 0) await addDevDependency(peerDevDeps, { ...resolvedOptions }); | ||
| } | ||
| return { exec: { | ||
| command: resolvedOptions.packageManager.command, | ||
| args | ||
| } }; | ||
| } | ||
| /** | ||
| * Adds dev dependency to the project. | ||
| * | ||
| * @param name - Name of the dev dependency to add. | ||
| * @param options - Options to pass to the API call. | ||
| * @param options.cwd - The directory to run the command in. | ||
| * @param options.silent - Whether to run the command in silent mode. | ||
| * @param options.packageManager - The package manager info to use (auto-detected). | ||
| * @param options.workspace - The name of the workspace to use. | ||
| * @param options.global - Whether to run the command in global mode. | ||
| * | ||
| */ | ||
| async function addDevDependency(name, options = {}) { | ||
| return await addDependency(name, { | ||
| ...options, | ||
| dev: true | ||
| }); | ||
| } | ||
| /** | ||
| * Removes dependency from the project. | ||
| * | ||
| * @param name - Name of the dependency to remove. | ||
| * @param options - Options to pass to the API call. | ||
| * @param options.cwd - The directory to run the command in. | ||
| * @param options.silent - Whether to run the command in silent mode. | ||
| * @param options.packageManager - The package manager info to use (auto-detected). | ||
| * @param options.dev - Whether to remove dev dependency. | ||
| * @param options.workspace - The name of the workspace to use. | ||
| * @param options.global - Whether to run the command in global mode. | ||
| */ | ||
| async function removeDependency(name, options = {}) { | ||
| const resolvedOptions = await resolveOperationOptions(options); | ||
| const names = Array.isArray(name) ? name : [name]; | ||
| if (names.length === 0) return {}; | ||
| const args = (resolvedOptions.packageManager.name === "yarn" ? [ | ||
| resolvedOptions.global && resolvedOptions.packageManager.majorVersion === "1" ? "global" : "", | ||
| ...getWorkspaceArgs(resolvedOptions), | ||
| "remove", | ||
| resolvedOptions.dev ? "-D" : "", | ||
| resolvedOptions.global ? "-g" : "", | ||
| ...names | ||
| ] : [ | ||
| resolvedOptions.packageManager.name === "npm" ? "uninstall" : "remove", | ||
| ...getWorkspaceArgs(resolvedOptions), | ||
| resolvedOptions.dev ? "-D" : "", | ||
| resolvedOptions.global ? "-g" : "", | ||
| ...names | ||
| ]).filter(Boolean); | ||
| if (!resolvedOptions.dry) await executeCommand(resolvedOptions.packageManager.command, args, { | ||
| cwd: resolvedOptions.cwd, | ||
| silent: resolvedOptions.silent, | ||
| corepack: resolvedOptions.corepack | ||
| }); | ||
| return { exec: { | ||
| command: resolvedOptions.packageManager.command, | ||
| args | ||
| } }; | ||
| } | ||
| /** | ||
| * Ensures dependency is installed. | ||
| * | ||
| * @param name - Name of the dependency. | ||
| * @param options - Options to pass to the API call. | ||
| * @param options.cwd - The directory to run the command in. | ||
| * @param options.dev - Whether to install as dev dependency (if not already installed). | ||
| * @param options.workspace - The name of the workspace to install dependency in (if not already installed). | ||
| */ | ||
| async function ensureDependencyInstalled(name, options = {}) { | ||
| const resolvedOptions = await resolveOperationOptions(options); | ||
| if (doesDependencyExist(name, resolvedOptions)) return true; | ||
| await addDependency(name, resolvedOptions); | ||
| } | ||
| /** | ||
| * Dedupe dependencies in the project. | ||
| * | ||
| * @param options - Options to pass to the API call. | ||
| * @param options.cwd - The directory to run the command in. | ||
| * @param options.packageManager - The package manager info to use (auto-detected). | ||
| * @param options.silent - Whether to run the command in silent mode. | ||
| * @param options.recreateLockfile - Whether to recreate the lockfile instead of deduping. | ||
| */ | ||
| async function dedupeDependencies(options = {}) { | ||
| const resolvedOptions = await resolveOperationOptions(options); | ||
| const isSupported = !["bun", "deno"].includes(resolvedOptions.packageManager.name); | ||
| if (options.recreateLockfile ?? !isSupported) { | ||
| const lockfiles = Array.isArray(resolvedOptions.packageManager.lockFile) ? resolvedOptions.packageManager.lockFile : [resolvedOptions.packageManager.lockFile]; | ||
| for (const lockfile of lockfiles) if (lockfile) fs.rmSync(resolve(resolvedOptions.cwd, lockfile), { force: true }); | ||
| return await installDependencies(resolvedOptions); | ||
| } | ||
| if (isSupported) { | ||
| const isyarnv1 = resolvedOptions.packageManager.name === "yarn" && resolvedOptions.packageManager.majorVersion === "1"; | ||
| if (!resolvedOptions.dry) await executeCommand(resolvedOptions.packageManager.command, [isyarnv1 ? "install" : "dedupe"], { | ||
| cwd: resolvedOptions.cwd, | ||
| silent: resolvedOptions.silent, | ||
| corepack: resolvedOptions.corepack | ||
| }); | ||
| return { exec: { | ||
| command: resolvedOptions.packageManager.command, | ||
| args: [isyarnv1 ? "install" : "dedupe"] | ||
| } }; | ||
| } | ||
| throw new Error(`Deduplication is not supported for ${resolvedOptions.packageManager.name}`); | ||
| } | ||
| /** | ||
| * Runs a script defined in the package.json file. | ||
| * | ||
| * @param name - Name of the script to run. | ||
| * @param options - Options to pass to the API call. | ||
| * @param options.cwd - The directory to run the command in. | ||
| * @param options.env - Additional environment variables to set for the script execution. | ||
| * @param options.silent - Whether to run the command in silent mode. | ||
| * @param options.packageManager - The package manager info to use (auto-detected). | ||
| * @param options.args - Additional arguments to pass to the script. | ||
| */ | ||
| async function runScript(name, options = {}) { | ||
| const resolvedOptions = await resolveOperationOptions(options); | ||
| const args = [ | ||
| resolvedOptions.packageManager.name === "deno" ? "task" : "run", | ||
| name, | ||
| ...options.args || [] | ||
| ]; | ||
| if (!resolvedOptions.dry) await executeCommand(resolvedOptions.packageManager.command, args, { | ||
| cwd: resolvedOptions.cwd, | ||
| env: resolvedOptions.env, | ||
| silent: resolvedOptions.silent, | ||
| corepack: resolvedOptions.corepack | ||
| }); | ||
| return { exec: { | ||
| command: resolvedOptions.packageManager.command, | ||
| args | ||
| } }; | ||
| } | ||
| /** | ||
| * Download and execute a package with the package manager. | ||
| * | ||
| * @param name - Name of the package to download and execute. | ||
| * @param options - Options to pass to the API call. | ||
| * @param options.cwd - The directory to run the command in. | ||
| * @param options.env - Additional environment variables to set for the command execution. | ||
| * @param options.silent - Whether to run the command in silent mode. | ||
| * @param options.packageManager - The package manager info to use (auto-detected). | ||
| * @param options.args - The arguments to pass to the command. | ||
| * @param options.short - Whether to use the short version of the command (e.g. pnpx instead of pnpm dlx). | ||
| * @param options.packages - The packages to pass to the command (e.g. npx --package=<package1> --package=<package2> <command>). | ||
| */ | ||
| async function dlx(name, options = {}) { | ||
| const resolvedOptions = await resolveOperationOptions(options); | ||
| const [command, ...args] = dlxCommand(resolvedOptions.packageManager.name, name, { | ||
| args: options.args, | ||
| short: options.short, | ||
| packages: options.packages | ||
| }).split(" "); | ||
| if (!resolvedOptions.dry) await executeCommand(command, args, { | ||
| cwd: resolvedOptions.cwd, | ||
| env: resolvedOptions.env, | ||
| silent: resolvedOptions.silent, | ||
| corepack: resolvedOptions.corepack | ||
| }); | ||
| return { exec: { | ||
| command, | ||
| args | ||
| } }; | ||
| } | ||
| //#endregion | ||
| export { addDependency, addDependencyCommand, addDevDependency, dedupeDependencies, detectPackageManager, dlx, dlxCommand, ensureDependencyInstalled, installDependencies, installDependenciesCommand, packageManagers, removeDependency, runScript, runScriptCommand }; |
+22
-24
| { | ||
| "name": "nypm", | ||
| "version": "0.6.2", | ||
| "version": "0.6.3", | ||
| "description": "Unified Package Manager for Node.js", | ||
@@ -10,10 +10,9 @@ "repository": "unjs/nypm", | ||
| "exports": { | ||
| "types": "./dist/index.d.mts", | ||
| "default": "./dist/index.mjs" | ||
| ".": "./dist/index.mjs" | ||
| }, | ||
| "module": "./dist/index.mjs", | ||
| "types": "./dist/index.d.mts", | ||
| "bin": { | ||
| "nypm": "./dist/cli.mjs" | ||
| }, | ||
| "module": "./dist/index.mjs", | ||
| "types": "./dist/index.d.ts", | ||
| "files": [ | ||
@@ -23,36 +22,35 @@ "dist" | ||
| "dependencies": { | ||
| "citty": "^0.1.6", | ||
| "consola": "^3.4.2", | ||
| "citty": "^0.2.0", | ||
| "pathe": "^2.0.3", | ||
| "pkg-types": "^2.3.0", | ||
| "tinyexec": "^1.0.1" | ||
| "tinyexec": "^1.0.2" | ||
| }, | ||
| "devDependencies": { | ||
| "@types/node": "^24.4.0", | ||
| "@vitest/coverage-v8": "^3.2.4", | ||
| "@types/node": "^25.0.9", | ||
| "@typescript/native-preview": "7.0.0-dev.20260120.1", | ||
| "@vitest/coverage-v8": "^4.0.17", | ||
| "automd": "^0.4.2", | ||
| "changelogen": "^0.6.2", | ||
| "eslint": "^9.35.0", | ||
| "eslint-config-unjs": "^0.5.0", | ||
| "jiti": "^2.5.1", | ||
| "prettier": "^3.6.2", | ||
| "std-env": "^3.9.0", | ||
| "typescript": "^5.9.2", | ||
| "ufo": "^1.6.1", | ||
| "unbuild": "^3.6.1", | ||
| "vitest": "^3.2.4" | ||
| "eslint": "^9.39.2", | ||
| "eslint-config-unjs": "^0.6.2", | ||
| "obuild": "^0.4.18", | ||
| "pkg-types": "^2.3.0", | ||
| "prettier": "^3.8.0", | ||
| "std-env": "^3.10.0", | ||
| "typescript": "^5.9.3", | ||
| "ufo": "^1.6.3", | ||
| "vitest": "^4.0.17" | ||
| }, | ||
| "engines": { | ||
| "node": "^14.16.0 || >=16.10.0" | ||
| "node": ">=18" | ||
| }, | ||
| "scripts": { | ||
| "build": "automd && unbuild", | ||
| "build": "automd && obuild", | ||
| "dev": "vitest dev", | ||
| "lint": "eslint . && prettier -c src test", | ||
| "lint:fix": "eslint . --fix && prettier -w src test", | ||
| "nypm": "jiti src/cli.ts", | ||
| "nypm": "node ./src/cli.ts", | ||
| "release": "pnpm test && pnpm build && changelogen --release --push && pnpm publish", | ||
| "test": "pnpm lint && pnpm test:types && vitest run --coverage", | ||
| "test:types": "tsc --noEmit" | ||
| "test:types": "tsgo --noEmit" | ||
| } | ||
| } |
-176
| #!/usr/bin/env node | ||
| import { defineCommand, runMain } from 'citty'; | ||
| import { resolve } from 'pathe'; | ||
| import { consola } from 'consola'; | ||
| import { a as addDependency, i as installDependencies, r as removeDependency, d as detectPackageManager, c as dedupeDependencies, f as runScript } from './shared/nypm.CLjaS_sz.mjs'; | ||
| import 'pkg-types'; | ||
| import 'node:module'; | ||
| import 'tinyexec'; | ||
| import 'node:fs'; | ||
| import 'node:fs/promises'; | ||
| const name = "nypm"; | ||
| const version = "0.6.2"; | ||
| const description = "Unified Package Manager for Node.js"; | ||
| const operationArgs = { | ||
| cwd: { | ||
| type: "string", | ||
| description: "Current working directory" | ||
| }, | ||
| workspace: { | ||
| type: "boolean", | ||
| description: "Add to workspace" | ||
| }, | ||
| silent: { | ||
| type: "boolean", | ||
| description: "Run in silent mode" | ||
| }, | ||
| dry: { | ||
| type: "boolean", | ||
| description: "Run in dry run mode (does not execute commands)" | ||
| } | ||
| }; | ||
| const install = defineCommand({ | ||
| meta: { | ||
| description: "Install dependencies" | ||
| }, | ||
| args: { | ||
| ...operationArgs, | ||
| name: { | ||
| type: "positional", | ||
| description: "Dependency name", | ||
| required: false | ||
| }, | ||
| dev: { | ||
| type: "boolean", | ||
| alias: "D", | ||
| description: "Add as dev dependency" | ||
| }, | ||
| global: { | ||
| type: "boolean", | ||
| alias: "g", | ||
| description: "Add globally" | ||
| }, | ||
| "frozen-lockfile": { | ||
| type: "boolean", | ||
| description: "Install dependencies with frozen lock file" | ||
| } | ||
| }, | ||
| run: async ({ args }) => { | ||
| const result = await (args._.length > 0 ? addDependency(args._, args) : installDependencies(args)); | ||
| handleRes(result, args); | ||
| } | ||
| }); | ||
| const remove = defineCommand({ | ||
| meta: { | ||
| description: "Remove dependencies" | ||
| }, | ||
| args: { | ||
| name: { | ||
| type: "positional", | ||
| description: "Dependency name", | ||
| required: true | ||
| }, | ||
| ...operationArgs | ||
| }, | ||
| run: async ({ args }) => { | ||
| const result = await removeDependency(args._, args); | ||
| handleRes(result, args); | ||
| } | ||
| }); | ||
| const detect = defineCommand({ | ||
| meta: { | ||
| description: "Detect the current package manager" | ||
| }, | ||
| args: { | ||
| cwd: { | ||
| type: "string", | ||
| description: "Current working directory" | ||
| } | ||
| }, | ||
| run: async ({ args }) => { | ||
| const cwd = resolve(args.cwd || "."); | ||
| const packageManager = await detectPackageManager(cwd); | ||
| if (packageManager?.warnings) { | ||
| for (const warning of packageManager.warnings) { | ||
| consola.warn(warning); | ||
| } | ||
| } | ||
| if (!packageManager) { | ||
| consola.error(`Cannot detect package manager in \`${cwd}\``); | ||
| return process.exit(1); | ||
| } | ||
| consola.log( | ||
| `Detected package manager in \`${cwd}\`: \`${packageManager.name}@${packageManager.version}\`` | ||
| ); | ||
| } | ||
| }); | ||
| const dedupe = defineCommand({ | ||
| meta: { | ||
| description: "Dedupe dependencies" | ||
| }, | ||
| args: { | ||
| cwd: { | ||
| type: "string", | ||
| description: "Current working directory" | ||
| }, | ||
| silent: { | ||
| type: "boolean", | ||
| description: "Run in silent mode" | ||
| }, | ||
| recreateLockFile: { | ||
| type: "boolean", | ||
| description: "Recreate lock file" | ||
| } | ||
| }, | ||
| run: async ({ args }) => { | ||
| const result = await dedupeDependencies(args); | ||
| handleRes(result, args); | ||
| } | ||
| }); | ||
| const run = defineCommand({ | ||
| meta: { | ||
| description: "Run script" | ||
| }, | ||
| args: { | ||
| name: { | ||
| type: "positional", | ||
| description: "Script name", | ||
| required: true | ||
| }, | ||
| ...operationArgs | ||
| }, | ||
| run: async ({ args }) => { | ||
| const result = await runScript(args.name, { | ||
| ...args, | ||
| args: args._.slice(1) | ||
| }); | ||
| handleRes(result, args); | ||
| } | ||
| }); | ||
| const main = defineCommand({ | ||
| meta: { | ||
| name, | ||
| version, | ||
| description | ||
| }, | ||
| subCommands: { | ||
| install, | ||
| i: install, | ||
| add: install, | ||
| remove, | ||
| rm: remove, | ||
| uninstall: remove, | ||
| un: remove, | ||
| detect, | ||
| dedupe, | ||
| run | ||
| } | ||
| }); | ||
| runMain(main); | ||
| function handleRes(result, args) { | ||
| if (args.dry && !args.silent) { | ||
| consola.log(`${result.exec?.command} ${result.exec?.args.join(" ")}`); | ||
| } | ||
| } |
| import { readPackageJSON } from 'pkg-types'; | ||
| import { createRequire } from 'node:module'; | ||
| import { resolve, normalize, join } from 'pathe'; | ||
| import { x } from 'tinyexec'; | ||
| import * as fs from 'node:fs'; | ||
| import { existsSync } from 'node:fs'; | ||
| import { readFile } from 'node:fs/promises'; | ||
| async function findup(cwd, match, options = {}) { | ||
| const segments = normalize(cwd).split("/"); | ||
| while (segments.length > 0) { | ||
| const path = segments.join("/") || "/"; | ||
| const result = await match(path); | ||
| if (result || !options.includeParentDirs) { | ||
| return result; | ||
| } | ||
| segments.pop(); | ||
| } | ||
| } | ||
| function cached(fn) { | ||
| let v; | ||
| return () => { | ||
| if (v === void 0) { | ||
| v = fn().then((r) => { | ||
| v = r; | ||
| return v; | ||
| }); | ||
| } | ||
| return v; | ||
| }; | ||
| } | ||
| const hasCorepack = cached(async () => { | ||
| if (globalThis.process?.versions?.webcontainer) { | ||
| return false; | ||
| } | ||
| try { | ||
| const { exitCode } = await x("corepack", ["--version"]); | ||
| return exitCode === 0; | ||
| } catch { | ||
| return false; | ||
| } | ||
| }); | ||
| async function executeCommand(command, args, options = {}) { | ||
| const xArgs = command === "npm" || command === "bun" || command === "deno" || !await hasCorepack() ? [command, args] : ["corepack", [command, ...args]]; | ||
| const { exitCode, stdout, stderr } = await x(xArgs[0], xArgs[1], { | ||
| nodeOptions: { | ||
| cwd: resolve(options.cwd || process.cwd()), | ||
| env: options.env, | ||
| stdio: options.silent ? "pipe" : "inherit" | ||
| } | ||
| }); | ||
| if (exitCode !== 0) { | ||
| throw new Error( | ||
| `\`${xArgs.flat().join(" ")}\` failed.${options.silent ? ["", stdout, stderr].join("\n") : ""}` | ||
| ); | ||
| } | ||
| } | ||
| const NO_PACKAGE_MANAGER_DETECTED_ERROR_MSG = "No package manager auto-detected."; | ||
| async function resolveOperationOptions(options = {}) { | ||
| const cwd = options.cwd || process.cwd(); | ||
| const env = { ...process.env, ...options.env }; | ||
| const packageManager = (typeof options.packageManager === "string" ? packageManagers.find((pm) => pm.name === options.packageManager) : options.packageManager) || await detectPackageManager(options.cwd || process.cwd()); | ||
| if (!packageManager) { | ||
| throw new Error(NO_PACKAGE_MANAGER_DETECTED_ERROR_MSG); | ||
| } | ||
| return { | ||
| cwd, | ||
| env, | ||
| silent: options.silent ?? false, | ||
| packageManager, | ||
| dev: options.dev ?? false, | ||
| workspace: options.workspace, | ||
| global: options.global ?? false, | ||
| dry: options.dry ?? false | ||
| }; | ||
| } | ||
| function getWorkspaceArgs(options) { | ||
| if (!options.workspace) { | ||
| return []; | ||
| } | ||
| const workspacePkg = typeof options.workspace === "string" && options.workspace !== "" ? options.workspace : void 0; | ||
| if (options.packageManager.name === "pnpm") { | ||
| return workspacePkg ? ["--filter", workspacePkg] : ["--workspace-root"]; | ||
| } | ||
| if (options.packageManager.name === "npm") { | ||
| return workspacePkg ? ["-w", workspacePkg] : ["--workspaces"]; | ||
| } | ||
| if (options.packageManager.name === "yarn") { | ||
| if (!options.packageManager.majorVersion || options.packageManager.majorVersion === "1") { | ||
| return workspacePkg ? ["--cwd", workspacePkg] : ["-W"]; | ||
| } else { | ||
| return workspacePkg ? ["workspace", workspacePkg] : []; | ||
| } | ||
| } | ||
| return []; | ||
| } | ||
| function getWorkspaceArgs2(options) { | ||
| if (!options.workspace) { | ||
| return []; | ||
| } | ||
| const workspacePkg = typeof options.workspace === "string" && options.workspace !== "" ? options.workspace : void 0; | ||
| if (options.packageManager === "pnpm") { | ||
| return workspacePkg ? ["--filter", workspacePkg] : ["--workspace-root"]; | ||
| } | ||
| if (options.packageManager === "npm") { | ||
| return workspacePkg ? ["-w", workspacePkg] : ["--workspaces"]; | ||
| } | ||
| if (options.packageManager === "yarn") { | ||
| if (options.yarnBerry) { | ||
| return workspacePkg ? ["workspace", workspacePkg] : []; | ||
| } else { | ||
| return workspacePkg ? ["--cwd", workspacePkg] : ["-W"]; | ||
| } | ||
| } | ||
| return []; | ||
| } | ||
| function fmtCommand(args) { | ||
| return args.filter(Boolean).map((arg, i) => i > 0 && arg.includes(" ") ? `"${arg}"` : arg).join(" "); | ||
| } | ||
| function doesDependencyExist(name, options) { | ||
| const require = createRequire( | ||
| options.cwd.endsWith("/") ? options.cwd : options.cwd + "/" | ||
| ); | ||
| try { | ||
| const resolvedPath = require.resolve(name); | ||
| return resolvedPath.startsWith(options.cwd); | ||
| } catch { | ||
| return false; | ||
| } | ||
| } | ||
| function parsePackageManagerField(packageManager) { | ||
| const [name, _version] = (packageManager || "").split("@"); | ||
| const [version, buildMeta] = _version?.split("+") || []; | ||
| if (name && name !== "-" && /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(name)) { | ||
| return { name, version, buildMeta }; | ||
| } | ||
| const sanitized = name.replace(/\W+/g, ""); | ||
| const warnings = [ | ||
| `Abnormal characters found in \`packageManager\` field, sanitizing from \`${name}\` to \`${sanitized}\`` | ||
| ]; | ||
| return { | ||
| name: sanitized, | ||
| version, | ||
| buildMeta, | ||
| warnings | ||
| }; | ||
| } | ||
| const packageManagers = [ | ||
| { | ||
| name: "npm", | ||
| command: "npm", | ||
| lockFile: "package-lock.json" | ||
| }, | ||
| { | ||
| name: "pnpm", | ||
| command: "pnpm", | ||
| lockFile: "pnpm-lock.yaml", | ||
| files: ["pnpm-workspace.yaml"] | ||
| }, | ||
| { | ||
| name: "bun", | ||
| command: "bun", | ||
| lockFile: ["bun.lockb", "bun.lock"] | ||
| }, | ||
| { | ||
| name: "yarn", | ||
| command: "yarn", | ||
| lockFile: "yarn.lock", | ||
| files: [".yarnrc.yml"] | ||
| }, | ||
| { | ||
| name: "deno", | ||
| command: "deno", | ||
| lockFile: "deno.lock", | ||
| files: ["deno.json"] | ||
| } | ||
| ]; | ||
| async function detectPackageManager(cwd, options = {}) { | ||
| const detected = await findup( | ||
| resolve(cwd || "."), | ||
| async (path) => { | ||
| if (!options.ignorePackageJSON) { | ||
| const packageJSONPath = join(path, "package.json"); | ||
| if (existsSync(packageJSONPath)) { | ||
| const packageJSON = JSON.parse( | ||
| await readFile(packageJSONPath, "utf8") | ||
| ); | ||
| if (packageJSON?.packageManager) { | ||
| const { | ||
| name, | ||
| version = "0.0.0", | ||
| buildMeta, | ||
| warnings | ||
| } = parsePackageManagerField(packageJSON.packageManager); | ||
| if (name) { | ||
| const majorVersion = version.split(".")[0]; | ||
| const packageManager = packageManagers.find( | ||
| (pm) => pm.name === name && pm.majorVersion === majorVersion | ||
| ) || packageManagers.find((pm) => pm.name === name); | ||
| return { | ||
| name, | ||
| command: name, | ||
| version, | ||
| majorVersion, | ||
| buildMeta, | ||
| warnings, | ||
| files: packageManager?.files, | ||
| lockFile: packageManager?.lockFile | ||
| }; | ||
| } | ||
| } | ||
| } | ||
| const denoJSONPath = join(path, "deno.json"); | ||
| if (existsSync(denoJSONPath)) { | ||
| return packageManagers.find((pm) => pm.name === "deno"); | ||
| } | ||
| } | ||
| if (!options.ignoreLockFile) { | ||
| for (const packageManager of packageManagers) { | ||
| const detectionsFiles = [ | ||
| packageManager.lockFile, | ||
| packageManager.files | ||
| ].flat().filter(Boolean); | ||
| if (detectionsFiles.some((file) => existsSync(resolve(path, file)))) { | ||
| return { | ||
| ...packageManager | ||
| }; | ||
| } | ||
| } | ||
| } | ||
| }, | ||
| { | ||
| includeParentDirs: options.includeParentDirs ?? true | ||
| } | ||
| ); | ||
| if (!detected && !options.ignoreArgv) { | ||
| const scriptArg = process.argv[1]; | ||
| if (scriptArg) { | ||
| for (const packageManager of packageManagers) { | ||
| const re = new RegExp(`[/\\\\]\\.?${packageManager.command}`); | ||
| if (re.test(scriptArg)) { | ||
| return packageManager; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| return detected; | ||
| } | ||
| function installDependenciesCommand(packageManager, options = {}) { | ||
| const installCmd = options.short ? "i" : "install"; | ||
| const pmToFrozenLockfileInstallCommand = { | ||
| npm: ["ci"], | ||
| yarn: [installCmd, "--immutable"], | ||
| bun: [installCmd, "--frozen-lockfile"], | ||
| pnpm: [installCmd, "--frozen-lockfile"], | ||
| deno: [installCmd, "--frozen"] | ||
| }; | ||
| const commandArgs = options.frozenLockFile ? pmToFrozenLockfileInstallCommand[packageManager] : [installCmd]; | ||
| return fmtCommand([packageManager, ...commandArgs]); | ||
| } | ||
| function addDependencyCommand(packageManager, name, options = {}) { | ||
| const names = Array.isArray(name) ? name : [name]; | ||
| if (packageManager === "deno") { | ||
| for (let i = 0; i < names.length; i++) { | ||
| if (!/^(npm|jsr|file):.+$/.test(names[i])) { | ||
| names[i] = `npm:${names[i]}`; | ||
| } | ||
| } | ||
| } | ||
| const args = (packageManager === "yarn" ? [ | ||
| ...getWorkspaceArgs2({ packageManager, ...options }), | ||
| // Global is not supported in berry: yarnpkg/berry#821 | ||
| options.global && !options.yarnBerry ? "global" : "", | ||
| "add", | ||
| options.dev ? options.short ? "-D" : "--dev" : "", | ||
| ...names | ||
| ] : [ | ||
| packageManager === "npm" ? options.short ? "i" : "install" : "add", | ||
| ...getWorkspaceArgs2({ packageManager, ...options }), | ||
| options.dev ? options.short ? "-D" : "--dev" : "", | ||
| options.global ? "-g" : "", | ||
| ...names | ||
| ]).filter(Boolean); | ||
| return fmtCommand([packageManager, ...args]); | ||
| } | ||
| function runScriptCommand(packageManager, name, options = {}) { | ||
| const args = [ | ||
| packageManager === "deno" ? "task" : "run", | ||
| name, | ||
| ...options.args || [] | ||
| ]; | ||
| return fmtCommand([packageManager, ...args]); | ||
| } | ||
| function dlxCommand(packageManager, name, options = {}) { | ||
| const pmToDlxCommand = { | ||
| npm: options.short ? "npx" : "npm exec", | ||
| yarn: "yarn dlx", | ||
| pnpm: options.short ? "pnpx" : "pnpm dlx", | ||
| bun: options.short ? "bunx" : "bun x", | ||
| deno: "deno run -A" | ||
| }; | ||
| const command = pmToDlxCommand[packageManager]; | ||
| let packages = options.packages || []; | ||
| if (packageManager === "deno") { | ||
| if (!name.startsWith("npm:")) { | ||
| name = `npm:${name}`; | ||
| } | ||
| packages = packages.map( | ||
| (pkg) => pkg.startsWith("npm:") ? pkg : `npm:${pkg}` | ||
| ); | ||
| } | ||
| const packageArgs = []; | ||
| if (packages.length > 0 && packageManager !== "deno") { | ||
| const packageFlag = options.short && /^npm|yarn$/.test(packageManager) ? "-p" : "--package"; | ||
| for (const pkg of packages) { | ||
| packageArgs.push(`${packageFlag}=${pkg}`); | ||
| } | ||
| } | ||
| const argSep = packageManager === "npm" && !options.short ? "--" : ""; | ||
| return fmtCommand([ | ||
| command, | ||
| ...packageArgs, | ||
| name, | ||
| argSep, | ||
| ...options.args || [] | ||
| ]); | ||
| } | ||
| async function installDependencies(options = {}) { | ||
| const resolvedOptions = await resolveOperationOptions(options); | ||
| const pmToFrozenLockfileInstallCommand = { | ||
| npm: ["ci"], | ||
| yarn: ["install", "--immutable"], | ||
| bun: ["install", "--frozen-lockfile"], | ||
| pnpm: ["install", "--frozen-lockfile"], | ||
| deno: ["install", "--frozen"] | ||
| }; | ||
| const commandArgs = options.frozenLockFile ? pmToFrozenLockfileInstallCommand[resolvedOptions.packageManager.name] : ["install"]; | ||
| if (!resolvedOptions.dry) { | ||
| await executeCommand(resolvedOptions.packageManager.command, commandArgs, { | ||
| cwd: resolvedOptions.cwd, | ||
| silent: resolvedOptions.silent | ||
| }); | ||
| } | ||
| return { | ||
| exec: { | ||
| command: resolvedOptions.packageManager.command, | ||
| args: commandArgs | ||
| } | ||
| }; | ||
| } | ||
| async function addDependency(name, options = {}) { | ||
| const resolvedOptions = await resolveOperationOptions(options); | ||
| const names = Array.isArray(name) ? name : [name]; | ||
| if (resolvedOptions.packageManager.name === "deno") { | ||
| for (let i = 0; i < names.length; i++) { | ||
| if (!/^(npm|jsr|file):.+$/.test(names[i])) { | ||
| names[i] = `npm:${names[i]}`; | ||
| } | ||
| } | ||
| } | ||
| if (names.length === 0) { | ||
| return {}; | ||
| } | ||
| const args = (resolvedOptions.packageManager.name === "yarn" ? [ | ||
| ...getWorkspaceArgs(resolvedOptions), | ||
| // Global is not supported in berry: yarnpkg/berry#821 | ||
| resolvedOptions.global && resolvedOptions.packageManager.majorVersion === "1" ? "global" : "", | ||
| "add", | ||
| resolvedOptions.dev ? "-D" : "", | ||
| ...names | ||
| ] : [ | ||
| resolvedOptions.packageManager.name === "npm" ? "install" : "add", | ||
| ...getWorkspaceArgs(resolvedOptions), | ||
| resolvedOptions.dev ? "-D" : "", | ||
| resolvedOptions.global ? "-g" : "", | ||
| ...names | ||
| ]).filter(Boolean); | ||
| if (!resolvedOptions.dry) { | ||
| await executeCommand(resolvedOptions.packageManager.command, args, { | ||
| cwd: resolvedOptions.cwd, | ||
| silent: resolvedOptions.silent | ||
| }); | ||
| } | ||
| if (!resolvedOptions.dry && options.installPeerDependencies) { | ||
| const existingPkg = await readPackageJSON(resolvedOptions.cwd); | ||
| const peerDeps = []; | ||
| const peerDevDeps = []; | ||
| for (const _name of names) { | ||
| const pkgName = _name.match(/^(.[^@]+)/)?.[0]; | ||
| const pkg = await readPackageJSON(pkgName, { | ||
| url: resolvedOptions.cwd | ||
| }).catch(() => ({})); | ||
| if (!pkg.peerDependencies || pkg.name !== pkgName) { | ||
| continue; | ||
| } | ||
| for (const [peerDependency, version] of Object.entries( | ||
| pkg.peerDependencies | ||
| )) { | ||
| if (pkg.peerDependenciesMeta?.[peerDependency]?.optional) { | ||
| continue; | ||
| } | ||
| if (existingPkg.dependencies?.[peerDependency] || existingPkg.devDependencies?.[peerDependency]) { | ||
| continue; | ||
| } | ||
| const isDev = pkg.peerDependenciesMeta?.[peerDependency]?.dev; | ||
| (isDev ? peerDevDeps : peerDeps).push(`${peerDependency}@${version}`); | ||
| } | ||
| } | ||
| if (peerDeps.length > 0) { | ||
| await addDependency(peerDeps, { ...resolvedOptions }); | ||
| } | ||
| if (peerDevDeps.length > 0) { | ||
| await addDevDependency(peerDevDeps, { ...resolvedOptions }); | ||
| } | ||
| } | ||
| return { | ||
| exec: { | ||
| command: resolvedOptions.packageManager.command, | ||
| args | ||
| } | ||
| }; | ||
| } | ||
| async function addDevDependency(name, options = {}) { | ||
| return await addDependency(name, { ...options, dev: true }); | ||
| } | ||
| async function removeDependency(name, options = {}) { | ||
| const resolvedOptions = await resolveOperationOptions(options); | ||
| const names = Array.isArray(name) ? name : [name]; | ||
| if (names.length === 0) { | ||
| return {}; | ||
| } | ||
| const args = (resolvedOptions.packageManager.name === "yarn" ? [ | ||
| // Global is not supported in berry: yarnpkg/berry#821 | ||
| resolvedOptions.global && resolvedOptions.packageManager.majorVersion === "1" ? "global" : "", | ||
| ...getWorkspaceArgs(resolvedOptions), | ||
| "remove", | ||
| resolvedOptions.dev ? "-D" : "", | ||
| resolvedOptions.global ? "-g" : "", | ||
| ...names | ||
| ] : [ | ||
| resolvedOptions.packageManager.name === "npm" ? "uninstall" : "remove", | ||
| ...getWorkspaceArgs(resolvedOptions), | ||
| resolvedOptions.dev ? "-D" : "", | ||
| resolvedOptions.global ? "-g" : "", | ||
| ...names | ||
| ]).filter(Boolean); | ||
| if (!resolvedOptions.dry) { | ||
| await executeCommand(resolvedOptions.packageManager.command, args, { | ||
| cwd: resolvedOptions.cwd, | ||
| silent: resolvedOptions.silent | ||
| }); | ||
| } | ||
| return { | ||
| exec: { | ||
| command: resolvedOptions.packageManager.command, | ||
| args | ||
| } | ||
| }; | ||
| } | ||
| async function ensureDependencyInstalled(name, options = {}) { | ||
| const resolvedOptions = await resolveOperationOptions(options); | ||
| const dependencyExists = doesDependencyExist(name, resolvedOptions); | ||
| if (dependencyExists) { | ||
| return true; | ||
| } | ||
| await addDependency(name, resolvedOptions); | ||
| } | ||
| async function dedupeDependencies(options = {}) { | ||
| const resolvedOptions = await resolveOperationOptions(options); | ||
| const isSupported = !["bun", "deno"].includes( | ||
| resolvedOptions.packageManager.name | ||
| ); | ||
| const recreateLockfile = options.recreateLockfile ?? !isSupported; | ||
| if (recreateLockfile) { | ||
| const lockfiles = Array.isArray(resolvedOptions.packageManager.lockFile) ? resolvedOptions.packageManager.lockFile : [resolvedOptions.packageManager.lockFile]; | ||
| for (const lockfile of lockfiles) { | ||
| if (lockfile) | ||
| fs.rmSync(resolve(resolvedOptions.cwd, lockfile), { force: true }); | ||
| } | ||
| return await installDependencies(resolvedOptions); | ||
| } | ||
| if (isSupported) { | ||
| const isyarnv1 = resolvedOptions.packageManager.name === "yarn" && resolvedOptions.packageManager.majorVersion === "1"; | ||
| if (!resolvedOptions.dry) { | ||
| await executeCommand( | ||
| resolvedOptions.packageManager.command, | ||
| [isyarnv1 ? "install" : "dedupe"], | ||
| { | ||
| cwd: resolvedOptions.cwd, | ||
| silent: resolvedOptions.silent | ||
| } | ||
| ); | ||
| } | ||
| return { | ||
| exec: { | ||
| command: resolvedOptions.packageManager.command, | ||
| args: [isyarnv1 ? "install" : "dedupe"] | ||
| } | ||
| }; | ||
| } | ||
| throw new Error( | ||
| `Deduplication is not supported for ${resolvedOptions.packageManager.name}` | ||
| ); | ||
| } | ||
| async function runScript(name, options = {}) { | ||
| const resolvedOptions = await resolveOperationOptions(options); | ||
| const args = [ | ||
| resolvedOptions.packageManager.name === "deno" ? "task" : "run", | ||
| name, | ||
| ...options.args || [] | ||
| ]; | ||
| if (!resolvedOptions.dry) { | ||
| await executeCommand(resolvedOptions.packageManager.command, args, { | ||
| cwd: resolvedOptions.cwd, | ||
| env: resolvedOptions.env, | ||
| silent: resolvedOptions.silent | ||
| }); | ||
| } | ||
| return { | ||
| exec: { | ||
| command: resolvedOptions.packageManager.command, | ||
| args | ||
| } | ||
| }; | ||
| } | ||
| async function dlx(name, options = {}) { | ||
| const resolvedOptions = await resolveOperationOptions(options); | ||
| const commandStr = dlxCommand(resolvedOptions.packageManager.name, name, { | ||
| args: options.args, | ||
| short: options.short, | ||
| packages: options.packages | ||
| }); | ||
| const [command, ...args] = commandStr.split(" "); | ||
| if (!resolvedOptions.dry) { | ||
| await executeCommand(command, args, { | ||
| cwd: resolvedOptions.cwd, | ||
| env: resolvedOptions.env, | ||
| silent: resolvedOptions.silent | ||
| }); | ||
| } | ||
| return { | ||
| exec: { | ||
| command, | ||
| args | ||
| } | ||
| }; | ||
| } | ||
| export { addDependency as a, addDevDependency as b, dedupeDependencies as c, detectPackageManager as d, ensureDependencyInstalled as e, runScript as f, dlx as g, installDependenciesCommand as h, installDependencies as i, addDependencyCommand as j, runScriptCommand as k, dlxCommand as l, packageManagers as p, removeDependency as r }; |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 2 instances
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 2 instances
3
-40%6
-50%35928
-3.85%14
7.69%5
-44.44%535
-26.71%+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
Updated
Updated