fix(linter): ensure that @nx/eslint-plugin is installed when we add an extracted base eslintrc file (#26679)

The current eslint logic doesn't add the necessary `@nx/eslint-plugin`
package when we extract root config. This PR fixes the issue. This
applies to projects not generated using CNW but rather using something
like `npm create vite`, where the eslint setup isn't what we expect.

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #
This commit is contained in:
Jack Hsu 2024-06-26 06:38:31 -04:00 committed by GitHub
parent 81dced7252
commit c24c20e990
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 110 additions and 12 deletions

View File

@ -1,5 +1,6 @@
import {
addDependenciesToPackageJson,
GeneratorCallback,
joinPathFragments,
offsetFromRoot,
ProjectConfiguration,
@ -15,7 +16,7 @@ import {
getGlobalFlatEslintConfiguration,
} from './global-eslint-config';
import { useFlatConfig } from '../../utils/flat-config';
import { eslintVersion } from '../../utils/versions';
import { eslintVersion, nxVersion } from '../../utils/versions';
import {
addBlockToFlatConfigExport,
addImportToFlatConfig,
@ -31,7 +32,7 @@ export function migrateConfigToMonorepoStyle(
tree: Tree,
unitTestRunner: string,
keepExistingVersions?: boolean
): void {
): GeneratorCallback {
const rootEslintConfig = findEslintFile(tree);
let skipCleanup = false;
if (
@ -105,6 +106,14 @@ export function migrateConfigToMonorepoStyle(
}
}
});
return addDependenciesToPackageJson(
tree,
{},
{
'@nx/eslint-plugin': nxVersion,
}
);
}
export function findLintTarget(

View File

@ -0,0 +1,92 @@
import {
addProjectConfiguration,
ProjectGraph,
readJson,
Tree,
} from '@nx/devkit';
import { Linter } from '../utils/linter';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import { lintProjectGenerator } from './lint-project';
let projectGraph: ProjectGraph;
jest.mock('@nx/devkit', () => ({
...jest.requireActual<any>('@nx/devkit'),
createProjectGraphAsync: jest
.fn()
.mockImplementation(async () => projectGraph),
}));
describe('@nx/eslint:lint-project (convert to monorepo style)', () => {
let tree: Tree;
const defaultOptions = {
skipFormat: false,
addPlugin: true,
};
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
const rootpkg = {
root: '.',
projectType: 'library' as const,
targets: {
'eslint:lint': {
executor: 'nx:run-commands',
options: {
command: 'eslint .',
},
},
},
};
projectGraph = {
nodes: {
rootpkg: {
type: 'lib',
name: 'rootpkg',
data: rootpkg,
},
},
dependencies: {},
};
addProjectConfiguration(tree, 'rootpkg', rootpkg);
tree.write(
'.eslintrc.cjs',
`
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react-hooks/recommended',
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parser: '@typescript-eslint/parser',
}
`
);
});
it('should generate a eslint config and configure the target in project configuration', async () => {
addProjectConfiguration(tree, 'nestedpkg', {
root: 'nestedpkg',
projectType: 'library',
targets: {},
});
await lintProjectGenerator(tree, {
...defaultOptions,
linter: Linter.EsLint,
project: 'nestedpkg',
setParserOptionsProject: false,
});
expect(readJson(tree, 'package.json')).toMatchObject({
devDependencies: {
'@nx/eslint-plugin': expect.any(String),
},
});
});
});

View File

@ -1,16 +1,16 @@
import {
createProjectGraphAsync,
formatFiles,
GeneratorCallback,
NxJsonConfiguration,
offsetFromRoot,
ProjectConfiguration,
ProjectGraph,
Tree,
readNxJson,
formatFiles,
offsetFromRoot,
readJson,
readNxJson,
readProjectConfiguration,
runTasksInSerial,
Tree,
updateJson,
updateProjectConfiguration,
writeJson,
@ -21,10 +21,7 @@ import { findEslintFile } from '../utils/eslint-file';
import { join } from 'path';
import { lintInitGenerator } from '../init/init';
import type { Linter } from 'eslint';
import {
findLintTarget,
migrateConfigToMonorepoStyle,
} from '../init/init-migration';
import { migrateConfigToMonorepoStyle } from '../init/init-migration';
import { getProjects } from 'nx/src/generators/utils/project-configuration';
import { useFlatConfig } from '../../utils/flat-config';
import {
@ -36,7 +33,6 @@ import {
import {
baseEsLintConfigFile,
baseEsLintFlatConfigFile,
ESLINT_CONFIG_FILENAMES,
} from '../../utils/config-file';
import { hasEslintPlugin } from '../utils/plugin';
import { setupRootEsLint } from './setup-root-eslint';
@ -144,12 +140,13 @@ export async function lintProjectGeneratorInternal(
filteredProjects.push(project);
}
});
migrateConfigToMonorepoStyle(
const migrateTask = migrateConfigToMonorepoStyle(
filteredProjects,
tree,
options.unitTestRunner,
options.keepExistingVersions
);
tasks.push(migrateTask);
}
}