@@ -7,6 +7,7 @@ const fs = require('fs');
7
7
const glob = require ( 'glob' ) ;
8
8
const packages = require ( '../../lib/packages' ) ;
9
9
const path = require ( 'path' ) ;
10
+ const _ = require ( 'lodash' ) ;
10
11
11
12
12
13
const IMPORT_RE = / ( ^ | \n ) \s * i m p o r t \b (?: .| \n ) * ?\' [ ^ \' ] * \' / g;
@@ -28,6 +29,18 @@ const ANGULAR_PACKAGES = [
28
29
'@angular/core'
29
30
] ;
30
31
32
+ let exitCode = 0 ;
33
+
34
+ const depsInfo = validateDependenciesPerPackage ( packages ) ;
35
+
36
+ validateRootPackageJson ( depsInfo . allSourceDeps ) ;
37
+
38
+ checkDependenciesConflictAcrossPackages ( depsInfo . allDeclaredDepsMap ) ;
39
+
40
+ process . exit ( exitCode ) ;
41
+
42
+
43
+ // utils
31
44
32
45
function listImportedModules ( source ) {
33
46
const imports = source . match ( IMPORT_RE ) ;
@@ -40,7 +53,7 @@ function listImportedModules(source) {
40
53
. filter ( x => ! ! x )
41
54
. filter ( modulePath => modulePath [ 0 ] != '.' )
42
55
. map ( fullImportPath => {
43
- if ( fullImportPath [ 0 ] == '@' ) {
56
+ if ( fullImportPath [ 0 ] === '@' ) {
44
57
// Need to get the scope as well.
45
58
return fullImportPath . split ( '/' ) . slice ( 0 , 2 ) . join ( '/' ) ;
46
59
} else {
@@ -60,7 +73,7 @@ function listRequiredModules(source) {
60
73
. filter ( x => ! ! x )
61
74
. filter ( modulePath => modulePath [ 0 ] != '.' )
62
75
. map ( fullImportPath => {
63
- if ( fullImportPath [ 0 ] == '@' ) {
76
+ if ( fullImportPath [ 0 ] === '@' ) {
64
77
// Need to get the scope as well.
65
78
return fullImportPath . split ( '/' ) . slice ( 0 , 2 ) . join ( '/' ) ;
66
79
} else {
@@ -70,7 +83,7 @@ function listRequiredModules(source) {
70
83
}
71
84
72
85
function reportMissingDependencies ( missingDeps ) {
73
- if ( missingDeps . length == 0 ) {
86
+ if ( missingDeps . length === 0 ) {
74
87
console . log ( chalk . green ( ' no dependency missing from package.json.' ) ) ;
75
88
} else {
76
89
console . log ( chalk . yellow ( ` ${ missingDeps . length } missing from package.json:` ) ) ;
@@ -80,7 +93,7 @@ function reportMissingDependencies(missingDeps) {
80
93
}
81
94
82
95
function reportExcessiveDependencies ( overDeps ) {
83
- if ( overDeps . length == 0 ) {
96
+ if ( overDeps . length === 0 ) {
84
97
console . log ( chalk . green ( ' no excessive dependencies in package.json.' ) ) ;
85
98
} else {
86
99
console . log ( chalk . yellow ( ` ${ overDeps . length } excessive dependencies in package.json:` ) ) ;
@@ -89,63 +102,114 @@ function reportExcessiveDependencies(overDeps) {
89
102
}
90
103
}
91
104
92
- let exitCode = 0 ;
93
- const overallDeps = [ ] ;
94
- for ( const packageName of Object . keys ( packages ) ) {
95
- console . log ( chalk . green ( `Reading dependencies of "${ packageName } ".` ) ) ;
105
+ function reportInconsistentDepsDependencies ( inconsistentDeps ) {
106
+ if ( inconsistentDeps . length === 0 ) {
107
+ console . log ( chalk . green ( ' no inconsistentDeps dependencies across packages.' ) ) ;
108
+ } else {
109
+ console . log ( chalk . yellow ( ` ${ inconsistentDeps . length } inconsistent dependencies found:` ) ) ;
110
+ inconsistentDeps . forEach ( arr => console . log ( ` ${ arr . join ( ' vs ' ) } ` ) ) ;
111
+ exitCode = 0 ;
112
+ }
113
+ }
96
114
115
+ function retrieveDependencyMapFromPackageSource ( packageName ) {
97
116
const allSources = glob . sync ( path . join ( __dirname , '../../packages/' , packageName , '**/*' ) )
98
117
. filter ( p => p . match ( / \. ( j s | t s ) $ / ) )
99
118
. filter ( p => ! p . match ( / \. s p e c \. / ) )
100
119
. filter ( p => ! p . match ( / \/ b l u e p r i n t s \/ / ) ) ;
101
120
102
- const importMap = { } ;
103
- allSources . forEach ( function ( filePath ) {
121
+ return allSources . reduce ( function ( importMap , filePath ) {
104
122
const source = fs . readFileSync ( filePath , 'utf8' ) ;
105
123
106
124
listImportedModules ( source )
107
125
. forEach ( modulePath => importMap [ modulePath ] = true ) ;
108
126
listRequiredModules ( source )
109
127
. forEach ( modulePath => importMap [ modulePath ] = true ) ;
110
- } ) ;
111
128
112
- const dependencies = Object . keys ( importMap )
113
- // Filter out the node packages that should not be depended on.
114
- . filter ( x => NODE_PACKAGES . indexOf ( x ) == - 1 ) ;
115
- overallDeps . push ( ...dependencies ) ;
129
+ return importMap ;
130
+ } , { } ) ;
131
+ }
132
+
133
+ function validateDependenciesPerPackage ( packages ) {
134
+ const allSourceDeps = [ ] ;
135
+ const allDeclaredDepsMap = { } ;
136
+
137
+ for ( const packageName of Object . keys ( packages ) ) {
138
+ console . log ( chalk . blue ( `Reading dependencies of "${ packageName } ".` ) ) ;
116
139
117
- console . log ( chalk . green ( ` found ${ dependencies . length } dependencies...` ) ) ;
118
- const packageJson = JSON . parse ( fs . readFileSync ( packages [ packageName ] . packageJson , 'utf8' ) ) ;
119
- const allDeps = [ ]
120
- . concat ( Object . keys ( packageJson [ 'dependencies' ] || { } ) )
121
- . concat ( Object . keys ( packageJson [ 'devDependencies' ] || { } ) )
122
- . concat ( Object . keys ( packageJson [ 'peerDependencies' ] || { } ) ) ;
140
+ const importMap = retrieveDependencyMapFromPackageSource ( packageName )
123
141
124
- const missingDeps = dependencies . filter ( d => allDeps . indexOf ( d ) == - 1 ) ;
125
- reportMissingDependencies ( missingDeps ) ;
142
+ const dependencies = Object . keys ( importMap )
143
+ // Filter out the node packages that should not be depended on.
144
+ . filter ( x => NODE_PACKAGES . indexOf ( x ) == - 1 ) ;
145
+ allSourceDeps . push ( ...dependencies ) ;
126
146
127
- const overDeps = allDeps . filter ( d => dependencies . indexOf ( d ) == - 1 )
128
- . filter ( x => ANGULAR_PACKAGES . indexOf ( x ) == - 1 ) ;
129
- reportExcessiveDependencies ( overDeps ) ;
147
+ console . log ( chalk . green ( ` found ${ dependencies . length } dependencies...` ) ) ;
130
148
131
- console . log ( '' ) ;
149
+ const packageJson = JSON . parse ( fs . readFileSync ( packages [ packageName ] . packageJson , 'utf8' ) ) ;
150
+
151
+ const DeclaredDepsMap = Object . assign (
152
+ { } ,
153
+ packageJson [ 'dependencies' ] || { } ,
154
+ packageJson [ 'devDependencies' ] || { } ,
155
+ packageJson [ 'peerDependencies' ] || { }
156
+ ) ;
157
+ allDeclaredDepsMap [ packageName ] = DeclaredDepsMap ;
158
+ const declaredDeps = Object . keys ( DeclaredDepsMap ) ;
159
+
160
+ const missingDeps = dependencies . filter ( d => declaredDeps . indexOf ( d ) === - 1 ) ;
161
+ reportMissingDependencies ( missingDeps ) ;
162
+
163
+ const excessiveDeps = declaredDeps . filter ( d => dependencies . indexOf ( d ) === - 1 )
164
+ . filter ( x => ANGULAR_PACKAGES . indexOf ( x ) === - 1 ) ;
165
+ reportExcessiveDependencies ( excessiveDeps ) ;
166
+ }
167
+
168
+ return {
169
+ allDeclaredDepsMap,
170
+ allSourceDeps
171
+ } ;
132
172
}
133
173
134
- console . log ( chalk . green ( 'Validating root package. [devDependencies ignored]' ) ) ;
135
- const rootPackagePath = path . join ( __dirname , '../../package.json' ) ;
136
- const rootPackageJson = JSON . parse ( fs . readFileSync ( rootPackagePath , 'utf8' ) ) ;
137
- // devDependencies are ignored
138
- const allRootDeps = [ ]
174
+ function validateRootPackageJson ( overallDeps ) {
175
+ console . log ( chalk . blue ( 'Validating root package. [devDependencies ignored]' ) ) ;
176
+
177
+ const rootPackagePath = path . join ( __dirname , '../../package.json' ) ;
178
+ const rootPackageJson = JSON . parse ( fs . readFileSync ( rootPackagePath , 'utf8' ) ) ;
179
+
180
+ // devDependencies are ignored
181
+ const allRootDeps = [ ]
139
182
. concat ( Object . keys ( rootPackageJson [ 'dependencies' ] || { } ) )
140
183
. concat ( Object . keys ( rootPackageJson [ 'peerDependencies' ] || { } ) ) ;
141
184
142
- const internalPackages = Object . keys ( packages ) ;
143
- const missingRootDeps = overallDeps . filter ( d => allRootDeps . indexOf ( d ) == - 1 )
144
- . filter ( d => internalPackages . indexOf ( d ) == - 1 ) ;
145
- reportMissingDependencies ( missingRootDeps ) ;
185
+ const internalPackages = Object . keys ( packages ) ;
186
+ const missingRootDeps = overallDeps . filter ( d => allRootDeps . indexOf ( d ) = == - 1 )
187
+ . filter ( d => internalPackages . indexOf ( d ) = == - 1 ) ;
188
+ reportMissingDependencies ( missingRootDeps ) ;
146
189
147
- const overRootDeps = allRootDeps . filter ( d => overallDeps . indexOf ( d ) == - 1 )
148
- . filter ( x => ANGULAR_PACKAGES . indexOf ( x ) == - 1 ) ;
149
- reportExcessiveDependencies ( overRootDeps ) ;
190
+ const overRootDeps = allRootDeps . filter ( d => overallDeps . indexOf ( d ) === - 1 )
191
+ . filter ( x => ANGULAR_PACKAGES . indexOf ( x ) === - 1 ) ;
192
+ reportExcessiveDependencies ( overRootDeps ) ;
193
+ }
150
194
151
- process . exit ( exitCode ) ;
195
+ function checkDependenciesConflictAcrossPackages ( allDeclaredDepsMap ) {
196
+ console . log ( chalk . blue ( 'Validating packages\' dependencies conflict.' ) ) ;
197
+
198
+ const allDeclaredDeps = Object . keys ( allDeclaredDepsMap )
199
+ . reduce ( ( collect , packageName ) => collect . concat ( Object . keys ( allDeclaredDepsMap [ packageName ] ) ) , [ ] ) ;
200
+
201
+ const inconsistentDeps = _ . uniq ( allDeclaredDeps ) . reduce ( function ( collect , dep ) {
202
+ const test = _ ( allDeclaredDepsMap )
203
+ . map ( ( map , name ) => map [ dep ] ? [ name , `${ dep } @${ map [ dep ] } ` ] : null )
204
+ . compact ( )
205
+ . uniqBy ( 1 )
206
+ . value ( ) ;
207
+ if ( test . length > 1 ) {
208
+ collect . push ( test . map ( pair => `[${ pair [ 0 ] } ]: ${ pair [ 1 ] } ` ) ) ;
209
+ }
210
+
211
+ return collect ;
212
+ } , [ ] ) ;
213
+
214
+ reportInconsistentDepsDependencies ( inconsistentDeps ) ;
215
+ }
0 commit comments