Skip to content

Commit 819c9ef

Browse files
devversionhansl
authored andcommitted
chore(): forbidden identifiers check for relative scope imports. (#764)
1 parent a4c9f1d commit 819c9ef

File tree

1 file changed

+85
-6
lines changed

1 file changed

+85
-6
lines changed

scripts/ci/forbidden-identifiers.js

Lines changed: 85 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
const child_process = require('child_process');
1010
const fs = require('fs');
11+
const path = require('path');
1112

1213
const exec = function(cmd) {
1314
return new Promise(function(resolve, reject) {
@@ -33,7 +34,16 @@ const blocked_statements = [
3334
'from \\\'rxjs/Rx\\\'',
3435
];
3536

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+
3645
const blockedRegex = new RegExp(blocked_statements.join('|'), 'g');
46+
const importRegex = /from\s+'(.*)';/g;
3747

3848
/**
3949
* Find the fork point between HEAD of the current branch, and master.
@@ -85,6 +95,63 @@ function findChangedFiles() {
8595
});
8696
}
8797

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+
88155

89156
// Find all files, check for errors, and output every errors found.
90157
findChangedFiles()
@@ -116,23 +183,35 @@ findChangedFiles()
116183
content.forEach(function(line) {
117184
ln++;
118185

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) {
121190
// Accumulate all errors at once.
122-
errors.push({
191+
let error = {
123192
fileName: fileName,
124193
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);
127204
}
128205
});
129206
return errors;
130207
}, []);
131208
})
132209
.then(errors => {
133210
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+
135213
errors.forEach(entry => {
214+
if (entry.message) console.error(entry.message);
136215
console.error(` ${entry.fileName}@${entry.lineNumber}, Statement: ${entry.statement}.\n`);
137216
});
138217

0 commit comments

Comments
 (0)