https://github.com/discoveryjs/node-modules
An utility for scan and analyze packages in `node_modules`
https://github.com/discoveryjs/node-modules
Last synced: 10 months ago
JSON representation
An utility for scan and analyze packages in `node_modules`
- Host: GitHub
- URL: https://github.com/discoveryjs/node-modules
- Owner: discoveryjs
- License: mit
- Created: 2019-09-07T15:01:08.000Z (almost 7 years ago)
- Default Branch: master
- Last Pushed: 2022-02-12T13:29:24.000Z (over 4 years ago)
- Last Synced: 2025-09-01T07:14:17.600Z (10 months ago)
- Language: JavaScript
- Homepage:
- Size: 32.2 KB
- Stars: 7
- Watchers: 1
- Forks: 0
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# @discoveryjs/node-modules
[](https://www.npmjs.com/package/@discoveryjs/node-modules)
[](https://twitter.com/js_discovery)
An utility for scan and analyze packages in `node_modules`. It uses file system scan to determine which package physical instances are exactly installed in `node_modules`.
Is a part of [Discovery.js](https://github.com/discoveryjs) projects.
- [How to use](#how-to-use)
- [API](#api)
- [fetchNodeModules(basedir): Promise.](#fetchnodemodulesbasedir-promisepackages-array)
- [fetchNodeModules.analyzer(file, content, context)](#fetchnodemodulesanalyzerfile-content-context)
- [Examples](#examples)
- [License](#license)
## How to use
Install:
```
npm install @discoveryjs/node-modules
```
Use:
```js
const fetchNodeModules = require('@discoveryjs/node-modules');
fetchNodeModules('absolute/path/to/project').then(packages => {
// do something with found packages
});
```
See [examples](#examples) below.
## API
### fetchNodeModules(basedir): Promise.
Main function to fetch a package list for a specified `basedir`. The method check `basedir` for `node_modules` and `package.json` to retrieve a package list. When `basedir` is not specified `process.cwd()` is using. Root `package.json` is optional and used to determine which packages are using for development purposes only.
A list of packages contains each physical instance of packages. That is, if a package has several copies of itself (e.g. due to various versions) all of them will be in the list. Each entry has following properties:
- `name` – value of `name` field in `package.json`
- `version` – value of `version` field in `package.json`; can be `null` for root `package.json`
- `dev` – boolean value, which `true` when a package is using for dev purposes only
- `path` – relative to `basedir` path to a package. It can be used as an unique identifier of a package instance (and `deps.resolved` use the same values for a reference)
- `entry` - relative to `path` path to an entry point module. It can be `null` when entry is not resolved
- `deps` - list of entries from `dependencies`, `peerDependencies` and `optionalDependencies` sections of `package.json`. `devDependencies` are included for root `package.json` only. Each entry has following properties:
- `type` – one of `prod`, `peer`, `optional` or `dev`
- `name` - a key from a dependency section
- `version` - a value from a dependency section
- `resolved` - resolved path to a package. It can be used to find a physical instance of package it refers to. It may contain `null`, if no physical instance of package is not found (Note: that's a missed dependency for `prod`, `peer` and `dev` dependencies, but not a problem for `optional`).
- `packageJson` - content of a `package.json` parsed with `JSON.parse()`
### fetchNodeModules.analyzer(file, content, context)
Analyzer to use with [@discoveryjs/scan-fs](https://github.com/discoveryjs/scan-fs):
```js
const scanFs = require('@discoveryjs/scan-fs');
const nodeModules = require('@discoveryjs/node-modules');
scanFs({
...
rules: [
...
{
test: /\/package\.json$/,
extract: nodeModules.analyzer
}
]
});
```
## Examples
```js
const fetchNodeModules = require('@discoveryjs/node-modules');
fetchNodeModules(__dirname).then(modules => {
const groupByName = modules.reduce(
(map, entry) => map.set(entry.name, (map.get(entry.name) || []).concat(entry)),
new Map()
);
// find packages with more than one physical instance
// and sort by entry count from top to bottom
const duplicates = [...groupByName]
.filter(([, entries]) => entries.length > 1)
.sort(([, a], [, b]) => b.length - a.length);
// output findings
duplicates.forEach(([name, entries]) => {
console.log(`${name} (${entries.length} entries)`);
entries.forEach(({ path, version }) => console.log(` ${path} ${version}`));
});
});
```
The same example but using [jora](https://github.com/discoveryjs/jora):
```js
const fetchNodeModules = require('@discoveryjs/node-modules');
const jora = require('jora');
fetchNodeModules(__dirname).then(modules => {
const duplicates = jora(`
group().({ name: key, entries: value })
.[entries.size() > 1]
.sort()
.reverse()
`)(modules);
// output findings
duplicates.forEach(({ name, entries }) => {
console.log(`${name} (${entries.length} entries)`);
entries.forEach(({ path, version }) => console.log(` ${path} ${version}`));
});
});
```
Example of output in both cases:
```
ansi-regex (2 entries)
node_modules/ansi-regex 3.0.0
node_modules/strip-ansi/node_modules/ansi-regex 4.1.0
resolve-from (2 entries)
node_modules/resolve-from 5.0.0
node_modules/import-fresh/node_modules/resolve-from 4.0.0
...
```
## License
MIT