Skip to content

Commit

Permalink
feat(lint): extend circular dependency check
Browse files Browse the repository at this point in the history
  • Loading branch information
skydever authored and vsavkin committed Mar 29, 2018
1 parent 4e9d52a commit fff9659
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,56 @@ describe('Enforce Module Boundaries', () => {
'Circular dependency between "anotherlib" and "mylib" detected'
);
});

it('should error when circular dependency detected (indirect)', () => {
const failures = runRule(
{},
`${process.cwd()}/proj/libs/mylib/src/main.ts`,
'import "@mycompany/badcirclelib"',
[
{
name: 'mylib',
root: 'libs/mylib/src',
type: ProjectType.lib,
tags: [],
files: [`libs/mylib/src/main.ts`]
},
{
name: 'anotherlib',
root: 'libs/anotherlib/src',
type: ProjectType.lib,
tags: [],
files: [`libs/anotherlib/src/main.ts`]
},
{
name: 'badcirclelib',
root: 'libs/badcirclelib/src',
type: ProjectType.lib,
tags: [],
files: [`libs/badcirclelib/src/main.ts`]
},
{
name: 'myapp',
root: 'apps/myapp/src',
type: ProjectType.app,
tags: [],
files: [`apps/myapp/index.ts`]
}
],
{
mylib: [
{ projectName: 'badcirclelib', type: DependencyType.es6Import }
],
badcirclelib: [
{ projectName: 'anotherlib', type: DependencyType.es6Import }
],
anotherlib: [{ projectName: 'mylib', type: DependencyType.es6Import }]
}
);
expect(failures[0].getFailure()).toEqual(
'Circular dependency between "mylib" and "badcirclelib" detected'
);
});
});

function runRule(
Expand Down
24 changes: 21 additions & 3 deletions packages/schematics/src/tslint/nxEnforceModuleBoundariesRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,27 @@ class EnforceModuleBoundariesWalker extends Lint.RuleWalker {
targetProject: ProjectNode
): boolean {
if (!this.deps[targetProject.name]) return false;
return this.deps[targetProject.name].some(
dep => dep.projectName == sourceProject.name
);
return this.isDependingOn(targetProject.name, sourceProject.name);
}

private isDependingOn(
sourceProjectName: string,
targetProjectName: string,
done: { [projectName: string]: boolean } = {}
): boolean {
if (done[sourceProjectName]) return false;
if (!this.deps[sourceProjectName]) return false;
return this.deps[sourceProjectName]
.map(
dep =>
dep.projectName === targetProjectName
? true
: this.isDependingOn(dep.projectName, targetProjectName, {
...done,
[`${sourceProjectName}`]: true
})
)
.some(result => result);
}

private onlyLoadChildren(
Expand Down

0 comments on commit fff9659

Please sign in to comment.