1const fs = require('fs');
2const path = require('path');
3
4/**
5 * Returns a mapping from the names of symlinked packages to the physical paths of each package.
6 */
7module.exports = function getSymlinkedNodeModulesForDirectory(packagePath) {
8  const nodeModulesPath = path.join(packagePath, 'node_modules');
9  const directories = listDirectoryContents(nodeModulesPath);
10
11  const modules = {};
12  for (const directory of directories) {
13    // The directory is either a scope or a package
14    if (directory.startsWith('@')) {
15      const scopePath = path.join(nodeModulesPath, directory);
16      const scopedPackageDirectories = fs.readdirSync(scopePath);
17      for (const subdirectory of scopedPackageDirectories) {
18        const dependencyName = `${directory}/${subdirectory}`;
19        const dependencyPath = path.join(scopePath, subdirectory);
20        if (fs.lstatSync(dependencyPath).isSymbolicLink()) {
21          modules[dependencyName] = fs.realpathSync(dependencyPath);
22        }
23      }
24    } else {
25      const dependencyName = directory;
26      const dependencyPath = path.join(nodeModulesPath, directory);
27      if (fs.lstatSync(dependencyPath).isSymbolicLink()) {
28        modules[dependencyName] = fs.realpathSync(dependencyPath);
29      }
30    }
31  }
32  return modules;
33};
34
35function listDirectoryContents(directory) {
36  try {
37    return fs.readdirSync(directory);
38  } catch (e) {
39    if (e.code === 'ENOENT') {
40      return [];
41    }
42    throw e;
43  }
44}
45