fix(linter): migrate custom ignorePath to flat config (#20017)

This commit is contained in:
Miroslav Jonaš 2023-11-05 11:11:35 +01:00 committed by GitHub
parent fa22c77d64
commit f421716edf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 116 additions and 24 deletions

View File

@ -135,7 +135,7 @@ module.exports = [
"
`;
exports[`convert-to-flat-config generator should add global gitignores 1`] = `
exports[`convert-to-flat-config generator should add global eslintignores 1`] = `
"const { FlatCompat } = require('@eslint/eslintrc');
const nxEslintPlugin = require('@nx/eslint-plugin');
const js = require('@eslint/js');
@ -317,6 +317,33 @@ module.exports = [
"
`;
exports[`convert-to-flat-config generator should handle custom eslintignores 1`] = `
"const baseConfig = require('../../eslint.config.js');
module.exports = [
...baseConfig,
{
files: [
'libs/test-lib/**/*.ts',
'libs/test-lib/**/*.tsx',
'libs/test-lib/**/*.js',
'libs/test-lib/**/*.jsx',
],
rules: {},
},
{
files: ['libs/test-lib/**/*.ts', 'libs/test-lib/**/*.tsx'],
rules: {},
},
{
files: ['libs/test-lib/**/*.js', 'libs/test-lib/**/*.jsx'],
rules: {},
},
{ ignores: ['libs/test-lib/ignore/me'] },
{ ignores: ['libs/test-lib/ignore/me/as/well'] },
];
"
`;
exports[`convert-to-flat-config generator should run successfully 1`] = `
"const { FlatCompat } = require('@eslint/eslintrc');
const nxEslintPlugin = require('@nx/eslint-plugin');

View File

@ -62,7 +62,8 @@ describe('convertEslintJsonToFlatConfig', () => {
tree,
'',
'.eslintrc.json',
'eslint.config.js'
'eslint.config.js',
['.eslintignore']
);
expect(tree.read('eslint.config.js', 'utf-8')).toMatchInlineSnapshot(`
@ -119,7 +120,6 @@ describe('convertEslintJsonToFlatConfig', () => {
`);
expect(tree.exists('.eslintrc.json')).toBeFalsy();
expect(tree.exists('.eslintignore')).toBeFalsy();
});
it('should convert project configs', async () => {
@ -174,7 +174,8 @@ describe('convertEslintJsonToFlatConfig', () => {
tree,
'mylib',
'.eslintrc.json',
'eslint.config.js'
'eslint.config.js',
['mylib/.eslintignore']
);
expect(tree.read('mylib/eslint.config.js', 'utf-8')).toMatchInlineSnapshot(`
@ -229,6 +230,5 @@ describe('convertEslintJsonToFlatConfig', () => {
`);
expect(tree.exists('mylib/.eslintrc.json')).toBeFalsy();
expect(tree.exists('mylib/.eslintignore')).toBeFalsy();
});
});

View File

@ -27,7 +27,8 @@ export function convertEslintJsonToFlatConfig(
tree: Tree,
root: string,
sourceFile: string,
destinationFile: string
destinationFile: string,
ignorePaths: string[]
) {
const importsMap = new Map<string, string>();
const exportElements: ts.Expression[] = [];
@ -174,19 +175,20 @@ export function convertEslintJsonToFlatConfig(
}
}
if (tree.exists(`${root}/.eslintignore`)) {
const patterns = tree
.read(`${root}/.eslintignore`, 'utf-8')
.split('\n')
.filter((line) => line.length > 0 && line !== 'node_modules')
.map((path) => mapFilePath(path, root));
if (patterns.length > 0) {
exportElements.push(generateAst({ ignores: patterns }));
for (const ignorePath of ignorePaths) {
if (tree.exists(ignorePath)) {
const patterns = tree
.read(ignorePath, 'utf-8')
.split('\n')
.filter((line) => line.length > 0 && line !== 'node_modules')
.map((path) => mapFilePath(path, root));
if (patterns.length > 0) {
exportElements.push(generateAst({ ignores: patterns }));
}
}
}
tree.delete(join(root, sourceFile));
tree.delete(join(root, '.eslintignore'));
// create the node list and print it to new file
const nodeList = createNodeList(

View File

@ -12,6 +12,7 @@ import { ConvertToFlatConfigGeneratorSchema } from './schema';
import { lintProjectGenerator } from '../lint-project/lint-project';
import { Linter } from '../utils/linter';
import { eslintrcVersion } from '../../utils/versions';
import { read } from 'fs';
describe('convert-to-flat-config generator', () => {
let tree: Tree;
@ -153,7 +154,7 @@ describe('convert-to-flat-config generator', () => {
).toEqual(eslintrcVersion);
});
it('should add global gitignores', async () => {
it('should add global eslintignores', async () => {
await lintProjectGenerator(tree, {
skipFormat: false,
linter: Linter.EsLint,
@ -164,7 +165,39 @@ describe('convert-to-flat-config generator', () => {
tree.write('.eslintignore', 'ignore/me');
await convertToFlatConfigGenerator(tree, options);
expect(tree.read('eslint.config.js', 'utf-8')).toMatchSnapshot();
const config = tree.read('eslint.config.js', 'utf-8');
expect(config).toContain('ignore/me');
expect(config).toMatchSnapshot();
expect(tree.exists('.eslintignore')).toBeFalsy();
});
it('should handle custom eslintignores', async () => {
await lintProjectGenerator(tree, {
skipFormat: false,
linter: Linter.EsLint,
eslintFilePatterns: ['**/*.ts'],
project: 'test-lib',
setParserOptionsProject: false,
});
tree.write('another-folder/.myeslintignore', 'ignore/me');
updateJson(tree, 'libs/test-lib/project.json', (json) => {
json.targets.lint.options.ignorePath = 'another-folder/.myeslintignore';
return json;
});
tree.write('libs/test-lib/.eslintignore', 'ignore/me/as/well');
await convertToFlatConfigGenerator(tree, options);
expect(
tree.read('libs/test-lib/eslint.config.js', 'utf-8')
).toMatchSnapshot();
expect(tree.exists('another-folder/.myeslintignore')).toBeFalsy();
expect(tree.exists('libs/test-lib/.eslintignore')).toBeFalsy();
expect(
readJson(tree, 'libs/test-lib/project.json').targets.lint.options
.ignorePath
).toBeUndefined();
});
it('should add settings', async () => {

View File

@ -26,13 +26,28 @@ export async function convertToFlatConfigGenerator(
);
}
// rename root eslint config to eslint.config.js
const eslintIgnoreFiles = new Set<string>(['.eslintignore']);
// convert root eslint config to eslint.config.js
convertRootToFlatConfig(tree, eslintFile);
// rename and map files
// convert project eslint files to eslint.config.js
const projects = getProjects(tree);
for (const [project, projectConfig] of projects) {
convertProjectToFlatConfig(tree, project, projectConfig, readNxJson(tree));
convertProjectToFlatConfig(
tree,
project,
projectConfig,
readNxJson(tree),
eslintIgnoreFiles
);
}
// delete all .eslintignore files
for (const ignoreFile of eslintIgnoreFiles) {
tree.delete(ignoreFile);
}
// replace references in nx.json
updateNxJsonConfig(tree);
// install missing packages
@ -60,18 +75,24 @@ function convertProjectToFlatConfig(
tree: Tree,
project: string,
projectConfig: ProjectConfiguration,
nxJson: NxJsonConfiguration
nxJson: NxJsonConfiguration,
eslintIgnoreFiles: Set<string>
) {
if (tree.exists(`${projectConfig.root}/.eslintrc.json`)) {
if (projectConfig.targets) {
const eslintTargets = Object.keys(projectConfig.targets || {}).filter(
(t) => projectConfig.targets[t].executor === '@nx/eslint:lint'
);
let ignorePath: string | undefined;
for (const target of eslintTargets) {
// remove any obsolete `eslintConfig` options pointing to the old config file
if (projectConfig.targets[target].options?.eslintConfig) {
delete projectConfig.targets[target].options.eslintConfig;
}
if (projectConfig.targets[target].options?.ignorePath) {
ignorePath = projectConfig.targets[target].options.ignorePath;
delete projectConfig.targets[target].options.ignorePath;
}
updateProjectConfiguration(tree, project, projectConfig);
}
const nxHasLintTargets = Object.keys(nxJson.targetDefaults || {}).some(
@ -85,8 +106,13 @@ function convertProjectToFlatConfig(
tree,
projectConfig.root,
'.eslintrc.json',
'eslint.config.js'
'eslint.config.js',
ignorePath
);
eslintIgnoreFiles.add(`${projectConfig.root}/.eslintignore`);
if (ignorePath) {
eslintIgnoreFiles.add(ignorePath);
}
}
}
}
@ -121,7 +147,11 @@ function convertConfigToFlatConfig(
tree: Tree,
root: string,
source: string,
target: string
target: string,
ignorePath?: string
) {
convertEslintJsonToFlatConfig(tree, root, source, target);
const ignorePaths = ignorePath
? [ignorePath, `${root}/.eslintignore`]
: [`${root}/.eslintignore`];
convertEslintJsonToFlatConfig(tree, root, source, target, ignorePaths);
}