Skip to content

Instantly share code, notes, and snippets.

@jsumners
Created November 18, 2021 15:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jsumners/91fe9ec14ea380fc624da4bba5b31291 to your computer and use it in GitHub Desktop.
Save jsumners/91fe9ec14ea380fc624da4bba5b31291 to your computer and use it in GitHub Desktop.
Walk a Node project's dependency tree and list the dependencies and their versions
import fs from 'fs/promises';
import treeify from 'treeify';
const result = await readModDir('.');
console.log(treeify.asTree(result, true));
async function readModDir(modDirPath) {
const dirEntries = await fs.readdir(new URL(modDirPath, import.meta.url));
const hasNodeModules = dirEntries.some(entry => entry === 'node_modules');
const pkgSrc = await fs.readFile(new URL(`${modDirPath}/package.json`, import.meta.url));
const pkg = JSON.parse(pkgSrc);
const deps = hasNodeModules ? await readNodeModules(modDirPath) : {};
const result = {
[pkg.name]: {
version: pkg.version
}
};
if (deps && Object.keys(deps).length > 0) {
result.deps = deps;
}
return result;
}
async function readNodeModules(modDirPath) {
const basePath = `${modDirPath}/node_modules`;
const dirEntries = await fs.readdir(new URL(basePath, import.meta.url));
const result = {};
for (const entry of dirEntries.filter(e => e.startsWith('.') === false)) {
if (entry.startsWith('@')) {
const subDirEntries = await fs.readdir(new URL(`${basePath}/${entry}`, import.meta.url));
for (const subEntry of subDirEntries) {
const scopedDir = await readModDir(`${basePath}/${entry}/${subEntry}`);
result[entry] = scopedDir;
}
continue;
}
const modInfo = await readModDir(`${basePath}/${entry}`);
result[entry] = modInfo[entry];
}
return result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment