@rnm/pm
Version:
Unified Package Manager for Node.js
69 lines • 11.3 kB
JavaScript
import fs from "node:fs/promises";
import path from "node:path";
import process from "node:process";
import { findUp } from "find-up-simple";
const importPkgJson = async (p) => await fs
.readFile(p, "utf8")
.then(JSON.parse)
.catch(() => undefined);
async function detectByPackageJson(directory = process.cwd()) {
const pkgJsonContent = await importPkgJson(path.join(directory, "package.json"));
// 1. detect pm by `packageManager` field
const [packageManager, rest] = pkgJsonContent?.packageManager?.split("@") ?? [];
if (packageManager === "npm" ||
packageManager === "yarn" ||
packageManager === "pnpm") {
const version = rest?.split("+")[0];
return { name: packageManager, ...(version && { version }) };
}
// 2. detect pm by `devEngines` filed
const { name, version: devEnginesVer } = pkgJsonContent?.devEngines?.packageManager ?? {};
if (name === "npm" || name === "yarn" || name === "pnpm") {
const version = devEnginesVer?.split("+")[0];
return { name, ...(version && { version }) };
}
// 3. detect pm by `engines` filed
// Note: Corepack does not support `engines` field. So the result doesn't include the version. See https://github.com/nodejs/corepack/issues/694.
if (pkgJsonContent?.engines?.["npm"])
return { name: "npm" };
if (pkgJsonContent?.engines?.["yarn"])
return { name: "yarn" };
if (pkgJsonContent?.engines?.["pnpm"])
return { name: "pnpm" };
const parent = path.dirname(directory);
if (directory === parent)
return undefined;
return await detectByPackageJson(parent);
}
async function detectByLockFile(directory = process.cwd()) {
const locks = (await Promise.all([
findUp("package-lock.json", { cwd: directory }),
findUp("yarn.lock", { cwd: directory }),
findUp("pnpm-lock.yaml", { cwd: directory }),
])).filter((p) => p !== undefined);
if (locks.length > 1) {
throw new Error("Multiple lock files found. Please remove one of them.");
}
if (locks[0]?.endsWith("package-lock.json"))
return { name: "npm" };
if (locks[0]?.endsWith("yarn.lock"))
return { name: "yarn" };
if (locks[0]?.endsWith("pnpm-lock.yaml"))
return { name: "pnpm" };
return undefined;
}
/**
* Detects the package manager used in the specified directory.
* @param directory - The absolute path to the directory to check.
*/
export async function detect(directory = process.cwd()) {
const pkgJsonPath = await findUp("package.json", { cwd: directory });
if (!pkgJsonPath) {
// throw new Error("No package.json found.");
return undefined;
}
// detect pm by package.json or lock files
return ((await detectByPackageJson(path.dirname(pkgJsonPath))) ??
(await detectByLockFile(directory)));
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGV0ZWN0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvZGV0ZWN0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDbEMsT0FBTyxJQUFJLE1BQU0sV0FBVyxDQUFDO0FBQzdCLE9BQU8sT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUNuQyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFReEMsTUFBTSxhQUFhLEdBQUcsS0FBSyxFQUFFLENBQVMsRUFBRSxFQUFFLENBQ3hDLE1BQU0sRUFBRTtLQUNMLFFBQVEsQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDO0tBQ25CLElBQUksQ0FJRixJQUFJLENBQUMsS0FBSyxDQUFDO0tBQ2IsS0FBSyxDQUFDLEdBQUcsRUFBRSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0FBRTVCLEtBQUssVUFBVSxtQkFBbUIsQ0FDaEMsU0FBUyxHQUFHLE9BQU8sQ0FBQyxHQUFHLEVBQUU7SUFFekIsTUFBTSxjQUFjLEdBQUcsTUFBTSxhQUFhLENBQ3hDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLGNBQWMsQ0FBQyxDQUNyQyxDQUFDO0lBRUYseUNBQXlDO0lBQ3pDLE1BQU0sQ0FBQyxjQUFjLEVBQUUsSUFBSSxDQUFDLEdBQzFCLGNBQWMsRUFBRSxjQUFjLEVBQUUsS0FBSyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNuRCxJQUNFLGNBQWMsS0FBSyxLQUFLO1FBQ3hCLGNBQWMsS0FBSyxNQUFNO1FBQ3pCLGNBQWMsS0FBSyxNQUFNLEVBQ3pCLENBQUM7UUFDRCxNQUFNLE9BQU8sR0FBRyxJQUFJLEVBQUUsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3BDLE9BQU8sRUFBRSxJQUFJLEVBQUUsY0FBYyxFQUFFLEdBQUcsQ0FBQyxPQUFPLElBQUksRUFBRSxPQUFP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N0MsT0FBTyxTQUFTLENBQUM7SUFDbkIsQ0FBQztJQUVELDBDQUEwQztJQUMxQyxPQUFPLENBQ0wsQ0FBQyxNQUFNLG1CQUFtQixDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQztRQUN0RCxDQUFDLE1BQU0sZ0JBQWdCLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FDcEMsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgZnMgZnJvbSBcIm5vZGU6ZnMvcHJvbWlzZXNcIjtcbmltcG9ydCBwYXRoIGZyb20gXCJub2RlOnBhdGhcIjtcbmltcG9ydCBwcm9jZXNzIGZyb20gXCJub2RlOnByb2Nlc3NcIjtcbmltcG9ydCB7IGZpbmRVcCB9IGZyb20gXCJmaW5kLXVwLXNpbXBsZVwiO1xuaW1wb3J0IHR5cGUgeyBTdXBwb3J0ZWRQbSB9IGZyb20gXCIuLi9jb25zdGFudHMudHNcIjtcblxuZXhwb3J0IGludGVyZmFjZSBEZXRlY3RSZXN1bHQge1xuICBuYW1lOiBTdXBwb3J0ZWRQbTtcbiAgdmVyc2lvbj86IHN0cmluZztcbn1cblxuY29uc3QgaW1wb3J0UGtnSnNvbiA9IGFzeW5jIChwOiBzdHJpbmcpID0+XG4gIGF3YWl0IGZzXG4gICAgLnJlYWRGaWxlKHAsIFwidXRmOFwiKVxuICAgIC50aGVuPHtcbiAgICAgIHBhY2thZ2VNYW5hZ2VyPzogc3RyaW5nO1xuICAgICAgZW5naW5lcz86IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG4gICAgICBkZXZFbmdpbmVzPzogeyBwYWNrYWdlTWFuYWdlcj86IHsgbmFtZT86IHN0cmluZzsgdmVyc2lvbj86IHN0cmluZyB9IH07XG4gICAgfT4oSlNPTi5wYXJzZSlcbiAgICAuY2F0Y2goKCkgPT4gdW5kZWZpbmVkKTtcblxuYXN5bmMgZnVuY3Rpb24gZGV0ZWN0QnlQYWNrYWdlSnNvbihcbiAgZGlyZWN0b3J5ID0gcHJvY2Vzcy5jd2QoKSxcbik6IFByb21pc2U8RGV0ZWN0UmVzdWx0IHwgdW5kZWZpbmVkPiB7XG4gIGNvbnN0IHBrZ0pzb25Db250ZW50ID0gYXdhaXQgaW1wb3J0UGtnSnNvbihcbiAgICBwYXRoLmpvaW4oZGlyZWN0b3J5LCBcInBhY2thZ2UuanNvblwiKSxcbiAgKTtcblxuICAvLyAxLiBkZXRlY3QgcG0gYnkgYHBhY2thZ2VNYW5hZ2VyYCBmaWVsZFxuICBjb25zdCBbcGFja2FnZU1hbmFnZXIsIHJlc3RdID1cbiAgICBwa2dKc29uQ29udGVudD8ucGFja2FnZU1hbmFnZXI/LnNwbGl0KFwiQFwiKSA/PyBbXTtcbiAgaWYgKFxuICAgIHBhY2thZ2VNYW5hZ2VyID09PSBcIm5wbVwiIHx8XG4gICAgcGFja2FnZU1hbmFnZXIgPT09IFwieWFyblwiIHx8XG4gICAgcGFja2FnZU1hbmFnZXIgPT09IFwicG5wbVwiXG4gICkge1xuICAgIGNvbnN0IHZlcnNpb24gPSByZXN0Py5zcGxpdChcIitcIilbMF07XG4gICAgcmV0dXJuIHsgbmFtZTogcGFja2FnZU1hbmFnZXIsIC4uLih2ZXJzaW9uICYmIHsgdmVyc2lvbiB9KSB9O1xuICB9XG5cbiAgLy8gMi4gZGV0ZWN0IHBtIGJ5IGBkZXZFbmdpbmVzYCBmaWxlZFxuICBjb25zdCB7IG5hbWUsIHZlcnNpb246IGRldkVuZ2luZXNWZXIgfSA9XG4gICAgcGtnSnNvbkNvbnRlbnQ/LmRldkVuZ2luZXM/LnBhY2thZ2VNYW5hZ2VyID8/IHt9O1xuICBpZiAobmFtZSA9PT0gXCJucG1cIiB8fCBuYW1lID09PSBcInlhcm5cIiB8fCBuYW1lID09PSBcInBucG1cIikge1xuICAgIGNvbnN0IHZlcnNpb24gPSBkZXZFbmdpbmVzVmVyPy5zcGxpdChcIitcIilbMF07XG4gICAgcmV0dXJuIHsgbmFtZSwgLi4uKHZlcnNpb24gJiYgeyB2ZXJzaW9uIH0pIH07XG4gIH1cblxuICAvLyAzLiBkZXRlY3QgcG0gYnkgYGVuZ2luZXNgIGZpbGVkXG4gIC8vIE5vdGU6IENvcmVwYWNrIGRvZXMgbm90IHN1cHBvcnQgYGVuZ2luZXNgIGZpZWxkLiBTbyB0aGUgcmVzdWx0IGRvZXNuJ3QgaW5jbHVkZSB0aGUgdmVyc2lvbi4gU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9ub2RlanMvY29yZXBhY2svaXNzdWVzLzY5NC5cbiAgaWYgKHBrZ0pzb25Db250ZW50Py5lbmdpbmVzPy5bXCJucG1cIl0pIHJldHVybiB7IG5hbWU6IFwibnBtXCIgfTtcbiAgaWYgKHBrZ0pzb25Db250ZW50Py5lbmdpbmVzPy5bXCJ5YXJuXCJdKSByZXR1cm4geyBuYW1lOiBcInlhcm5cIiB9O1xuICBpZiAocGtnSnNvbkNvbnRlbnQ/LmVuZ2luZXM/LltcInBucG1cIl0pIHJldHVybiB7IG5hbWU6IFwicG5wbVwiIH07XG5cbiAgY29uc3QgcGFyZW50ID0gcGF0aC5kaXJuYW1lKGRpcmVjdG9yeSk7XG4gIGlmIChkaXJlY3RvcnkgPT09IHBhcmVudCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgcmV0dXJuIGF3YWl0IGRldGVjdEJ5UGFja2FnZUpzb24ocGFyZW50KTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZGV0ZWN0QnlMb2NrRmlsZShcbiAgZGlyZWN0b3J5ID0gcHJvY2Vzcy5jd2QoKSxcbik6IFByb21pc2U8RGV0ZWN0UmVzdWx0IHwgdW5kZWZpbmVkPiB7XG4gIGNvbnN0IGxvY2tzID0gKFxuICAgIGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgIGZpbmRVcChcInBhY2thZ2UtbG9jay5qc29uXCIsIHsgY3dkOiBkaXJlY3RvcnkgfSksXG4gICAgICBmaW5kVXAoXCJ5YXJuLmxvY2tcIiwgeyBjd2Q6IGRpcmVjdG9yeSB9KSxcbiAgICAgIGZpbmRVcChcInBucG0tbG9jay55YW1sXCIsIHsgY3dkOiBkaXJlY3RvcnkgfSksXG4gICAgXSlcbiAgKS5maWx0ZXIoKHApID0+IHAgIT09IHVuZGVmaW5lZCk7XG5cbiAgaWYgKGxvY2tzLmxlbmd0aCA+IDEpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJNdWx0aXBsZSBsb2NrIGZpbGVzIGZvdW5kLiBQbGVhc2UgcmVtb3ZlIG9uZSBvZiB0aGVtLlwiKTtcbiAgfVxuXG4gIGlmIChsb2Nrc1swXT8uZW5kc1dpdGgoXCJwYWNrYWdlLWxvY2suanNvblwiKSkgcmV0dXJuIHsgbmFtZTogXCJucG1cIiB9O1xuICBpZiAobG9ja3NbMF0/LmVuZHNXaXRoKFwieWFybi5sb2NrXCIpKSByZXR1cm4geyBuYW1lOiBcInlhcm5cIiB9O1xuICBpZiAobG9ja3NbMF0/LmVuZHNXaXRoKFwicG5wbS1sb2NrLnlhbWxcIikpIHJldHVybiB7IG5hbWU6IFwicG5wbVwiIH07XG5cbiAgcmV0dXJuIHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBEZXRlY3RzIHRoZSBwYWNrYWdlIG1hbmFnZXIgdXNlZCBpbiB0aGUgc3BlY2lmaWVkIGRpcmVjdG9yeS5cbiAqIEBwYXJhbSBkaXJlY3RvcnkgLSBUaGUgYWJzb2x1dGUgcGF0aCB0byB0aGUgZGlyZWN0b3J5IHRvIGNoZWNrLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZGV0ZWN0KFxuICBkaXJlY3RvcnkgPSBwcm9jZXNzLmN3ZCgpLFxuKTogUHJvbWlzZTxEZXRlY3RSZXN1bHQgfCB1bmRlZmluZWQ+IHtcbiAgY29uc3QgcGtnSnNvblBhdGggPSBhd2FpdCBmaW5kVXAoXCJwYWNrYWdlLmpzb25cIiwgeyBjd2Q6IGRpcmVjdG9yeSB9KTtcbiAgaWYgKCFwa2dKc29uUGF0aCkge1xuICAgIC8vIHRocm93IG5ldyBFcnJvcihcIk5vIHBhY2thZ2UuanNvbiBmb3VuZC5cIik7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8vIGRldGVjdCBwbSBieSBwYWNrYWdlLmpzb24gb3IgbG9jayBmaWxlc1xuICByZXR1cm4gKFxuICAgIChhd2FpdCBkZXRlY3RCeVBhY2thZ2VKc29uKHBhdGguZGlybmFtZShwa2dKc29uUGF0aCkpKSA/P1xuICAgIChhd2FpdCBkZXRlY3RCeUxvY2tGaWxlKGRpcmVjdG9yeSkpXG4gICk7XG59XG4iXX0=