Repository: jhipster/jhipster-lite
Pull request #10858 (2024-09-15 19:37:19)

Angular: migrate Eslint configuration to recommended flat config


Patch:
diff --git a/src/main/java/tech/jhipster/lite/generator/client/angular/core/domain/AngularModuleFactory.java b/src/main/java/tech/jhipster/lite/generator/client/angular/core/domain/AngularModuleFactory.java
index 434e040ec..d2add2837 100644
--- a/src/main/java/tech/jhipster/lite/generator/client/angular/core/domain/AngularModuleFactory.java
+++ b/src/main/java/tech/jhipster/lite/generator/client/angular/core/domain/AngularModuleFactory.java
@@ -42,11 +42,6 @@ public class AngularModuleFactory {
         .addDependency(packageName("rxjs"), ANGULAR)
         .addDependency(packageName("tslib"), ANGULAR)
         .addDependency(packageName("zone.js"), ANGULAR)
-        .addDevDependency(packageName("@angular-eslint/builder"), ANGULAR)
-        .addDevDependency(packageName("@angular-eslint/eslint-plugin"), ANGULAR)
-        .addDevDependency(packageName("@angular-eslint/eslint-plugin-template"), ANGULAR)
-        .addDevDependency(packageName("@angular-eslint/schematics"), ANGULAR)
-        .addDevDependency(packageName("@angular-eslint/template-parser"), ANGULAR)
         .addDevDependency(packageName("@typescript-eslint/eslint-plugin"), COMMON)
         .addDevDependency(packageName("@typescript-eslint/parser"), COMMON)
         .addDevDependency(packageName("eslint"), COMMON)
@@ -56,12 +51,15 @@ public class AngularModuleFactory {
         .addDevDependency(packageName("@angular/compiler-cli"), ANGULAR, ANGULAR_CORE_PACKAGE)
         .addDevDependency(packageName("@types/node"), COMMON)
         .addDevDependency(packageName("@types/jest"), COMMON)
+        .addDevDependency(packageName("angular-eslint"), ANGULAR)
+        .addDevDependency(packageName("globals"), COMMON)
         .addDevDependency(packageName("jest"), COMMON)
         .addDevDependency(packageName("jest-environment-jsdom"), ANGULAR)
         .addDevDependency(packageName("ts-jest"), COMMON)
         .addDevDependency(packageName("jest-preset-angular"), ANGULAR)
         .addDevDependency(packageName("jest-sonar-reporter"), ANGULAR)
         .addDevDependency(packageName("typescript"), ANGULAR)
+        .addDevDependency(packageName("typescript-eslint"), COMMON)
         .addDevDependency(packageName("npm-run-all2"), COMMON)
         .addScript(scriptKey("ng"), scriptCommand("ng"))
         .addScript(scriptKey("start"), scriptCommand("ng serve"))
@@ -72,18 +70,17 @@ public class AngularModuleFactory {
         .addScript(scriptKey("test"), scriptCommand("npm run watch:test"))
         .addScript(scriptKey("test:coverage"), scriptCommand("ng test --coverage"))
         .addScript(scriptKey("watch:test"), scriptCommand("ng test --watch"))
-        .addScript(scriptKey("lint"), scriptCommand("ng lint"))
+        .addScript(scriptKey("lint"), scriptCommand("eslint ."))
         .and()
       .files()
         .add(SOURCE.template("angular.json"), to("angular.json"))
         .add(SOURCE.file("tsconfig.json"), to("tsconfig.json"))
         .add(SOURCE.file("tsconfig.app.json"), to("tsconfig.app.json"))
-        .add(SOURCE.file(".eslintrc.json"), to(".eslintrc.json"))
         .batch(SOURCE_COMMON, to("."))
-          .addFile(".eslintignore")
           .addFile(".npmrc")
           .and()
         .batch(SOURCE, to("."))
+          .addTemplate("eslint.config.mjs")
           .addTemplate("proxy.conf.json")
           .addTemplate("jest.conf.js")
           .addTemplate("tsconfig.spec.json")
diff --git a/src/main/resources/generator/client/angular/core/.eslintrc.json b/src/main/resources/generator/client/angular/core/.eslintrc.json
deleted file mode 100644
index 0dafb08b1..000000000
--- a/src/main/resources/generator/client/angular/core/.eslintrc.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
-  "root": true,
-  "ignorePatterns": ["projects/**/*"],
-  "overrides": [
-    {
-      "files": ["*.ts"],
-      "parserOptions": {
-        "project": ["tsconfig.json"],
-        "createDefaultProgram": true
-      },
-      "extends": ["plugin:@angular-eslint/recommended", "plugin:@angular-eslint/template/process-inline-templates"],
-      "rules": {
-        "@angular-eslint/directive-selector": [
-          "error",
-          {
-            "type": "attribute",
-            "prefix": "app",
-            "style": "camelCase"
-          }
-        ],
-        "@angular-eslint/component-selector": [
-          "error",
-          {
-            "type": "element",
-            "prefix": "jhi",
-            "style": "kebab-case"
-          }
-        ]
-      }
-    },
-    {
-      "files": ["*.html"],
-      "extends": ["plugin:@angular-eslint/template/recommended", "plugin:@angular-eslint/template/accessibility"]
-    }
-  ]
-}
diff --git a/src/main/resources/generator/client/angular/core/angular.json.mustache b/src/main/resources/generator/client/angular/core/angular.json.mustache
index 4c72f90f6..9bbaad998 100644
--- a/src/main/resources/generator/client/angular/core/angular.json.mustache
+++ b/src/main/resources/generator/client/angular/core/angular.json.mustache
@@ -91,12 +91,6 @@
           "options": {
             "buildTarget": "project:build"
           }
-        },
-        "lint": {
-          "builder": "@angular-eslint/builder:lint",
-          "options": {
-            "lintFilePatterns": ["src/**/*.ts", "src/**/*.html"]
-          }
         }
       }
     }
diff --git a/src/main/resources/generator/client/angular/core/eslint.config.mjs.mustache b/src/main/resources/generator/client/angular/core/eslint.config.mjs.mustache
new file mode 100644
index 000000000..8c251b5ec
--- /dev/null
+++ b/src/main/resources/generator/client/angular/core/eslint.config.mjs.mustache
@@ -0,0 +1,71 @@
+import globals from 'globals';
+import tseslint from 'typescript-eslint';
+import eslint from '@eslint/js';
+import angular from 'angular-eslint';
+
+export default tseslint.config(
+  {
+    languageOptions: {
+      globals: {
+        ...globals.node,
+      },
+    },
+  },
+  {
+    ignores: ['{{projectBuildDirectory}}/'],
+  },
+  eslint.configs.recommended,
+  {
+    files: ['src/main/webapp/**/*.ts'],
+    extends: [...tseslint.configs.strictTypeChecked, ...tseslint.configs.stylistic, ...angular.configs.tsRecommended],
+    languageOptions: {
+      globals: {
+        ...globals.browser,
+      },
+      parserOptions: {
+        project: ['./tsconfig.app.json', './tsconfig.spec.json'],
+      },
+    },
+    processor: {
+      // https://github.com/angular-eslint/angular-eslint/issues/1917
+      meta: {
+        name: 'extract-inline-html',
+      },
+      ...angular.processInlineTemplates,
+    },
+    rules: {
+      '@angular-eslint/component-selector': [
+        'error',
+        {
+          type: 'element',
+          prefix: 'jhi',
+          style: 'kebab-case',
+        },
+      ],
+      '@angular-eslint/directive-selector': [
+        'error',
+        {
+          type: 'attribute',
+          prefix: 'jhi',
+          style: 'camelCase',
+        },
+      ],
+      '@typescript-eslint/unbound-method': 'off',
+      '@typescript-eslint/no-floating-promises': 'off',
+      '@typescript-eslint/no-extraneous-class': 'off',
+      '@typescript-eslint/no-confusing-void-expression': 'off',
+      '@typescript-eslint/no-unsafe-assignment': 'off',
+      '@typescript-eslint/no-explicit-any': 'off',
+      '@typescript-eslint/no-non-null-assertion': 'off',
+      '@typescript-eslint/no-unsafe-member-access': 'off',
+      '@typescript-eslint/no-unsafe-argument': 'off',
+      '@typescript-eslint/consistent-type-definitions': 'off',
+      '@typescript-eslint/use-unknown-in-catch-callback-variable': 'off',
+    },
+  },
+  {
+    files: ['**/*.html'],
+    extends: [...angular.configs.templateRecommended, ...angular.configs.templateAccessibility],
+    rules: {},
+  },
+);
diff --git a/src/main/resources/generator/dependencies/angular/package.json b/src/main/resources/generator/dependencies/angular/package.json
index 3300e4ada..3084a8136 100644
--- a/src/main/resources/generator/dependencies/angular/package.json
+++ b/src/main/resources/generator/dependencies/angular/package.json
@@ -3,6 +3,7 @@
     "@angular/cdk": "18.2.3",
     "@angular/core": "18.2.4",
     "@angular/material": "18.2.3",
+    "angular-eslint": "18.3.1",
     "keycloak-js": "25.0.5",
     "rxjs": "7.8.1",
     "tslib": "2.7.0",
@@ -10,11 +11,6 @@
   },
   "devDependencies": {
     "@angular-builders/jest": "18.0.0",
-    "@angular-eslint/builder": "18.3.1",
-    "@angular-eslint/eslint-plugin": "18.3.1",
-    "@angular-eslint/eslint-plugin-template": "18.3.1",
-    "@angular-eslint/schematics": "18.3.1",
-    "@angular-eslint/template-parser": "18.3.1",
     "@angular/build": "18.2.4",
     "@angular/cli": "18.2.4",
     "@angular/compiler-cli": "18.2.4",


Test patch:
diff --git a/src/test/java/tech/jhipster/lite/generator/client/angular/core/domain/AngularModuleFactoryTest.java b/src/test/java/tech/jhipster/lite/generator/client/angular/core/domain/AngularModuleFactoryTest.java
index eea7f9ef2..afa9a3e02 100644
--- a/src/test/java/tech/jhipster/lite/generator/client/angular/core/domain/AngularModuleFactoryTest.java
+++ b/src/test/java/tech/jhipster/lite/generator/client/angular/core/domain/AngularModuleFactoryTest.java
@@ -38,14 +38,12 @@ class AngularModuleFactoryTest {
       .containing(nodeDependency("@angular/cdk"))
       .containing(nodeDependency("@angular/animations"))
       .containing(nodeDependency("@angular/build"))
-      .containing(nodeDependency("@angular-eslint/builder"))
-      .containing(nodeDependency("@angular-eslint/eslint-plugin"))
-      .containing(nodeDependency("@angular-eslint/eslint-plugin-template"))
-      .containing(nodeDependency("@angular-eslint/schematics"))
-      .containing(nodeDependency("@angular-eslint/template-parser"))
       .containing(nodeDependency("@typescript-eslint/eslint-plugin"))
       .containing(nodeDependency("@typescript-eslint/parser"))
+      .containing(nodeDependency("angular-eslint"))
       .containing(nodeDependency("eslint"))
+      .containing(nodeDependency("globals"))
+      .containing(nodeDependency("typescript-eslint"))
       .containing(nodeDependency("npm-run-all2"))
       .containing(nodeScript("ng", "ng"))
       .containing(nodeScript("watch", "npm-run-all --parallel watch:*"))
@@ -56,7 +54,7 @@ class AngularModuleFactoryTest {
       .containing(nodeScript("test", "npm run watch:test"))
       .containing(nodeScript("watch:test", "ng test --watch"))
       .containing(nodeScript("test:coverage", "ng test --coverage"))
-      .containing(nodeScript("lint", "ng lint"))
+      .containing(nodeScript("lint", "eslint ."))
       .containing("  \"jestSonar\": {\n    \"reportPath\": \"target/test-results\",\n    \"reportFile\": \"TESTS-results-sonar.xml\"\n  }")
       .and()
       .hasFile(".gitignore")
@@ -85,8 +83,7 @@ class AngularModuleFactoryTest {
         "tsconfig.spec.json",
         "proxy.conf.json",
         ".npmrc",
-        ".eslintignore",
-        ".eslintrc.json"
+        "eslint.config.mjs"
       )
       .hasPrefixedFiles(
         "src/main/webapp/app",
diff --git a/src/test/resources/projects/angular/angular.json b/src/test/resources/projects/angular/angular.json
index 820774732..a5845d8f8 100644
--- a/src/test/resources/projects/angular/angular.json
+++ b/src/test/resources/projects/angular/angular.json
@@ -94,12 +94,6 @@
           "options": {
             "buildTarget": "project:build"
           }
-        },
-        "lint": {
-          "builder": "@angular-eslint/builder:lint",
-          "options": {
-            "lintFilePatterns": ["src/**/*.ts", "src/**/*.html"]
-          }
         }
       }
     }
diff --git a/src/test/resources/projects/angular/empty-angular.json b/src/test/resources/projects/angular/empty-angular.json
index 4059ec02a..c4baa9daf 100644
--- a/src/test/resources/projects/angular/empty-angular.json
+++ b/src/test/resources/projects/angular/empty-angular.json
@@ -91,12 +91,6 @@
           "options": {
             "buildTarget": "project:build"
           }
-        },
-        "lint": {
-          "builder": "@angular-eslint/builder:lint",
-          "options": {
-            "lintFilePatterns": ["src/**/*.ts", "src/**/*.html"]
-          }
         }
       }
     }