You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

findSymlinkedModules.js.patch 3.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. /**
  2. * Copyright (c) 2015-present, Facebook, Inc.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under the BSD-style license found in the
  6. * LICENSE file in the root directory of this source tree. An additional grant
  7. * of patent rights can be found in the PATENTS file in the same directory.
  8. *
  9. * @format
  10. * @flow
  11. */
  12. const path = require('path');
  13. const fs = require('fs');
  14. /**
  15. * Find symlinked modules inside "node_modules."
  16. *
  17. * Naively, we could just perform a depth-first search of all folders in
  18. * node_modules, recursing when we find a symlink.
  19. *
  20. * We can be smarter than this due to our knowledge of how npm/Yarn lays out
  21. * "node_modules" / how tools that build on top of npm/Yarn (such as Lerna)
  22. * install dependencies.
  23. *
  24. * Starting from a given root node_modules folder, this algorithm will look at
  25. * both the top level descendants of the node_modules folder or second level
  26. * descendants of folders that start with "@" (which indicates a scoped
  27. * package). If any of those folders is a symlink, it will recurse into the
  28. * link, and perform the same search in the linked folder.
  29. *
  30. * The end result should be a list of all resolved module symlinks for a given
  31. * root.
  32. */
  33. module.exports = function findSymlinkedModules(
  34. projectRoot: string,
  35. ignoredRoots: Array<string> = [],
  36. ) {
  37. const timeStart = Date.now();
  38. const nodeModuleRoot = path.join(projectRoot, 'node_modules');
  39. const resolvedSymlinks = findModuleSymlinks(nodeModuleRoot, [
  40. ...ignoredRoots,
  41. projectRoot,
  42. ]);
  43. const timeEnd = Date.now();
  44. console.log(
  45. `Scanning folders for symlinks in ${nodeModuleRoot} (${timeEnd -
  46. timeStart}ms)`,
  47. );
  48. return resolvedSymlinks;
  49. };
  50. function findModuleSymlinks(
  51. modulesPath: string,
  52. ignoredPaths: Array<string> = [],
  53. ): Array<string> {
  54. if (!fs.existsSync(modulesPath)) {
  55. return [];
  56. }
  57. // Find module symlinks
  58. const moduleFolders = fs.readdirSync(modulesPath);
  59. const symlinks = moduleFolders.reduce((links, folderName) => {
  60. const folderPath = path.join(modulesPath, folderName);
  61. const maybeSymlinkPaths = [];
  62. if (folderName.startsWith('@')) {
  63. const scopedModuleFolders = fs.readdirSync(folderPath);
  64. maybeSymlinkPaths.push(
  65. ...scopedModuleFolders.map(name => path.join(folderPath, name)),
  66. );
  67. } else {
  68. maybeSymlinkPaths.push(folderPath);
  69. }
  70. return links.concat(resolveSymlinkPaths(maybeSymlinkPaths, ignoredPaths));
  71. }, []);
  72. // For any symlinks found, look in _that_ modules node_modules directory
  73. // and find any symlinked modules
  74. const nestedSymlinks = symlinks.reduce(
  75. (links, symlinkPath) =>
  76. links.concat(
  77. // We ignore any found symlinks or anything from the ignored list,
  78. // to prevent infinite recursion
  79. findModuleSymlinks(path.join(symlinkPath, 'node_modules'), [
  80. ...ignoredPaths,
  81. ...symlinks,
  82. ]),
  83. ),
  84. [],
  85. );
  86. return [...new Set([...symlinks, ...nestedSymlinks])];
  87. }
  88. function resolveSymlinkPaths(maybeSymlinkPaths, ignoredPaths) {
  89. return maybeSymlinkPaths.reduce((links, maybeSymlinkPath) => {
  90. if (fs.lstatSync(maybeSymlinkPath).isSymbolicLink()) {
  91. const resolved = path.resolve(
  92. path.dirname(maybeSymlinkPath),
  93. fs.readlinkSync(maybeSymlinkPath),
  94. );
  95. if (ignoredPaths.indexOf(resolved) === -1 && fs.existsSync(resolved)) {
  96. links.push(resolved);
  97. }
  98. }
  99. return links;
  100. }, []);
  101. }