1
1
import path from 'path' ;
2
2
import fs from 'fs' ;
3
- import pkgUp from 'eslint-module-utils/pkgUp' ;
4
3
import minimatch from 'minimatch' ;
5
4
import resolve from 'eslint-module-utils/resolve' ;
6
5
import moduleVisitor from 'eslint-module-utils/moduleVisitor' ;
@@ -40,16 +39,43 @@ function extractDepFields(pkg) {
40
39
} ;
41
40
}
42
41
43
- function getPackageDepFields ( packageJsonPath , throwAtRead ) {
44
- if ( ! depFieldCache . has ( packageJsonPath ) ) {
45
- const depFields = extractDepFields ( readJSON ( packageJsonPath , throwAtRead ) ) ;
46
- depFieldCache . set ( packageJsonPath , depFields ) ;
42
+ function getPackageDepFields ( packageDir , considerInParents , requireInDir ) {
43
+ const cacheKey = JSON . stringify ( { packageDir, considerInParents : [ ...considerInParents ] } ) ;
44
+
45
+ if ( ! depFieldCache . has ( cacheKey ) ) {
46
+ // try in the current directory, erroring if the user explicitly specified this directory
47
+ // and reading fails
48
+ const parsedPackage = readJSON ( path . join ( packageDir , 'package.json' ) , requireInDir ) ;
49
+ const depFields = extractDepFields ( parsedPackage || { } ) ;
50
+
51
+ // If readJSON returned nothing, we want to keep searching since the current directory didn't
52
+ // have a package.json. Also keep searching if we're merging in some set of parents dependencies.
53
+ // However, if we're already at the root, stop.
54
+ if ( ( ! parsedPackage || considerInParents . size > 0 ) && packageDir !== path . parse ( packageDir ) . root ) {
55
+ const parentDepFields = getPackageDepFields ( path . dirname ( packageDir ) , considerInParents , false ) ;
56
+
57
+ Object . keys ( depFields ) . forEach ( depsKey => {
58
+ if (
59
+ ( depsKey === 'dependencies' && considerInParents . has ( 'prod' ) ) ||
60
+ ( depsKey === 'devDependencies' && considerInParents . has ( 'dev' ) ) ||
61
+ ( depsKey === 'peerDependencies' && considerInParents . has ( 'peer' ) ) ||
62
+ ( depsKey === 'optionalDependencies' && considerInParents . has ( 'optional' ) )
63
+ ) {
64
+ Object . assign ( depFields [ depsKey ] , parentDepFields [ depsKey ] ) ;
65
+ }
66
+ if ( depsKey === 'bundledDependencies' && considerInParents . has ( 'bundled' ) ) {
67
+ depFields [ depsKey ] = depFields [ depsKey ] . concat ( parentDepFields [ depsKey ] ) ;
68
+ }
69
+ } ) ;
70
+ }
71
+
72
+ depFieldCache . set ( cacheKey , depFields ) ;
47
73
}
48
74
49
- return depFieldCache . get ( packageJsonPath ) ;
75
+ return depFieldCache . get ( cacheKey ) ;
50
76
}
51
77
52
- function getDependencies ( context , packageDir ) {
78
+ function getDependencies ( context , packageDir , considerInParents ) {
53
79
let paths = [ ] ;
54
80
try {
55
81
const packageContent = {
@@ -71,22 +97,24 @@ function getDependencies(context, packageDir) {
71
97
if ( paths . length > 0 ) {
72
98
// use rule config to find package.json
73
99
paths . forEach ( dir => {
74
- const packageJsonPath = path . join ( dir , 'package.json' ) ;
75
- const _packageContent = getPackageDepFields ( packageJsonPath , true ) ;
76
- Object . keys ( packageContent ) . forEach ( depsKey =>
77
- Object . assign ( packageContent [ depsKey ] , _packageContent [ depsKey ] ) ,
78
- ) ;
100
+ const _packageContent = getPackageDepFields ( dir , considerInParents , true ) ;
101
+ Object . keys ( packageContent ) . forEach ( depsKey => {
102
+ if ( depsKey === 'bundledDependencies' ) {
103
+ packageContent [ depsKey ] = packageContent [ depsKey ] . concat ( _packageContent [ depsKey ] ) ;
104
+ } else {
105
+ Object . assign ( packageContent [ depsKey ] , _packageContent [ depsKey ] ) ;
106
+ }
107
+ } ) ;
79
108
} ) ;
80
109
} else {
81
- const packageJsonPath = pkgUp ( {
82
- cwd : context . getPhysicalFilename ? context . getPhysicalFilename ( ) : context . getFilename ( ) ,
83
- normalize : false ,
84
- } ) ;
85
-
86
110
// use closest package.json
87
111
Object . assign (
88
112
packageContent ,
89
- getPackageDepFields ( packageJsonPath , false ) ,
113
+ getPackageDepFields (
114
+ path . dirname ( context . getPhysicalFilename ? context . getPhysicalFilename ( ) : context . getFilename ( ) ) ,
115
+ considerInParents ,
116
+ false ,
117
+ ) ,
90
118
) ;
91
119
}
92
120
@@ -275,6 +303,21 @@ module.exports = {
275
303
'packageDir' : { 'type' : [ 'string' , 'array' ] } ,
276
304
'includeInternal' : { 'type' : [ 'boolean' ] } ,
277
305
'includeTypes' : { 'type' : [ 'boolean' ] } ,
306
+ 'considerInParents' : {
307
+ 'type' : 'array' ,
308
+ 'uniqueItems' : true ,
309
+ 'additionalItems' : false ,
310
+ 'items' : {
311
+ 'type' : 'string' ,
312
+ 'enum' : [
313
+ 'prod' ,
314
+ 'dev' ,
315
+ 'peer' ,
316
+ 'bundled' ,
317
+ 'optional' ,
318
+ ] ,
319
+ } ,
320
+ } ,
278
321
} ,
279
322
'additionalProperties' : false ,
280
323
} ,
@@ -284,7 +327,7 @@ module.exports = {
284
327
create ( context ) {
285
328
const options = context . options [ 0 ] || { } ;
286
329
const filename = context . getPhysicalFilename ? context . getPhysicalFilename ( ) : context . getFilename ( ) ;
287
- const deps = getDependencies ( context , options . packageDir ) || extractDepFields ( { } ) ;
330
+ const deps = getDependencies ( context , options . packageDir , new Set ( options . considerInParents || [ ] ) ) || extractDepFields ( { } ) ;
288
331
289
332
const depsOptions = {
290
333
allowDevDeps : testConfig ( options . devDependencies , filename ) !== false ,
0 commit comments