in ng-dev/ts-circular-dependencies/index.ts [64:146]
export function main(
approve: boolean,
config: CircularDependenciesTestConfig,
printWarnings: boolean,
): number {
const {baseDir, goldenFile, glob, resolveModule, approveCommand} = config;
const analyzer = new Analyzer(resolveModule);
const cycles: ReferenceChain[] = [];
const checkedNodes = new WeakSet<ts.SourceFile>();
globSync(glob, {absolute: true, ignore: ['**/node_modules/**']}).forEach((filePath) => {
const sourceFile = analyzer.getSourceFile(filePath);
cycles.push(...analyzer.findCycles(sourceFile, checkedNodes));
});
const actual = convertReferenceChainToGolden(cycles, baseDir);
info(green(` Current number of cycles: ${yellow(cycles.length.toString())}`));
if (approve) {
writeFileSync(goldenFile, JSON.stringify(actual, null, 2));
info(green('✅ Updated golden file.'));
return 0;
} else if (!existsSync(goldenFile)) {
error(red(`❌ Could not find golden file: ${goldenFile}`));
return 1;
}
const warningsCount = analyzer.unresolvedFiles.size + analyzer.unresolvedModules.size;
// By default, warnings for unresolved files or modules are not printed. This is because
// it's common that third-party modules are not resolved/visited. Also generated files
// from the View Engine compiler (i.e. factories, summaries) cannot be resolved.
if (printWarnings && warningsCount !== 0) {
info(yellow('⚠ The following imports could not be resolved:'));
Array.from(analyzer.unresolvedModules)
.sort()
.forEach((specifier) => info(` • ${specifier}`));
analyzer.unresolvedFiles.forEach((value, key) => {
info(` • ${getRelativePath(baseDir, key)}`);
value.sort().forEach((specifier) => info(` ${specifier}`));
});
} else {
info(yellow(`⚠ ${warningsCount} imports could not be resolved.`));
info(yellow(` Please rerun with "--warnings" to inspect unresolved imports.`));
}
const expected = JSON.parse(readFileSync(goldenFile, 'utf8')) as Golden;
const {fixedCircularDeps, newCircularDeps} = compareGoldens(actual, expected);
const isMatching = fixedCircularDeps.length === 0 && newCircularDeps.length === 0;
if (isMatching) {
info(green('✅ Golden matches current circular dependencies.'));
return 0;
}
error(red('❌ Golden does not match current circular dependencies.'));
if (newCircularDeps.length !== 0) {
error(yellow(` New circular dependencies which are not allowed:`));
newCircularDeps.forEach((c) => error(` • ${convertReferenceChainToString(c)}`));
error();
}
if (fixedCircularDeps.length !== 0) {
error(yellow(` Fixed circular dependencies that need to be removed from the golden:`));
fixedCircularDeps.forEach((c) => error(` • ${convertReferenceChainToString(c)}`));
info(
yellow(
`\n Total: ${newCircularDeps.length} new cycle(s), ${fixedCircularDeps.length} fixed cycle(s). \n`,
),
);
if (approveCommand) {
info(yellow(` Please approve the new golden with: ${approveCommand}`));
} else {
info(
yellow(
` Please update the golden. The following command can be ` +
`run: yarn ts-circular-deps approve ${getRelativePath(process.cwd(), goldenFile)}.`,
),
);
}
}
return 1;
}