Skip to content

Commit

Permalink
feat(linter): automatic fixes for noRelativeOrAbsoluteImportsAcrossLi…
Browse files Browse the repository at this point in the history
…braries and noSelfCircularDependencies
  • Loading branch information
juristr committed Feb 9, 2022
1 parent 9a0db6a commit 87c387b
Show file tree
Hide file tree
Showing 6 changed files with 868 additions and 142 deletions.
156 changes: 156 additions & 0 deletions e2e/linter/src/linter.test.ts
@@ -1,6 +1,7 @@
import * as path from 'path';
import {
checkFilesExist,
createFile,
newProject,
readFile,
readJson,
Expand All @@ -9,6 +10,7 @@ import {
updateFile,
} from '@nrwl/e2e/utils';
import * as ts from 'typescript';
import { names } from '@nrwl/devkit';

describe('Linter', () => {
describe('linting errors', () => {
Expand Down Expand Up @@ -191,6 +193,160 @@ describe('Linter', () => {
expect(lintOutput).toContain(knownLintErrorMessage);
}, 1000000);
});

it('lint plugin should ensure module boundaries', () => {
const proj = newProject();
const myapp = uniq('myapp');
const myapp2 = uniq('myapp2');
const mylib = uniq('mylib');
const lazylib = uniq('lazylib');
const invalidtaglib = uniq('invalidtaglib');
const validtaglib = uniq('validtaglib');

runCLI(`generate @nrwl/angular:app ${myapp} --tags=validtag`);
runCLI(`generate @nrwl/angular:app ${myapp2}`);
runCLI(`generate @nrwl/angular:lib ${mylib}`);
runCLI(`generate @nrwl/angular:lib ${lazylib}`);
runCLI(`generate @nrwl/angular:lib ${invalidtaglib} --tags=invalidtag`);
runCLI(`generate @nrwl/angular:lib ${validtaglib} --tags=validtag`);

const eslint = readJson('.eslintrc.json');
eslint.overrides[0].rules[
'@nrwl/nx/enforce-module-boundaries'
][1].depConstraints = [
{ sourceTag: 'validtag', onlyDependOnLibsWithTags: ['validtag'] },
...eslint.overrides[0].rules['@nrwl/nx/enforce-module-boundaries'][1]
.depConstraints,
];
updateFile('.eslintrc.json', JSON.stringify(eslint, null, 2));

const tsConfig = readJson('tsconfig.base.json');

/**
* apps do not add themselves to the tsconfig file.
*
* Let's add it so that we can trigger the lint failure
*/
tsConfig.compilerOptions.paths[`@${proj}/${myapp2}`] = [
`apps/${myapp2}/src/main.ts`,
];

tsConfig.compilerOptions.paths[`@secondScope/${lazylib}`] =
tsConfig.compilerOptions.paths[`@${proj}/${lazylib}`];
delete tsConfig.compilerOptions.paths[`@${proj}/${lazylib}`];
updateFile('tsconfig.base.json', JSON.stringify(tsConfig, null, 2));

updateFile(
`apps/${myapp}/src/main.ts`,
`
import '../../../libs/${mylib}';
import '@secondScope/${lazylib}';
import '@${proj}/${myapp2}';
import '@${proj}/${invalidtaglib}';
import '@${proj}/${validtaglib}';
const s = {loadChildren: '@${proj}/${lazylib}'};
`
);

const out = runCLI(`lint ${myapp}`, { silenceError: true });
expect(out).toContain(
'Projects cannot be imported by a relative or absolute path, and must begin with a npm scope'
);
// expect(out).toContain('Imports of lazy-loaded libraries are forbidden');
expect(out).toContain('Imports of apps are forbidden');
expect(out).toContain(
'A project tagged with "validtag" can only depend on libs tagged with "validtag"'
);
}, 1000000);

describe('workspace boundary rules', () => {
const libA = uniq('lib-a');
const libB = uniq('lib-b');
const libC = uniq('lib-c');
let projScope;

beforeAll(() => {
projScope = newProject();
runCLI(`generate @nrwl/workspace:lib ${libA}`);
runCLI(`generate @nrwl/workspace:lib ${libB}`);
runCLI(`generate @nrwl/workspace:lib ${libC}`);

// updateFile(`apps/${myapp}/src/main.ts`, `console.log("should fail");`);
});

xdescribe('aaashould autofix noSelfCircularDependencies', () => {
beforeAll(() => {
/*
import { func1, func2 } from '@scope/same-lib';
should be transformed into
import { func1 } from './func1';
import { func2 } from './func2';
*/

createFile(
`libs/${libC}/src/lib/another-func.ts`,
`
export function anotherFunc() {
return 'hi';
}
`
);

updateFile(
`libs/${libC}/src/lib/index.ts`,
`
export * from './lib/${names(libC).fileName}';
export * from './lib/another-func';
`
);

createFile(
`libs/${libC}/src/lib/lib-c-another.ts`,
`
import { ${
names(libC).propertyName
}, anotherFunc } from '@${projScope}/${libC}';
export function someStuff() {
anotherFunc();
return ${names(libC).propertyName}();
}
`
);

// scenario 2
});

it('should fix a circular self reference', () => {
const stdout = runCLI(`lint ${libC}`, {
silenceError: true,
});
expect(stdout).toContain(
'Projects should use relative imports to import from other files within the same project'
);

// fix them
const fixedStout = runCLI(`lint ${libC} --fix`, {
silenceError: true,
});
expect(fixedStout).not.toContain(
'Projects should use relative imports to import from other files within the same project'
);
const fileContent = readFile(`libs/${libC}/src/lib/lib-c-another.ts`);
expect(fileContent).toContain(
`import { ${names(libC).propertyName} } from './${
names(libC).fileName
}';`
);
expect(fileContent).toContain(
`import { anotherFunc } from './another-func';`
);
});
});
});
});

/**
Expand Down

0 comments on commit 87c387b

Please sign in to comment.