fix(node): fix standalone linter setup (#15681)

This commit is contained in:
Miroslav Jonaš 2023-03-22 19:17:40 +01:00 committed by GitHub
parent e744f0429f
commit 4bf652d2e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 141 additions and 100 deletions

View File

@ -443,68 +443,81 @@ describe('Linter', () => {
beforeEach(() => newProject());
afterEach(() => cleanupProject());
function verifySuccessfulStandaloneSetup(myapp: string) {
expect(runCLI(`lint ${myapp}`, { silenceError: true })).toContain(
'All files pass linting'
);
expect(runCLI(`lint e2e`, { silenceError: true })).toContain(
'All files pass linting'
);
expect(() => checkFilesExist(`.eslintrc.base.json`)).toThrow();
const rootEslint = readJson('.eslintrc.json');
const e2eEslint = readJson('e2e/.eslintrc.json');
// should directly refer to nx plugin
expect(rootEslint.plugins).toEqual(['@nrwl/nx']);
expect(e2eEslint.plugins).toEqual(['@nrwl/nx']);
}
function verifySuccessfulMigratedSetup(myapp: string, mylib: string) {
expect(runCLI(`lint ${myapp}`, { silenceError: true })).toContain(
'All files pass linting'
);
expect(runCLI(`lint e2e`, { silenceError: true })).toContain(
'All files pass linting'
);
expect(runCLI(`lint ${mylib}`, { silenceError: true })).toContain(
'All files pass linting'
);
expect(() => checkFilesExist(`.eslintrc.base.json`)).not.toThrow();
const rootEslint = readJson('.eslintrc.base.json');
const appEslint = readJson('.eslintrc.json');
const e2eEslint = readJson('e2e/.eslintrc.json');
const libEslint = readJson(`libs/${mylib}/.eslintrc.json`);
// should directly refer to nx plugin
expect(rootEslint.plugins).toEqual(['@nrwl/nx']);
expect(appEslint.plugins).toBeUndefined();
expect(e2eEslint.plugins).toBeUndefined();
expect(libEslint.plugins).toBeUndefined();
// should extend base
expect(appEslint.extends.slice(-1)).toEqual(['./.eslintrc.base.json']);
expect(e2eEslint.extends.slice(-1)).toEqual(['../.eslintrc.base.json']);
expect(libEslint.extends.slice(-1)).toEqual([
'../../.eslintrc.base.json',
]);
}
it('(React standalone) should set root project config to app and e2e app and migrate when another lib is added', () => {
const myapp = uniq('myapp');
const mylib = uniq('mylib');
runCLI(`generate @nrwl/react:app ${myapp} --rootProject=true`);
verifySuccessfulStandaloneSetup(myapp);
let rootEslint = readJson('.eslintrc.json');
let appEslint = readJson('.eslintrc.json');
let e2eEslint = readJson('e2e/.eslintrc.json');
expect(() => checkFilesExist(`.eslintrc.base.json`)).toThrow();
// should directly refer to nx plugin
expect(rootEslint.plugins).toEqual(['@nrwl/nx']);
expect(e2eEslint.plugins).toEqual(['@nrwl/nx']);
// should only extend framework plugin
expect(rootEslint.extends).toEqual(['plugin:@nrwl/nx/react']);
expect(e2eEslint.extends).toEqual(['plugin:cypress/recommended']);
// should have plugin extends
expect(rootEslint.overrides[0].extends).toEqual([
'plugin:@nrwl/nx/typescript',
]);
expect(rootEslint.overrides[1].extends).toEqual([
'plugin:@nrwl/nx/javascript',
]);
expect(e2eEslint.overrides[0].extends).toEqual([
'plugin:@nrwl/nx/typescript',
]);
expect(e2eEslint.overrides[1].extends).toEqual([
'plugin:@nrwl/nx/javascript',
]);
expect(appEslint.overrides[0].extends).toBeDefined();
expect(appEslint.overrides[1].extends).toBeDefined();
expect(e2eEslint.overrides[0].extends).toBeDefined();
expect(e2eEslint.overrides[1].extends).toBeDefined();
runCLI(`generate @nrwl/react:lib ${mylib} --unitTestRunner=jest`);
// should add new tslint
expect(() => checkFilesExist(`.eslintrc.base.json`)).not.toThrow();
const appEslint = readJson(`.eslintrc.json`);
rootEslint = readJson('.eslintrc.base.json');
runCLI(`generate @nrwl/workspace:lib ${mylib} --unitTestRunner=jest`);
verifySuccessfulMigratedSetup(myapp, mylib);
appEslint = readJson(`.eslintrc.json`);
e2eEslint = readJson('e2e/.eslintrc.json');
const libEslint = readJson(`libs/${mylib}/.eslintrc.json`);
// should directly refer to nx plugin only in the root
expect(rootEslint.plugins).toEqual(['@nrwl/nx']);
expect(appEslint.plugins).toBeUndefined();
expect(e2eEslint.plugins).toBeUndefined();
// should extend framework plugin and root config
expect(appEslint.extends).toEqual([
'plugin:@nrwl/nx/react',
'./.eslintrc.base.json',
]);
expect(e2eEslint.extends).toEqual([
'plugin:cypress/recommended',
'../.eslintrc.base.json',
]);
expect(libEslint.extends).toEqual([
'plugin:@nrwl/nx/react',
'../../.eslintrc.base.json',
]);
// should have no plugin extends
expect(appEslint.overrides[0].extends).toBeUndefined();
expect(appEslint.overrides[1].extends).toBeUndefined();
expect(e2eEslint.overrides[0].extends).toBeUndefined();
expect(e2eEslint.overrides[1].extends).toBeUndefined();
expect(libEslint.overrides[1].extends).toBeUndefined();
expect(libEslint.overrides[1].extends).toBeUndefined();
});
it('(Angular standalone) should set root project config to app and e2e app and migrate when another lib is added', () => {
@ -514,57 +527,23 @@ describe('Linter', () => {
runCLI(
`generate @nrwl/angular:app ${myapp} --rootProject=true --no-interactive`
);
verifySuccessfulStandaloneSetup(myapp);
let rootEslint = readJson('.eslintrc.json');
let appEslint = readJson('.eslintrc.json');
let e2eEslint = readJson('e2e/.eslintrc.json');
expect(() => checkFilesExist(`.eslintrc.base.json`)).toThrow();
// should directly refer to nx plugin
expect(rootEslint.plugins).toEqual(['@nrwl/nx']);
expect(e2eEslint.plugins).toEqual(['@nrwl/nx']);
// should only extend framework plugin
expect(e2eEslint.extends).toEqual(['plugin:cypress/recommended']);
// should have plugin extends
expect(rootEslint.overrides[0].files).toEqual(['*.ts']);
expect(rootEslint.overrides[0].extends).toEqual([
'plugin:@nrwl/nx/typescript',
'plugin:@nrwl/nx/angular',
'plugin:@angular-eslint/template/process-inline-templates',
]);
expect(Object.keys(rootEslint.overrides[0].rules)).toEqual([
'@angular-eslint/directive-selector',
'@angular-eslint/component-selector',
]);
expect(rootEslint.overrides[1].files).toEqual(['*.html']);
expect(rootEslint.overrides[1].extends).toEqual([
'plugin:@nrwl/nx/angular-template',
]);
expect(e2eEslint.overrides[0].extends).toEqual([
'plugin:@nrwl/nx/typescript',
]);
expect(e2eEslint.overrides[1].extends).toEqual([
'plugin:@nrwl/nx/javascript',
]);
expect(appEslint.overrides[0].extends).toBeDefined();
expect(appEslint.overrides[1].extends).toBeDefined();
expect(e2eEslint.overrides[0].extends).toBeDefined();
expect(e2eEslint.overrides[1].extends).toBeDefined();
runCLI(`generate @nrwl/angular:lib ${mylib} --no-interactive`);
// should add new tslint
expect(() => checkFilesExist(`.eslintrc.base.json`)).not.toThrow();
const appEslint = readJson(`.eslintrc.json`);
rootEslint = readJson('.eslintrc.base.json');
runCLI(`generate @nrwl/workspace:lib ${mylib} --no-interactive`);
verifySuccessfulMigratedSetup(myapp, mylib);
appEslint = readJson(`.eslintrc.json`);
e2eEslint = readJson('e2e/.eslintrc.json');
const libEslint = readJson(`libs/${mylib}/.eslintrc.json`);
// should directly refer to nx plugin only in the root
expect(rootEslint.plugins).toEqual(['@nrwl/nx']);
expect(appEslint.plugins).toBeUndefined();
expect(e2eEslint.plugins).toBeUndefined();
// should extend framework plugin and root config
expect(appEslint.extends).toEqual(['./.eslintrc.base.json']);
expect(e2eEslint.extends).toEqual([
'plugin:cypress/recommended',
'../.eslintrc.base.json',
]);
expect(libEslint.extends).toEqual(['../../.eslintrc.base.json']);
// should have no plugin extends
expect(appEslint.overrides[0].extends).toEqual([
'plugin:@nrwl/nx/angular',
@ -572,10 +551,37 @@ describe('Linter', () => {
]);
expect(e2eEslint.overrides[0].extends).toBeUndefined();
expect(e2eEslint.overrides[1].extends).toBeUndefined();
expect(libEslint.overrides[0].extends).toEqual([
'plugin:@nrwl/nx/angular',
'plugin:@angular-eslint/template/process-inline-templates',
]);
});
it('(Node standalone) should set root project config to app and e2e app and migrate when another lib is added', () => {
const myapp = uniq('myapp');
const mylib = uniq('mylib');
runCLI(
`generate @nrwl/node:app ${myapp} --rootProject=true --no-interactive`
);
verifySuccessfulStandaloneSetup(myapp);
let appEslint = readJson('.eslintrc.json');
let e2eEslint = readJson('e2e/.eslintrc.json');
// should have plugin extends
expect(appEslint.overrides[0].extends).toBeDefined();
expect(appEslint.overrides[1].extends).toBeDefined();
expect(e2eEslint.overrides[0].extends).toBeDefined();
expect(e2eEslint.overrides[1].extends).toBeDefined();
runCLI(`generate @nrwl/workspace:lib ${mylib} --no-interactive`);
verifySuccessfulMigratedSetup(myapp, mylib);
appEslint = readJson(`.eslintrc.json`);
e2eEslint = readJson('e2e/.eslintrc.json');
// should have no plugin extends
expect(appEslint.overrides[0].extends).toBeUndefined();
expect(appEslint.overrides[1].extends).toBeUndefined();
expect(e2eEslint.overrides[0].extends).toBeUndefined();
expect(e2eEslint.overrides[1].extends).toBeUndefined();
});
});
});

View File

@ -45,6 +45,7 @@ import { e2eProjectGenerator } from '../e2e-project/e2e-project';
import { setupDockerGenerator } from '../setup-docker/setup-docker';
import { Schema } from './schema';
import { mapLintPattern } from '@nrwl/linter/src/generators/lint-project/lint-project';
export interface NormalizedSchema extends Schema {
appProjectRoot: string;
@ -273,7 +274,11 @@ export async function addLintingToApplication(
joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'),
],
eslintFilePatterns: [
`${options.appProjectRoot}/**/*.${options.js ? 'js' : 'ts'}`,
mapLintPattern(
options.appProjectRoot,
options.js ? 'js' : 'ts',
options.rootProject
),
],
unitTestRunner: options.unitTestRunner,
skipFormat: true,
@ -382,11 +387,8 @@ export async function applicationGenerator(tree: Tree, schema: Schema) {
updateTsConfigOptions(tree, options);
if (options.linter !== Linter.None) {
const lintTask = await addLintingToApplication(tree, {
...options,
skipFormat: true,
});
if (options.linter === Linter.EsLint) {
const lintTask = await addLintingToApplication(tree, options);
tasks.push(lintTask);
}

View File

@ -14,11 +14,17 @@ import {
readProjectConfiguration,
runTasksInSerial,
Tree,
updateJson,
} from '@nrwl/devkit';
import { Linter, lintProjectGenerator } from '@nrwl/linter';
import { Schema } from './schema';
import { axiosVersion } from '../../utils/versions';
import { join } from 'path';
import {
globalJavaScriptOverrides,
globalTypeScriptOverrides,
} from '@nrwl/linter/src/generators/init/global-eslint-config';
export async function e2eProjectGenerator(host: Tree, _options: Schema) {
const tasks: GeneratorCallback[] = [];
@ -90,7 +96,7 @@ export async function e2eProjectGenerator(host: Tree, _options: Schema) {
);
tasks.push(installTask);
if (options.linter === 'eslint') {
if (options.linter === Linter.EsLint) {
const linterTask = await lintProjectGenerator(host, {
project: options.e2eProjectName,
linter: Linter.EsLint,
@ -104,6 +110,33 @@ export async function e2eProjectGenerator(host: Tree, _options: Schema) {
rootProject: options.rootProject,
});
tasks.push(linterTask);
updateJson(host, join(options.e2eProjectRoot, '.eslintrc.json'), (json) => {
if (options.rootProject) {
json.plugins = ['@nrwl/nx'];
json.extends = [];
}
json.overrides = [
...(options.rootProject
? [globalTypeScriptOverrides, globalJavaScriptOverrides]
: []),
/**
* In order to ensure maximum efficiency when typescript-eslint generates TypeScript Programs
* behind the scenes during lint runs, we need to make sure the project is configured to use its
* own specific tsconfigs, and not fall back to the ones in the root of the workspace.
*/
{
files: ['*.ts', '*.tsx', '*.js', '*.jsx'],
/**
* Having an empty rules object present makes it more obvious to the user where they would
* extend things from if they needed to
*/
rules: {},
},
];
return json;
});
}
if (options.formatFile) {