8
8
9
9
const child_process = require ( 'child_process' ) ;
10
10
const fs = require ( 'fs' ) ;
11
+ const path = require ( 'path' ) ;
11
12
12
13
const exec = function ( cmd ) {
13
14
return new Promise ( function ( resolve , reject ) {
@@ -33,7 +34,16 @@ const blocked_statements = [
33
34
'from \\\'rxjs/Rx\\\'' ,
34
35
] ;
35
36
37
+ // Retrieves all scope packages dynamically from the source.
38
+ // Developers shouldn't be able to import from other scope packages by using relative paths.
39
+ const componentFolders = fs
40
+ . readdirSync ( `${ __dirname } /../../src/components` )
41
+ . map ( componentName => `src/components/${ componentName } ` ) ;
42
+
43
+ const scopePackages = [ 'src/core' ] . concat ( componentFolders ) ;
44
+
36
45
const blockedRegex = new RegExp ( blocked_statements . join ( '|' ) , 'g' ) ;
46
+ const importRegex = / f r o m \s + ' ( .* ) ' ; / g;
37
47
38
48
/**
39
49
* Find the fork point between HEAD of the current branch, and master.
@@ -85,6 +95,63 @@ function findChangedFiles() {
85
95
} ) ;
86
96
}
87
97
98
+ /**
99
+ * Checks the line for any relative imports of a scope package, which should be imported by using
100
+ * the scope package name instead of the relative path.
101
+ * @param fileName Filename to validate the path
102
+ * @param line Line to be checked.
103
+ */
104
+ function isRelativeScopeImport ( fileName , line ) {
105
+ let importMatch = importRegex . exec ( line ) ;
106
+
107
+ // We have to reset the last index of the import regex, otherwise we
108
+ // would have incorrect matches in the next execution.
109
+ importRegex . lastIndex = 0 ;
110
+
111
+ // Skip the check if the current line doesn't match any imports.
112
+ if ( ! importMatch ) {
113
+ return false ;
114
+ }
115
+
116
+ let importPath = importMatch [ 1 ] ;
117
+
118
+ // Skip the check when the import doesn't start with a dot, because the line
119
+ // isn't importing any file relatively. Also applies to scope packages starting
120
+ // with `@`.
121
+ if ( ! importPath . startsWith ( '.' ) ) {
122
+ return false ;
123
+ }
124
+
125
+ // Transform the relative import path into an absolute path.
126
+ importPath = path . resolve ( path . dirname ( fileName ) , importPath ) ;
127
+
128
+ let currentScope = findScope ( fileName ) ;
129
+ let importScope = findScope ( importPath ) ;
130
+
131
+ if ( currentScope !== importScope ) {
132
+ // Transforms the invalid import statement into a correct import statement, which uses the scope package.
133
+ let scopeImport = `@angular2-material/${ path . basename ( importScope ) } /${ path . relative ( importScope , importPath ) } ` ;
134
+
135
+ return {
136
+ currentScope : currentScope ,
137
+ importScope : importScope ,
138
+ invalidStatement : importMatch [ 0 ] ,
139
+ scopeImportPath : scopeImport
140
+ }
141
+ }
142
+
143
+ return false ;
144
+
145
+ function findScope ( filePath ) {
146
+ // Normalize the filePath as well, to avoid issues with the different environments path delimiter.
147
+ filePath = path . normalize ( filePath ) ;
148
+
149
+ // Iterate through all scopes and try to find them inside of the file path.
150
+ return scopePackages . filter ( scope => filePath . indexOf ( path . normalize ( scope ) ) !== - 1 ) . pop ( ) ;
151
+ }
152
+
153
+ }
154
+
88
155
89
156
// Find all files, check for errors, and output every errors found.
90
157
findChangedFiles ( )
@@ -116,23 +183,35 @@ findChangedFiles()
116
183
content . forEach ( function ( line ) {
117
184
ln ++ ;
118
185
119
- let m = line . match ( blockedRegex ) ;
120
- if ( m ) {
186
+ let matches = line . match ( blockedRegex ) ;
187
+ let isScopeImport = isRelativeScopeImport ( fileName , line ) ;
188
+
189
+ if ( matches || isScopeImport ) {
121
190
// Accumulate all errors at once.
122
- errors . push ( {
191
+ let error = {
123
192
fileName : fileName ,
124
193
lineNumber : ln ,
125
- statement : m [ 0 ]
126
- } ) ;
194
+ statement : matches && matches [ 0 ] || isScopeImport . invalidStatement
195
+ } ;
196
+
197
+ if ( isScopeImport ) {
198
+ error . message =
199
+ ' You are using an import statement, which imports a file from another scope package.\n' +
200
+ ` Please import the file by using the following path: ${ isScopeImport . scopeImportPath } ` ;
201
+ }
202
+
203
+ errors . push ( error ) ;
127
204
}
128
205
} ) ;
129
206
return errors ;
130
207
} , [ ] ) ;
131
208
} )
132
209
. then ( errors => {
133
210
if ( errors . length > 0 ) {
134
- console . error ( 'Error: You are using a statement in your commit, which is not allowed.' ) ;
211
+ console . error ( 'Error: You are using a statement in your commit, which is not allowed.\n' ) ;
212
+
135
213
errors . forEach ( entry => {
214
+ if ( entry . message ) console . error ( entry . message ) ;
136
215
console . error ( ` ${ entry . fileName } @${ entry . lineNumber } , Statement: ${ entry . statement } .\n` ) ;
137
216
} ) ;
138
217
0 commit comments