has-dependency-installed.js 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. "use strict";
  2. const log = require("npmlog");
  3. const readPackageTree = require("read-package-tree");
  4. const semver = require("semver");
  5. /** @typedef {Map<string, string>} InstalledDependencies dependency name -> installed version */
  6. // cache installed lookups
  7. /** @type {Map<import("@lerna/package").Package, InstalledDependencies>} */
  8. const cache = new Map();
  9. module.exports.hasDependencyInstalled = hasDependencyInstalled;
  10. /**
  11. * Determine if a dependency has already been installed for this package
  12. * @param {import("@lerna/package").Package} pkg The Package instance to check for installed dependency
  13. * @param {string} depName Name of the dependency
  14. * @param {string} needVersion version to test with
  15. */
  16. function hasDependencyInstalled(pkg, depName, needVersion) {
  17. log.silly("hasDependencyInstalled", pkg.name, depName);
  18. return getInstalled(pkg).then(
  19. (versions) => versions.has(depName) && semver.satisfies(versions.get(depName), needVersion)
  20. );
  21. }
  22. /**
  23. * @param {import("@lerna/package").Package} pkg
  24. * @returns {Promise<InstalledDependencies>}
  25. */
  26. function getInstalled(pkg) {
  27. return new Promise((resolve, reject) => {
  28. if (cache.has(pkg)) {
  29. return resolve(cache.get(pkg));
  30. }
  31. readPackageTree(pkg.location, filterTopLevel, (err, { children }) => {
  32. if (err) {
  33. return reject(err);
  34. }
  35. /** @type {InstalledDependencies} */
  36. const deps = new Map(children.map(({ package: { name, version } }) => [name, version]));
  37. cache.set(pkg, deps);
  38. resolve(deps);
  39. });
  40. });
  41. }
  42. /**
  43. * @param {import("read-package-tree").Node} node
  44. * @param {string} kidName
  45. */
  46. function filterTopLevel(node, kidName) {
  47. if (node.parent) {
  48. return false;
  49. }
  50. return Boolean(
  51. (node.package.dependencies && node.package.dependencies[kidName]) ||
  52. (node.package.devDependencies && node.package.devDependencies[kidName]) ||
  53. (node.package.peerDependencies && node.package.peerDependencies[kidName]) ||
  54. (node.package.optionalDependencies && node.package.optionalDependencies[kidName])
  55. );
  56. }