diff --git a/packages/schematics/src/tslint/nxEnforceModuleBoundariesRule.spec.ts b/packages/schematics/src/tslint/nxEnforceModuleBoundariesRule.spec.ts index f97a8fdd4b..fd5421a696 100644 --- a/packages/schematics/src/tslint/nxEnforceModuleBoundariesRule.spec.ts +++ b/packages/schematics/src/tslint/nxEnforceModuleBoundariesRule.spec.ts @@ -321,6 +321,41 @@ describe('Enforce Module Boundaries', () => { ); expect(failures[0].getFailure()).toEqual('imports of apps are forbidden'); }); + + it('should error when circular dependency detected', () => { + const failures = runRule( + {}, + `${process.cwd()}/proj/libs/anotherlib/src/main.ts`, + 'import "@mycompany/mylib"', + [ + { + 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: 'myapp', + root: 'apps/myapp/src', + type: ProjectType.app, + tags: [], + files: [`apps/myapp/index.ts`] + } + ], + { + mylib: [{ projectName: 'anotherlib', type: DependencyType.es6Import }] + } + ); + expect(failures[0].getFailure()).toEqual('Circular dependency between \"anotherlib\" and \"mylib\" detected'); + }); }); function runRule( diff --git a/packages/schematics/src/tslint/nxEnforceModuleBoundariesRule.ts b/packages/schematics/src/tslint/nxEnforceModuleBoundariesRule.ts index b050664b87..24d373445a 100644 --- a/packages/schematics/src/tslint/nxEnforceModuleBoundariesRule.ts +++ b/packages/schematics/src/tslint/nxEnforceModuleBoundariesRule.ts @@ -98,6 +98,13 @@ class EnforceModuleBoundariesWalker extends Lint.RuleWalker { return; } + // check for circular dependency + if (this.isCircular(sourceProject, targetProject)) { + const error = `Circular dependency between "${sourceProject.name}" and "${targetProject.name}" detected`; + this.addFailureAt(node.getStart(), node.getWidth(), error); + return; + } + // same project => allow if (sourceProject === targetProject) { super.visitImportDeclaration(node); @@ -146,6 +153,11 @@ class EnforceModuleBoundariesWalker extends Lint.RuleWalker { super.visitImportDeclaration(node); } + private isCircular(sourceProject: ProjectNode, targetProject: ProjectNode): boolean { + if (!this.deps[targetProject.name]) return false; + return this.deps[targetProject.name].some(dep => dep.projectName == sourceProject.name); + } + private onlyLoadChildren(sourceProjectName: string, targetProjectName: string, visited: string[]) { if (visited.indexOf(sourceProjectName) > -1) return false; return (this.deps[sourceProjectName] || []).filter(d => {