detect.mjs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. import fs from 'node:fs';
  2. import fsPromises from 'node:fs/promises';
  3. import path from 'node:path';
  4. import process from 'node:process';
  5. import { LOCKS, AGENTS } from './constants.mjs';
  6. async function detect(options = {}) {
  7. const { cwd, onUnknown } = options;
  8. for (const directory of lookup(cwd)) {
  9. for (const lock of Object.keys(LOCKS)) {
  10. if (await fileExists(path.join(directory, lock))) {
  11. const name = LOCKS[lock];
  12. const result2 = await parsePackageJson(path.join(directory, "package.json"), onUnknown);
  13. if (result2)
  14. return result2;
  15. else
  16. return { name, agent: name };
  17. }
  18. }
  19. const result = await parsePackageJson(path.join(directory, "package.json"), onUnknown);
  20. if (result)
  21. return result;
  22. }
  23. return null;
  24. }
  25. function detectSync(options = {}) {
  26. const { cwd, onUnknown } = options;
  27. for (const directory of lookup(cwd)) {
  28. for (const lock of Object.keys(LOCKS)) {
  29. if (fileExistsSync(path.join(directory, lock))) {
  30. const name = LOCKS[lock];
  31. const result2 = parsePackageJsonSync(path.join(directory, "package.json"), onUnknown);
  32. if (result2)
  33. return result2;
  34. else
  35. return { name, agent: name };
  36. }
  37. }
  38. const result = parsePackageJsonSync(path.join(directory, "package.json"), onUnknown);
  39. if (result)
  40. return result;
  41. }
  42. return null;
  43. }
  44. function getUserAgent() {
  45. const userAgent = process.env.npm_config_user_agent;
  46. if (!userAgent) {
  47. return null;
  48. }
  49. const name = userAgent.split("/")[0];
  50. return AGENTS.includes(name) ? name : null;
  51. }
  52. function* lookup(cwd = process.cwd()) {
  53. let directory = path.resolve(cwd);
  54. const { root } = path.parse(directory);
  55. while (directory && directory !== root) {
  56. yield directory;
  57. directory = path.dirname(directory);
  58. }
  59. }
  60. async function parsePackageJson(filepath, onUnknown) {
  61. return !filepath || !await fileExists(filepath) ? null : handlePackageManager(filepath, onUnknown);
  62. }
  63. function parsePackageJsonSync(filepath, onUnknown) {
  64. return !filepath || !fileExistsSync(filepath) ? null : handlePackageManager(filepath, onUnknown);
  65. }
  66. function handlePackageManager(filepath, onUnknown) {
  67. try {
  68. const pkg = JSON.parse(fs.readFileSync(filepath, "utf8"));
  69. let agent;
  70. if (typeof pkg.packageManager === "string") {
  71. const [name, ver] = pkg.packageManager.replace(/^\^/, "").split("@");
  72. let version = ver;
  73. if (name === "yarn" && Number.parseInt(ver) > 1) {
  74. agent = "yarn@berry";
  75. version = "berry";
  76. return { name, agent, version };
  77. } else if (name === "pnpm" && Number.parseInt(ver) < 7) {
  78. agent = "pnpm@6";
  79. return { name, agent, version };
  80. } else if (AGENTS.includes(name)) {
  81. agent = name;
  82. return { name, agent, version };
  83. } else {
  84. return onUnknown?.(pkg.packageManager) ?? null;
  85. }
  86. }
  87. } catch {
  88. }
  89. return null;
  90. }
  91. async function fileExists(filePath) {
  92. try {
  93. const stats = await fsPromises.stat(filePath);
  94. if (stats.isFile()) {
  95. return true;
  96. }
  97. } catch {
  98. }
  99. return false;
  100. }
  101. function fileExistsSync(filePath) {
  102. try {
  103. const stats = fs.statSync(filePath);
  104. if (stats.isFile()) {
  105. return true;
  106. }
  107. } catch {
  108. }
  109. return false;
  110. }
  111. export { detect, detectSync, getUserAgent };