Skip to content

Commit

Permalink
feat(core): add support for notDependOnLibsWithTags module boundaries (
Browse files Browse the repository at this point in the history
…#592)

fixes #564
  • Loading branch information
DerStimmler authored Jan 31, 2023
1 parent cdc9c09 commit 483086b
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 5 deletions.
102 changes: 100 additions & 2 deletions packages/core/src/tasks/check-module-boundaries.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Tree, writeJson } from '@nrwl/devkit';
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';

import * as ESLintNamespace from 'eslint';
import * as fastGlob from 'fast-glob';
import { vol } from 'memfs';

import {
CONFIG_FILE_PATH,
Expand All @@ -21,7 +22,7 @@ const MOCK_BOUNDARIES: ModuleBoundaries = [
sourceTag: 'a',
},
{
onlyDependOnLibsWithTags: ['b', 'shared'],
notDependOnLibsWithTags: ['a', 'shared'],
sourceTag: 'b',
},
{
Expand Down Expand Up @@ -74,7 +75,32 @@ describe('load-module-boundaries', () => {
});
});

// eslint-disable-next-line @typescript-eslint/no-var-requires
jest.mock('fs', () => require('memfs').fs);

describe('enforce-module-boundaries', () => {
beforeEach(() => {
const appTree = createTreeWithEmptyWorkspace();
jest.spyOn(ESLintNamespace, 'ESLint').mockReturnValue({
calculateConfigForFile: jest.fn().mockResolvedValue({
rules: {
'@nrwl/nx/enforce-module-boundaries': [
1,
{ depConstraints: MOCK_BOUNDARIES },
],
},
}),
} as unknown as ESLintNamespace.ESLint);
writeJson<NxDotnetConfig>(appTree, CONFIG_FILE_PATH, {
nugetPackages: {},
});
});

afterEach(() => {
jest.resetAllMocks();
vol.reset();
});

it('should exit early if no tags on project', async () => {
const spy = jest.spyOn(checkModule, 'loadModuleBoundaries');
const results = await checkModuleBoundariesForProject('a', {
Expand All @@ -87,4 +113,76 @@ describe('enforce-module-boundaries', () => {
expect(spy).not.toHaveBeenCalled();
expect(results).toHaveLength(0);
});

it('should find violations with onlyDependOnLibsWithTags', async () => {
const globResults = ['libs/a/a.csproj'];
jest.spyOn(fastGlob, 'sync').mockImplementation(() => globResults);

vol.fromJSON({
'libs/a/a.csproj':
'<Project Sdk="Microsoft.NET.Sdk.Web"><ItemGroup><ProjectReference Include="..\\..\\libs\\ui\\ui.csproj" /></ItemGroup></Project>',
});

const results = await checkModuleBoundariesForProject('a', {
a: {
tags: ['a'],
targets: { ui: {} },
root: 'libs/a',
},
ui: {
tags: ['ui'],
targets: {},
root: 'libs/ui',
},
});
expect(results).toHaveLength(1);
});

it('should find violations with notDependOnLibsWithTags', async () => {
const globResults = ['libs/b/b.csproj'];
jest.spyOn(fastGlob, 'sync').mockImplementation(() => globResults);

vol.fromJSON({
'libs/b/b.csproj':
'<Project Sdk="Microsoft.NET.Sdk.Web"><ItemGroup><ProjectReference Include="..\\..\\libs\\a\\a.csproj" /></ItemGroup></Project>',
});

const results = await checkModuleBoundariesForProject('b', {
a: {
tags: ['a'],
targets: {},
root: 'libs/a',
},
b: {
tags: ['b'],
targets: { a: {} },
root: 'libs/b',
},
});
expect(results).toHaveLength(1);
});

it('should pass without violations', async () => {
const globResults = ['libs/a/a.csproj'];
jest.spyOn(fastGlob, 'sync').mockImplementation(() => globResults);

vol.fromJSON({
'libs/a/a.csproj':
'<Project Sdk="Microsoft.NET.Sdk.Web"><ItemGroup><ProjectReference Include="..\\..\\libs\\shared\\shared.csproj" /></ItemGroup></Project>',
});

const results = await checkModuleBoundariesForProject('a', {
a: {
tags: ['a'],
targets: { shared: {} },
root: 'libs/a',
},
shared: {
tags: ['shared'],
targets: {},
root: 'libs/shared',
},
});
expect(results).toHaveLength(0);
});
});
9 changes: 7 additions & 2 deletions packages/core/src/tasks/check-module-boundaries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ export async function checkModuleBoundariesForProject(
const configuredConstraints = await loadModuleBoundaries(projectRoot);
const relevantConstraints = configuredConstraints.filter(
(x) =>
tags.includes(x.sourceTag) && !x.onlyDependOnLibsWithTags.includes('*'),
tags.includes(x.sourceTag) &&
(!x.onlyDependOnLibsWithTags?.includes('*') ||
x.notDependOnLibsWithTags?.length),
);
if (!relevantConstraints.length) {
return [];
Expand All @@ -43,7 +45,10 @@ export async function checkModuleBoundariesForProject(
for (const constraint of relevantConstraints) {
if (
!dependencyTags.some((x) =>
constraint.onlyDependOnLibsWithTags.includes(x),
constraint.onlyDependOnLibsWithTags?.includes(x),
) ||
dependencyTags.some((x) =>
constraint.notDependOnLibsWithTags?.includes(x),
)
) {
violations.push(
Expand Down
3 changes: 2 additions & 1 deletion packages/utils/src/lib/models/nx.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export type ModuleBoundaries = {
sourceTag: '*' | string;
onlyDependOnLibsWithTags: string[];
onlyDependOnLibsWithTags?: string[];
notDependOnLibsWithTags?: string[];
}[];

0 comments on commit 483086b

Please sign in to comment.