Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: ng-add should also work for ESLint 9 flat config files (#4643) #4698

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

adxdits
Copy link

@adxdits adxdits commented Feb 9, 2025

PR Checklist

Please check if your PR fulfills the following requirements:

  • The commit message follows our guidelines: CONTRIBUTING.md
  • Tests for the changes have been added (for bug fixes / features)
  • Documentation has been added / updated (for bug fixes / features)

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • Other... Please describe:

What is the current behavior?

Today: When someone runs the NgRx ESLint schematic (for example via an ng add command), it updates the ESLint configuration by editing a JSON file (like .eslintrc.json) to add the NgRx plugin and its rules.
Closes #4643

What is the new behavior?

  • Detect if eslint.config.js exists and update it with NgRx plugin
  • Fallback to .eslintrc.json when flat config is missing
  • Preserve existing configuration

Steps to push the change:

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

Copy link

netlify bot commented Feb 9, 2025

Deploy Preview for ngrx-io canceled.

Built without sensitive environment variables

Name Link
🔨 Latest commit acaac29
🔍 Latest deploy log https://app.netlify.com/sites/ngrx-io/deploys/67bb878ddb69600008790837

Copy link
Member

@timdeschryver timdeschryver left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello, thanks for this PR ~ I will review this later this week.
I already noticed that there are no test cases, could you please write some tests to cover these changes?
I'm thinking of:

  • a test to detect the correct file is changed
  • a test that adds the NgRx plugin to a flat config file
  • a test that verifies the plugin isn't added twice

@@ -4,17 +4,79 @@ import type { Schema } from './schema';

export default function addNgRxESLintPlugin(schema: Schema): Rule {
return (host: Tree, context: SchematicContext) => {
const eslintConfigPath = '.eslintrc.json';
const jsonConfigPath = '.eslintrc.json';
const flatConfigPath = 'eslint.config.js';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should also cover commonjs and modulejs files:

  • eslint.config.js
  • eslint.config.mjs
  • eslint.config.cjs

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we also support .eslintrc.(m|c)js?

Copy link
Member

@timdeschryver timdeschryver Feb 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just as @timdeschryver said i updated the schematics to support only the flat ESLint config files (eslint.config.js, eslint.config.mjs, and eslint.config.cjs) since .eslintrc.(m|c)js files are no longer supported. :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only see eslint.config.js here, could you also want to include the other extensions?

@adxdits
Copy link
Author

adxdits commented Feb 12, 2025

Hello, thanks for this PR ~ I will review this later this week. I already noticed that there are no test cases, could you please write some tests to cover these changes? I'm thinking of:

  • a test to detect the correct file is changed
  • a test that adds the NgRx plugin to a flat config file
  • a test that verifies the plugin isn't added twice

Hello, of course. Thanks for pointing that out!

Copy link
Member

@timdeschryver timdeschryver left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C


// Add the import for the NgRx ESLint plugin if not already present.
if (!content.includes("from '@ngrx/eslint-plugin'")) {
content = `import ngrxEslintPlugin from '@ngrx/eslint-plugin';\n` + content;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to match this with the current import statements?
For example, when it's not the module syntax we should use

const ngrx = require("@ngrx/eslint-plugin");

// Check if the flat config already contains an NgRx config.
if (!content.includes('plugin:@ngrx')) {
// Look for an exported default array.
const exportDefaultRegex = /export\s+default\s+\[([\s\S]*?)\];/;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment here, ideally we also support module.exports = ....
As I expect most eslint configs use tseslint, checking for tseslint.config is probably the simplest solution. Updating it is harder than a JSON file, I think it can be easier if we use the TS AST to find the tseslint.config CallExpression, and add an argument.

const eslint = host.read(eslintConfigPath)?.toString('utf-8');
// If a flat config exists, update it
if (host.exists(flatConfigPath)) {
let content = host.read(flatConfigPath)?.toString('utf-8');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is becoming lengthy, could you split it up into at least two methods, one for the flat config, the other for the JSON file?

@@ -4,17 +4,79 @@ import type { Schema } from './schema';

export default function addNgRxESLintPlugin(schema: Schema): Rule {
return (host: Tree, context: SchematicContext) => {
const eslintConfigPath = '.eslintrc.json';
const jsonConfigPath = '.eslintrc.json';
const flatConfigPath = 'eslint.config.js';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only see eslint.config.js here, could you also want to include the other extensions?

Copy link
Member

@timdeschryver timdeschryver left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems as if I can't push to your branch, please update the files with https://gist.github.com/timdeschryver/bb49c998c5a39ebe289b77412aa8fd0f.
The main changes are to use Angular's recorder instead of TypeScript (ts.factory) to make the changes, this keeps the implementation consistent with our codebase.
It also updates the tests.
For the next time, please make sure the tests are green while creating a Pull Requests.

Also, please revert the changes to the package and package-lock files.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ng-add should also work for ESLint 9 flat config files
3 participants