Skip to content

Commit a44288e

Browse files
committed
Merge branch 'feat-7' into alpha
2 parents 31c4964 + 55d9fc6 commit a44288e

14 files changed

+468
-68
lines changed

.labrc.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
'use strict';
2+
3+
exports.globals = [
4+
'Symbol(__RESOLVED_TEMP_DIRECTORY__)'
5+
].join(',');

README.md

+44-6
Original file line numberDiff line numberDiff line change
@@ -5,45 +5,59 @@ List the Node.js versions supported by the package/repository
55
## Usage (command line)
66

77
```
8-
$ npx detect-node-support [path]
8+
$ npx detect-node-support [options] <path>
99
```
1010

1111
Prints the supported Node.js versions for the package at the specified path. When the path is not a git repository - tries to read the git repository from `package.json` and tries to detect the versions listed in the repository as well.
1212

1313
When `path` is omitted, tries to detect the versions for `cwd`.
1414

1515
```
16-
$ npx detect-node-support [package name]
16+
$ npx detect-node-support [options] <package name>
1717
```
1818

1919
Prints supported Node.js versions for the package from the registry.
2020

2121
```
22-
$ npx detect-node-support [repository git URL]
22+
$ npx detect-node-support [options] <repository git URL>
2323
```
2424

2525
Prints supported Node.js versions for the package at the git URL.
2626

27+
### Options
28+
29+
* `--deps` - include the support information of all dependencies
30+
2731
## Usage (library)
2832

2933
```
30-
const result = await require('detect-node-support').detect({ path });
34+
const result = await require('detect-node-support').detect({ path }, options);
3135
```
3236

3337
`path` should be a folder in the local file system. When the path is not a git repository - tries to read the git repository from `package.json` and tries to detect the versions listed in the repository as well.
3438

3539
```
36-
const result = await require('detect-node-support').detect({ packageName });
40+
const result = await require('detect-node-support').detect({ packageName }, options);
3741
```
3842

3943
`packageName` is a string name for the package in the registry.
4044

4145
```
42-
const result = await require('detect-node-support').detect({ repository });
46+
const result = await require('detect-node-support').detect({ repository }, options);
4347
```
4448

4549
`repository` is a URL for a git repository.
4650

51+
```
52+
const result = await require('detect-node-support').detect(what, options);
53+
```
54+
55+
`what` is a string containing either a package name, or a local path, or a reference to a git repository.
56+
57+
### Options
58+
59+
- `deps: false` - when `true`, include the support information of all dependencies.
60+
4761
### Result
4862

4963
- Throws if the `path` / `repository` does not have a `package.json`
@@ -88,6 +102,30 @@ const result = {
88102
"lts/*": "12.14.0",
89103
"invalid-specifier": false
90104
}
105+
},
106+
107+
// only present when explicitly requested
108+
"dependencies": {
109+
110+
// will contain a support object for every unique dependency in the tree
111+
// note that the `version` will be the _latest_ version available in the registry
112+
// see below for the actual versions installed
113+
"support": [
114+
{
115+
"name": "dependency-A"
116+
/*... other fields ...*/
117+
},
118+
{
119+
"name": "dependency-B"
120+
/*... other fields ...*/
121+
}
122+
],
123+
124+
// will contain a list of unique versions for each dependency found in the dependency tree
125+
"versions": {
126+
"dependency-A": ["0.0.10", "1.2.5"],
127+
"dependency-B": ["0.5.3", "1.0.0"]
128+
}
91129
}
92130
}
93131
```

bin/detect-node-support

+20-33
Original file line numberDiff line numberDiff line change
@@ -2,58 +2,45 @@
22

33
'use strict';
44

5-
const Fs = require('fs');
6-
const NodeSupport = require('..');
7-
const { URL } = require('url');
5+
const Minimist = require('minimist');
6+
const Util = require('util');
87

8+
const NodeSupport = require('..');
99

1010
const internals = {};
1111

1212
internals.help = () => {
1313

14-
return `Usage: detect-node-support [ path | Github URL | npm package name ]`;
15-
};
16-
14+
return `
15+
Usage: detect-node-support [--deps] [--json] <what>
1716
18-
internals.autoDetect = (what) => {
17+
<what> can be an npm package name, or a Github URL, or a path
18+
with a package.json.
1919
20-
try {
21-
var url = new URL(what);
22-
}
23-
catch (err) {
24-
if (err.code !== 'ERR_INVALID_URL') {
25-
throw err;
26-
}
27-
}
28-
29-
if (url) {
30-
return NodeSupport.detect({ repository: url.href });
31-
}
32-
33-
if (Fs.existsSync(what)) {
34-
return NodeSupport.detect({ path: what });
35-
}
36-
37-
if (what.includes('/') && !what.startsWith('@')) {
38-
return NodeSupport.detect({ repository: `https://github.com/${what}` });
39-
}
40-
41-
return NodeSupport.detect({ packageName: what });
20+
Options:
21+
--deps Include the support information of all dependencies
22+
--json Print JSON formatted output
23+
`;
4224
};
4325

44-
exports.main = async (nodeBin, thisBin, what) => {
26+
exports.main = async ({ _: [what], deps, json }) => {
4527

4628
if (!what) {
4729
console.log(internals.help());
4830
return;
4931
}
5032

51-
const result = await internals.autoDetect(what);
33+
const result = await NodeSupport.detect(what, { deps });
5234

53-
console.log(result);
35+
if (json) {
36+
console.log(JSON.stringify(result, null, ' '));
37+
}
38+
else {
39+
console.log(Util.inspect(result, false, null, true));
40+
}
5441
};
5542

56-
exports.main(...process.argv)
43+
exports.main(Minimist(process.argv.slice(2), { boolean: ['deps', 'json'] }))
5744
.catch((err) => {
5845

5946
console.error(err);

lib/deps.js

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
'use strict';
2+
3+
const { Arborist } = require('@npmcli/arborist');
4+
const Fs = require('fs');
5+
const Path = require('path');
6+
const Tempy = require('tempy');
7+
8+
const Package = require('./package');
9+
10+
const internals = {};
11+
12+
13+
internals.walk = (node, callback) => {
14+
15+
callback(node);
16+
17+
node.children.forEach((child) => {
18+
19+
internals.walk(child, callback);
20+
});
21+
};
22+
23+
24+
exports.resolve = async ({ packageJson, lockfile }) => {
25+
26+
const path = Tempy.directory();
27+
Fs.writeFileSync(Path.join(path, 'package.json'), JSON.stringify(packageJson, null, ' '));
28+
29+
if (lockfile) {
30+
Fs.writeFileSync(Path.join(path, 'package-lock.json'), JSON.stringify(lockfile, null, ' '));
31+
}
32+
33+
const arborist = new Arborist({ path });
34+
35+
await arborist.buildIdealTree();
36+
37+
const map = {};
38+
39+
internals.walk(arborist.idealTree, (node) => {
40+
41+
if (node === arborist.idealTree) {
42+
return;
43+
}
44+
45+
if (node.dev) {
46+
return;
47+
}
48+
49+
map[node.name] = map[node.name] || new Set();
50+
map[node.name].add(node.package.version);
51+
});
52+
53+
const result = {};
54+
55+
for (const name of Object.keys(map).sort()) {
56+
result[name] = [...map[name]];
57+
}
58+
59+
return result;
60+
};
61+
62+
internals.tryLoad = async (loadFile, filename) => {
63+
64+
try {
65+
return await loadFile(filename, { json: true });
66+
}
67+
catch (err) {
68+
if (err.code !== 'ENOENT') {
69+
throw err;
70+
}
71+
}
72+
};
73+
74+
exports.detect = async ({ packageJson, loadFile }) => {
75+
76+
const lockfile = (await internals.tryLoad(loadFile, 'package-lock.json')) || (await internals.tryLoad(loadFile, 'npm-shrinkwrap.json'));
77+
78+
const versions = await exports.resolve({ packageJson, lockfile });
79+
80+
const support = [];
81+
82+
for (const packageName of Object.keys(versions)) {
83+
try {
84+
const { result } = await Package.detect({ packageName });
85+
support.push(result);
86+
}
87+
catch (err) {
88+
console.warn(`Failed to detect support for ${packageName}: ${err && err.message}`);
89+
}
90+
}
91+
92+
return { support, versions };
93+
};

lib/engines.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
'use strict';
22

3-
exports.detect = ({ engines }) => {
3+
exports.detect = ({ packageJson }) => {
44

5-
if (engines) {
5+
if (packageJson.engines) {
66

77
return {
8-
engines: engines.node
8+
engines: packageJson.engines.node
99
};
1010
}
1111
};

lib/index.js

+6-15
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,15 @@
11
'use strict';
22

3-
const Engines = require('./engines');
3+
const Deps = require('./deps');
44
const Package = require('./package');
5-
const Travis = require('./travis');
65

7-
exports.detect = async ({ path, repository, packageName }) => {
6+
exports.detect = async function (what, { deps } = {}) {
87

9-
const packageInfo = await Package.detect({ path, repository, packageName });
8+
const { result, meta } = await Package.detect(what);
109

11-
const result = {};
12-
13-
result.name = packageInfo.name;
14-
result.version = packageInfo.version;
15-
result.commit = await packageInfo.getCommit();
16-
result.timestamp = Date.now();
17-
18-
const travis = await Travis.detect(packageInfo);
19-
const engines = await Engines.detect(packageInfo);
20-
21-
Object.assign(result, travis, engines);
10+
if (deps) {
11+
result.dependencies = await Deps.detect(meta);
12+
}
2213

2314
return result;
2415
};

lib/loader.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ internals.createPackageLoader = async (packageName) => {
4545
const result = await repositoryLoader.loadFile(filename, options);
4646

4747
if (filename === 'package.json' && result.name !== packageName) {
48-
throw new Error(`${repository} does not contain ${packageName}`);
48+
throw new Error(`${repository} does not contain ${packageName}. Monorepo not supported: https://github.com/pkgjs/detect-node-support/issues/6`);
4949
}
5050

5151
return result;

0 commit comments

Comments
 (0)