test-forbidden-regex
Version:
Test helper for testing forbidden regex
160 lines (140 loc) • 4.27 kB
text/typescript
import 'colors';
import * as fs from 'fs';
import * as path from 'path';
/* eslint-disable @typescript-eslint/no-empty-function */
const DEF_CB = () => {};
export function testForbiddenRegex(
regularExpressions: RegExp | RegExp[],
folderPath: string[] | string = 'src',
errorText = 'Error',
cb: (errors?: string | string[] | { message: string }) => void = DEF_CB,
): void {
const basePath = process.cwd();
const folderPathArr =
typeof folderPath === 'string' ? [folderPath] : folderPath;
const srcPath = path.join(basePath, ...folderPathArr);
const errors: string[] = [];
let counter = 0;
const regexs = Array.isArray(regularExpressions)
? regularExpressions
: [regularExpressions];
const scanFile = (pathStr: string): Promise<string | false> => {
return new Promise((resolve, reject) => {
fs.readFile(pathStr, 'utf8', function (err, contents) {
if (err) {
reject(err);
return;
}
const localErrors: string[] = [];
regexs.forEach((regex) => {
if (contents.match(regex)) {
localErrors.push(
'File file://' +
`${pathStr}`.underline +
' contains ' +
`${regex}`.red +
'. \n' +
`${errorText
.replace('$folder', folderPathArr.join('/'))
.replace('$file', pathStr)}`.yellow,
);
}
});
if (localErrors.length) {
resolve(localErrors.join(`\n`));
} else {
resolve(false);
}
});
});
};
const scanDirectory = (pathStr: string): Promise<string[]> => {
return new Promise((resolve, reject) => {
fs.readdir(pathStr, function (err, files) {
if (err) {
reject(err);
return;
}
resolve(toPaths(pathStr, files));
});
});
};
const toPaths = (directory: string, files: string[]): string[] => {
return files.map((el) => path.resolve(directory, el));
};
async function scanSrc(directoryPath: string) {
const files = await scanDirectory(directoryPath);
while (files.length) {
const nestedPath = files.pop();
if (fs.lstatSync(nestedPath).isDirectory()) {
files.push(...(await scanDirectory(nestedPath)));
} else {
const fileExtension = path.extname(nestedPath);
if (['.js', '.jsx', '.ts', '.tsx'].includes(fileExtension)) {
counter++;
const error = await scanFile(nestedPath);
if (error) {
errors.push(error);
}
}
}
}
}
scanSrc(srcPath).then(() => {
if (errors.length) {
const finalError =
`\n ${errors.length} Error${
errors.length === 1 ? ' was' : 's where'
} found in ${counter} scanned file${counter > 1 ? 's' : ''}:\n\n`.red +
errors.join(`\n`);
if (cb) {
cb(finalError);
} else {
console.error(finalError);
}
process.exitCode = 1;
} else {
if (cb) {
cb();
} else {
console.info(
` ${counter} Files was scanned. No ${regexs.join(', ')} Errors\n`
.green,
);
}
}
});
}
const messageText = (forbiddenImport: string): string =>
`We could not use `.yellow +
forbiddenImport.red +
` inside ./$folder folder. Please, move it according to project docs`.yellow;
export const noImportsInFolder = (
folder: string,
pattern: RegExp | string | Array<RegExp | string>,
noSrc = false,
): ((done) => void) => {
const folderPath = folder.split('/');
if (folderPath[0] !== 'src' && !noSrc) {
folderPath.unshift('src');
}
const patternArr: Array<string | RegExp> = Array.isArray(pattern)
? pattern
: [pattern];
const patternRegExpArr: RegExp[] = patternArr.map<RegExp>((p): RegExp => {
if (typeof p === 'string') {
return new RegExp(p, 'g');
}
return p;
});
return (done): void => {
testForbiddenRegex(
patternRegExpArr,
folderPath,
messageText(patternArr.map((p) => `import ... from ${p}`).join(', ')),
done,
);
};
};
export const relativeImportStartedFromTwoDots =
/import (.* from )?['"]\.\.\//gs;