Repository: ember-cli/eslint-plugin-ember
Pull request #1869 (2023-05-21 16:24:50)

Avoid crash with `inject` decorator in `no-restricted-service-injections` rule
Crash detected by:
* https://github.com/ember-cli/eslint-plugin-ember/pull/1741

```
Rule: "ember/no-restricted-service-injections"
Path: emberjs/data/tests/main/app/routes/application.ts
Link: https://github.com/emberjs/data/blob/HEAD/tests/main/app/routes/application.ts#L7

   5 |
   6 | export default class ApplicationRoute extends Route {
>  7 |   @inject declare store: Store;
   8 |
   9 |   model() {
  10 |     // adding a model to the store to enable manually testing the debug-adapter

Error:
TypeError: Cannot read property 'expression' of undefined
Occurred while linting /home/runner/work/eslint-plugin-ember/eslint-plugin-ember/node_modules/eslint-remote-tester/.cache-eslint-remote-tester/emberjs/data/tests/main/app/routes/application.ts:7
```

Related:
* https://github.com/ember-cli/eslint-plugin-ember/pull/1731


Patch:
diff --git a/lib/rules/no-restricted-service-injections.js b/lib/rules/no-restricted-service-injections.js
index 9504e663..e9d83b77 100644
--- a/lib/rules/no-restricted-service-injections.js
+++ b/lib/rules/no-restricted-service-injections.js
@@ -101,7 +101,9 @@ module.exports = {
       }
 
       // Find the service decorator.
-      const serviceDecorator = decoratorUtils.findDecorator(node, 'service');
+      const serviceDecorator =
+        decoratorUtils.findDecorator(node, 'service') ||
+        decoratorUtils.findDecorator(node, 'inject');
 
       // Get the service name either from the string argument or from the property name.
       const serviceName =


Test patch:
diff --git a/tests/lib/rules/no-restricted-service-injections.js b/tests/lib/rules/no-restricted-service-injections.js
index d3eea967..226843ca 100644
--- a/tests/lib/rules/no-restricted-service-injections.js
+++ b/tests/lib/rules/no-restricted-service-injections.js
@@ -4,6 +4,7 @@ const rule = require('../../../lib/rules/no-restricted-service-injections');
 const { DEFAULT_ERROR_MESSAGE } = rule;
 
 const EMBER_IMPORT = "import Ember from 'ember';";
+const INJECT_IMPORT = "import {inject} from '@ember/service';";
 const SERVICE_IMPORT = "import {inject as service} from '@ember/service';";
 const NEW_SERVICE_IMPORT = "import {service} from '@ember/service';";
 
@@ -23,6 +24,12 @@ ruleTester.run('no-restricted-service-injections', rule, {
       code: `${SERVICE_IMPORT} Component.extend({ myService: service() })`,
       options: [{ paths: ['app/components'], services: ['abc'] }],
     },
+    {
+      // Service name doesn't match (with property name):
+      filename: 'app/components/path.js',
+      code: `${INJECT_IMPORT} Component.extend({ myService: inject() })`,
+      options: [{ paths: ['app/components'], services: ['abc'] }],
+    },
     {
       // Service name doesn't match (with property name):
       filename: 'app/components/path.js',
@@ -148,6 +155,19 @@ ruleTester.run('no-restricted-service-injections', rule, {
         },
       ],
     },
+    {
+      // With decorator with camelized service name argument:
+      filename: 'app/components/path.js',
+      code: `${INJECT_IMPORT} class MyComponent extends Component { @inject('myService') randomName }`,
+      output: null,
+      options: [{ paths: ['app/components'], services: ['my-service'] }],
+      errors: [
+        {
+          message: DEFAULT_ERROR_MESSAGE,
+          // type could be ClassProperty (ESLint v7) or PropertyDefinition (ESLint v8)
+        },
+      ],
+    },
     {
       // With decorator with dasherized service name argument:
       filename: 'app/components/path.js',
@@ -236,5 +256,21 @@ ruleTester.run('no-restricted-service-injections', rule, {
       options: [{ services: ['my-service'] }],
       errors: [{ message: DEFAULT_ERROR_MESSAGE, type: 'Property' }],
     },
+
+    {
+      // TypeScript annotated injection (TypeScript).
+      code: `
+      import Route from '@ember/routing/route';
+      ${INJECT_IMPORT}
+      import type Store from '@ember-data/store';
+      export default class ApplicationRoute extends Route {
+        @inject declare store: Store;
+      }
+      `,
+      output: null,
+      options: [{ services: ['store'] }],
+      parser: require.resolve('@typescript-eslint/parser'),
+      errors: [{ message: DEFAULT_ERROR_MESSAGE, type: 'PropertyDefinition' }],
+    },
   ],
 });