11'use strict' ;
22
3+ const Debug = require ( 'debug' ) ;
34const { Arborist } = require ( '@npmcli/arborist' ) ;
45const Fs = require ( 'fs' ) ;
56const Path = require ( 'path' ) ;
6- const Tempy = require ( 'tempy ' ) ;
7+ const Tmp = require ( 'tmp ' ) ;
78
89const Package = require ( './package' ) ;
10+ const Utils = require ( './utils' ) ;
911
1012const internals = { } ;
1113
1214
15+ internals . log = Debug ( 'detect-node-support' ) ;
16+
17+
1318internals . walk = ( node , callback ) => {
1419
1520 callback ( node ) ;
@@ -21,15 +26,29 @@ internals.walk = (node, callback) => {
2126} ;
2227
2328
24- exports . resolve = async ( { packageJson, lockfile } ) => {
29+ internals . resolve = async ( { packageJson, lockfile } , options ) => {
30+
31+ const { deep, dev } = options ;
32+
33+ const tmpDir = Tmp . dirSync ( { unsafeCleanup : true } ) ;
34+ const path = tmpDir . name ;
2535
26- const path = Tempy . directory ( ) ;
2736 Fs . writeFileSync ( Path . join ( path , 'package.json' ) , JSON . stringify ( packageJson , null , ' ' ) ) ;
2837
2938 if ( lockfile ) {
3039 Fs . writeFileSync ( Path . join ( path , 'package-lock.json' ) , JSON . stringify ( lockfile , null , ' ' ) ) ;
3140 }
3241
42+ const direct = new Set ( ) ;
43+ [ 'dependencies' , 'devDependencies' , 'peerDependencies' , 'optionalDependencies' ] . forEach ( ( depType ) => {
44+
45+ if ( ! packageJson [ depType ] ) {
46+ return ;
47+ }
48+
49+ Object . keys ( packageJson [ depType ] ) . forEach ( ( dep ) => direct . add ( dep ) ) ;
50+ } ) ;
51+
3352 const arborist = new Arborist ( { path } ) ;
3453
3554 await arborist . buildIdealTree ( ) ;
@@ -38,11 +57,23 @@ exports.resolve = async ({ packageJson, lockfile }) => {
3857
3958 internals . walk ( arborist . idealTree , ( node ) => {
4059
41- if ( node === arborist . idealTree ) {
60+ if ( node . isRoot ) {
61+ return ;
62+ }
63+
64+ if ( ! dev && node . dev ) {
65+ // only include dev deps when `options.dev` flag is set
66+ return ;
67+ }
68+
69+ if ( ! deep && ! node . parent . isRoot ) {
70+ // only include deep deps when `options.deep` flag is set
4271 return ;
4372 }
4473
45- if ( node . dev ) {
74+ if ( ! deep && ! direct . has ( node . name ) ) {
75+ // only include deep deps when `options.deep` flag is set
76+ // workaround for https://github.com/npm/arborist/issues/60
4677 return ;
4778 }
4879
@@ -56,6 +87,8 @@ exports.resolve = async ({ packageJson, lockfile }) => {
5687 result [ name ] = [ ...map [ name ] ] ;
5788 }
5889
90+ tmpDir . removeCallback ( ) ;
91+
5992 return result ;
6093} ;
6194
@@ -71,23 +104,42 @@ internals.tryLoad = async (loadFile, filename) => {
71104 }
72105} ;
73106
74- exports . detect = async ( { packageJson, loadFile } ) => {
107+ exports . detect = async ( { packageJson, loadFile } , options ) => {
75108
76109 const lockfile = ( await internals . tryLoad ( loadFile , 'package-lock.json' ) ) || ( await internals . tryLoad ( loadFile , 'npm-shrinkwrap.json' ) ) ;
110+ internals . log ( lockfile ? 'Lock file present' : 'Lock file missing - things will be a bit slower' ) ;
77111
78- const versions = await exports . resolve ( { packageJson, lockfile } ) ;
112+ const versions = await internals . resolve ( { packageJson, lockfile } , options ) ;
79113
80114 const support = [ ] ;
115+ const errors = { } ;
116+ let hasErrors = false ;
117+
118+ const packages = Object . keys ( versions ) . sort ( ) ;
119+ const n = packages . length ;
120+
121+ for ( let i = 0 ; i < n ; ++ i ) {
122+
123+ const packageName = packages [ i ] ;
124+ internals . log ( `Resolving dependency ${ i + 1 } of ${ n } : ${ packageName } ` ) ;
81125
82- for ( const packageName of Object . keys ( versions ) ) {
83126 try {
84127 const { result } = await Package . detect ( { packageName } ) ;
85128 support . push ( result ) ;
86129 }
87130 catch ( err ) {
88- console . warn ( `Failed to detect support for ${ packageName } : ${ err && err . message } ` ) ;
131+ hasErrors = true ;
132+ errors [ packageName ] = {
133+ message : Utils . getErrorMessage ( err )
134+ } ;
89135 }
90136 }
91137
92- return { support, versions } ;
138+ const result = { support, versions } ;
139+
140+ if ( hasErrors ) {
141+ result . errors = errors ;
142+ }
143+
144+ return result ;
93145} ;
0 commit comments