fix(linter): generate flat config for new projects correctly (#26328)
- Change generated import for `FlatCompat`:
```diff
- const FlatCompat = require('@eslint/eslintrc');
+ const { FlatCompat } = require('@eslint/eslintrc');
```
- Fix replacing overrides to be reflected in the end result (the updated
content with the replacements was not being assigned)
- Add extended plugins/configs to the start (matches behavior of the old
config)
<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->
<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->
## 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 #22350
Fixes #26151
This commit is contained in:
parent
0594debfef
commit
e95204b037
@ -1,5 +1,6 @@
|
||||
import * as path from 'path';
|
||||
import {
|
||||
checkFilesDoNotExist,
|
||||
checkFilesExist,
|
||||
cleanupProject,
|
||||
createFile,
|
||||
@ -521,6 +522,43 @@ describe('Linter', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('flat config', () => {
|
||||
beforeAll(() => {
|
||||
runCLI(`generate @nx/eslint:convert-to-flat-config`);
|
||||
});
|
||||
|
||||
it('should generate new projects using flat config', () => {
|
||||
const reactLib = uniq('react-lib');
|
||||
const jsLib = uniq('js-lib');
|
||||
|
||||
runCLI(
|
||||
`generate @nx/react:lib ${reactLib} --directory=${reactLib} --projectNameAndRootFormat=as-provided`
|
||||
);
|
||||
runCLI(
|
||||
`generate @nx/js:lib ${jsLib} --directory=${jsLib} --projectNameAndRootFormat=as-provided`
|
||||
);
|
||||
|
||||
checkFilesExist(
|
||||
`${reactLib}/eslint.config.js`,
|
||||
`${jsLib}/eslint.config.js`
|
||||
);
|
||||
checkFilesDoNotExist(
|
||||
`${reactLib}/.eslintrc.json`,
|
||||
`${jsLib}/.eslintrc.json`
|
||||
);
|
||||
|
||||
// validate that the new projects are linted successfully
|
||||
let output = runCLI(`lint ${reactLib}`);
|
||||
expect(output).toContain(
|
||||
`Successfully ran target lint for project ${reactLib}`
|
||||
);
|
||||
output = runCLI(`lint ${jsLib}`);
|
||||
expect(output).toContain(
|
||||
`Successfully ran target lint for project ${jsLib}`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Root projects migration', () => {
|
||||
|
||||
@ -2,6 +2,7 @@ import {
|
||||
addExtendsToLintConfig,
|
||||
findEslintFile,
|
||||
lintConfigHasOverride,
|
||||
replaceOverridesInLintConfig,
|
||||
} from './eslint-file';
|
||||
|
||||
import { Tree, readJson } from '@nx/devkit';
|
||||
@ -120,4 +121,124 @@ describe('@nx/eslint:lint-file', () => {
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('replaceOverridesInLintConfig', () => {
|
||||
it('should replace overrides when using flat config', () => {
|
||||
tree.write('eslint.config.js', 'module.exports = {};');
|
||||
tree.write(
|
||||
'apps/demo/eslint.config.js',
|
||||
`const baseConfig = require("../../eslint.config.js");
|
||||
|
||||
module.exports = [
|
||||
...baseConfig,
|
||||
{
|
||||
files: [
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
"**/*.js",
|
||||
"**/*.jsx"
|
||||
],
|
||||
rules: {}
|
||||
},
|
||||
{
|
||||
files: [
|
||||
"**/*.ts",
|
||||
"**/*.tsx"
|
||||
],
|
||||
rules: {}
|
||||
},
|
||||
{
|
||||
files: [
|
||||
"**/*.js",
|
||||
"**/*.jsx"
|
||||
],
|
||||
rules: {}
|
||||
}
|
||||
];`
|
||||
);
|
||||
|
||||
replaceOverridesInLintConfig(tree, 'apps/demo', [
|
||||
{
|
||||
files: ['*.ts'],
|
||||
extends: [
|
||||
'plugin:@nx/angular',
|
||||
'plugin:@angular-eslint/template/process-inline-templates',
|
||||
],
|
||||
rules: {
|
||||
'@angular-eslint/directive-selector': [
|
||||
'error',
|
||||
{
|
||||
type: 'attribute',
|
||||
prefix: 'myOrg',
|
||||
style: 'camelCase',
|
||||
},
|
||||
],
|
||||
'@angular-eslint/component-selector': [
|
||||
'error',
|
||||
{
|
||||
type: 'element',
|
||||
prefix: 'my-org',
|
||||
style: 'kebab-case',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.html'],
|
||||
extends: ['plugin:@nx/angular-template'],
|
||||
rules: {},
|
||||
},
|
||||
]);
|
||||
|
||||
expect(tree.read('apps/demo/eslint.config.js', 'utf-8'))
|
||||
.toMatchInlineSnapshot(`
|
||||
"const { FlatCompat } = require("@eslint/eslintrc");
|
||||
const js = require("@eslint/js");
|
||||
const baseConfig = require("../../eslint.config.js");
|
||||
|
||||
const compat = new FlatCompat({
|
||||
baseDirectory: __dirname,
|
||||
recommendedConfig: js.configs.recommended,
|
||||
});
|
||||
|
||||
|
||||
module.exports = [
|
||||
...baseConfig,
|
||||
...compat.config({ extends: [
|
||||
"plugin:@nx/angular",
|
||||
"plugin:@angular-eslint/template/process-inline-templates"
|
||||
] }).map(config => ({
|
||||
...config,
|
||||
files: ["**/*.ts"],
|
||||
rules: {
|
||||
...config.rules,
|
||||
"@angular-eslint/directive-selector": [
|
||||
"error",
|
||||
{
|
||||
type: "attribute",
|
||||
prefix: "myOrg",
|
||||
style: "camelCase"
|
||||
}
|
||||
],
|
||||
"@angular-eslint/component-selector": [
|
||||
"error",
|
||||
{
|
||||
type: "element",
|
||||
prefix: "my-org",
|
||||
style: "kebab-case"
|
||||
}
|
||||
]
|
||||
}
|
||||
})),
|
||||
...compat.config({ extends: ["plugin:@nx/angular-template"] }).map(config => ({
|
||||
...config,
|
||||
files: ["**/*.html"],
|
||||
rules: {
|
||||
...config.rules
|
||||
}
|
||||
})),
|
||||
];"
|
||||
`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -291,7 +291,7 @@ export function replaceOverridesInLintConfig(
|
||||
content = removeOverridesFromLintConfig(content);
|
||||
overrides.forEach((override) => {
|
||||
const flatOverride = generateFlatOverride(override);
|
||||
addBlockToFlatConfigExport(content, flatOverride);
|
||||
content = addBlockToFlatConfigExport(content, flatOverride);
|
||||
});
|
||||
|
||||
tree.write(fileName, content);
|
||||
@ -315,7 +315,12 @@ export function addExtendsToLintConfig(
|
||||
const pluginExtends = generatePluginExtendsElement(plugins);
|
||||
let content = tree.read(fileName, 'utf8');
|
||||
content = addCompatToFlatConfig(content);
|
||||
tree.write(fileName, addBlockToFlatConfigExport(content, pluginExtends));
|
||||
tree.write(
|
||||
fileName,
|
||||
addBlockToFlatConfigExport(content, pluginExtends, {
|
||||
insertAtTheEnd: false,
|
||||
})
|
||||
);
|
||||
} else {
|
||||
const fileName = joinPathFragments(root, '.eslintrc.json');
|
||||
updateJson(tree, fileName, (json) => {
|
||||
|
||||
@ -223,7 +223,7 @@ describe('ast-utils', () => {
|
||||
];`;
|
||||
const result = addCompatToFlatConfig(content);
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
"const FlatCompat = require("@eslint/eslintrc");
|
||||
"const { FlatCompat } = require("@eslint/eslintrc");
|
||||
const js = require("@eslint/js");
|
||||
const baseConfig = require("../../eslint.config.js");
|
||||
|
||||
@ -262,7 +262,7 @@ describe('ast-utils', () => {
|
||||
];`;
|
||||
const result = addCompatToFlatConfig(content);
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
"const FlatCompat = require("@eslint/eslintrc");
|
||||
"const { FlatCompat } = require("@eslint/eslintrc");
|
||||
const baseConfig = require("../../eslint.config.js");
|
||||
const js = require("@eslint/js");
|
||||
|
||||
|
||||
@ -602,7 +602,7 @@ export function addCompatToFlatConfig(content: string) {
|
||||
if (result.includes('const compat = new FlatCompat')) {
|
||||
return result;
|
||||
}
|
||||
result = addImportToFlatConfig(result, 'FlatCompat', '@eslint/eslintrc');
|
||||
result = addImportToFlatConfig(result, ['FlatCompat'], '@eslint/eslintrc');
|
||||
const index = result.indexOf('module.exports');
|
||||
return applyChangesToString(result, [
|
||||
{
|
||||
|
||||
@ -116,7 +116,7 @@ describe('updateEslint', () => {
|
||||
|
||||
expect(tree.read(`${schema.appProjectRoot}/eslint.config.js`, 'utf-8'))
|
||||
.toMatchInlineSnapshot(`
|
||||
"const FlatCompat = require("@eslint/eslintrc");
|
||||
"const { FlatCompat } = require("@eslint/eslintrc");
|
||||
const js = require("@eslint/js");
|
||||
const baseConfig = require("../eslint.config.js");
|
||||
|
||||
@ -127,6 +127,7 @@ describe('updateEslint', () => {
|
||||
|
||||
|
||||
module.exports = [
|
||||
...compat.extends("plugin:@nx/react-typescript", "next", "next/core-web-vitals"),
|
||||
...baseConfig,
|
||||
{
|
||||
"files": [
|
||||
@ -156,7 +157,6 @@ describe('updateEslint', () => {
|
||||
],
|
||||
rules: {}
|
||||
},
|
||||
...compat.extends("plugin:@nx/react-typescript", "next", "next/core-web-vitals"),
|
||||
...compat.config({ env: { jest: true } }).map(config => ({
|
||||
...config,
|
||||
files: [
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user