Repository: ember-cli/eslint-plugin-ember
Pull request #1197 (2021-05-13 23:52:32)

Check import when detecting controller usage in `order-in-*` rules
This PR fixes `isInjectedControllerProp` to take an additional parameter `importedControllerName` which checks for the name that `controller` was imported under instead of always "controller".


Patch:
diff --git a/lib/rules/order-in-components.js b/lib/rules/order-in-components.js
index 4c4855d6..99697570 100644
--- a/lib/rules/order-in-components.js
+++ b/lib/rules/order-in-components.js
@@ -88,6 +88,7 @@ module.exports = {
     let importedInjectName;
     let importedEmberName;
     let importedObserverName;
+    let importedControllerName;
 
     const sourceCode = context.getSourceCode();
     const { scopeManager } = sourceCode;
@@ -105,6 +106,10 @@ module.exports = {
           importedObserverName =
             importedObserverName || getImportIdentifier(node, '@ember/object', 'observer');
         }
+        if (node.source.value === '@ember/controller') {
+          importedControllerName =
+            importedControllerName || getImportIdentifier(node, '@ember/controller', 'inject');
+        }
       },
       CallExpression(node) {
         if (!ember.isEmberComponent(context, node)) {
@@ -119,6 +124,7 @@ module.exports = {
           importedEmberName,
           importedInjectName,
           importedObserverName,
+          importedControllerName,
           scopeManager
         );
       },
diff --git a/lib/rules/order-in-controllers.js b/lib/rules/order-in-controllers.js
index cbe66073..4bc85234 100644
--- a/lib/rules/order-in-controllers.js
+++ b/lib/rules/order-in-controllers.js
@@ -60,6 +60,7 @@ module.exports = {
     let importedInjectName;
     let importedEmberName;
     let importedObserverName;
+    let importedControllerName;
 
     const sourceCode = context.getSourceCode();
     const { scopeManager } = sourceCode;
@@ -77,6 +78,10 @@ module.exports = {
           importedObserverName =
             importedObserverName || getImportIdentifier(node, '@ember/object', 'observer');
         }
+        if (node.source.value === '@ember/controller') {
+          importedControllerName =
+            importedControllerName || getImportIdentifier(node, '@ember/controller', 'inject');
+        }
       },
       CallExpression(node) {
         if (!ember.isEmberController(context, node)) {
@@ -91,6 +96,7 @@ module.exports = {
           importedEmberName,
           importedInjectName,
           importedObserverName,
+          importedControllerName,
           scopeManager
         );
       },
diff --git a/lib/rules/order-in-models.js b/lib/rules/order-in-models.js
index a413d7bb..42b1df47 100644
--- a/lib/rules/order-in-models.js
+++ b/lib/rules/order-in-models.js
@@ -55,6 +55,7 @@ module.exports = {
     let importedInjectName;
     let importedEmberName;
     let importedObserverName;
+    let importedControllerName;
 
     const sourceCode = context.getSourceCode();
     const { scopeManager } = sourceCode;
@@ -72,6 +73,10 @@ module.exports = {
           importedObserverName =
             importedObserverName || getImportIdentifier(node, '@ember/object', 'observer');
         }
+        if (node.source.value === '@ember/controller') {
+          importedControllerName =
+            importedControllerName || getImportIdentifier(node, '@ember/controller', 'inject');
+        }
       },
       CallExpression(node) {
         if (!ember.isDSModel(node, filePath)) {
@@ -86,6 +91,7 @@ module.exports = {
           importedEmberName,
           importedInjectName,
           importedObserverName,
+          importedControllerName,
           scopeManager
         );
       },
diff --git a/lib/rules/order-in-routes.js b/lib/rules/order-in-routes.js
index 86298585..98a44212 100644
--- a/lib/rules/order-in-routes.js
+++ b/lib/rules/order-in-routes.js
@@ -83,6 +83,7 @@ module.exports = {
     let importedInjectName;
     let importedEmberName;
     let importedObserverName;
+    let importedControllerName;
 
     const sourceCode = context.getSourceCode();
     const { scopeManager } = sourceCode;
@@ -100,6 +101,10 @@ module.exports = {
           importedObserverName =
             importedObserverName || getImportIdentifier(node, '@ember/object', 'observer');
         }
+        if (node.source.value === '@ember/controller') {
+          importedControllerName =
+            importedControllerName || getImportIdentifier(node, '@ember/controller', 'inject');
+        }
       },
       CallExpression(node) {
         if (!ember.isEmberRoute(context, node)) {
@@ -113,6 +118,7 @@ module.exports = {
           importedEmberName,
           importedInjectName,
           importedObserverName,
+          importedControllerName,
           scopeManager
         );
       },
diff --git a/lib/utils/ember.js b/lib/utils/ember.js
index f366837b..503e9a5f 100644
--- a/lib/utils/ember.js
+++ b/lib/utils/ember.js
@@ -337,11 +337,12 @@ function isInjectedServiceProp(node, importedEmberName, importedInjectName) {
  * * Ember.inject.controller()
  * @param {node} node
  * @param {string} importedEmberName name that `Ember` is imported under
+ * @param {string} importedControllerName name that `controller` is imported under
  * @returns
  */
-function isInjectedControllerProp(node, importedEmberName) {
+function isInjectedControllerProp(node, importedEmberName, importedControllerName) {
   return (
-    isPropOfType(node, 'controller') ||
+    isPropOfType(node, importedControllerName) ||
     (types.isProperty(node) &&
       types.isCallExpression(node.value) &&
       types.isMemberExpression(node.value.callee) &&
diff --git a/lib/utils/property-order.js b/lib/utils/property-order.js
index 2d92d892..d663bca6 100644
--- a/lib/utils/property-order.js
+++ b/lib/utils/property-order.js
@@ -58,13 +58,14 @@ function determinePropertyType(
   ORDER,
   importedEmberName,
   importedInjectName,
-  importedObserverName
+  importedObserverName,
+  importedControllerName
 ) {
   if (ember.isInjectedServiceProp(node, importedEmberName, importedInjectName)) {
     return 'service';
   }
 
-  if (ember.isInjectedControllerProp(node, importedEmberName)) {
+  if (ember.isInjectedControllerProp(node, importedEmberName, importedControllerName)) {
     return 'controller';
   }
 
@@ -204,6 +205,7 @@ function reportUnorderedProperties(
   importedEmberName,
   importedInjectName,
   importedObserverName,
+  importedControllerName,
   scopeManager
 ) {
   let maxOrder = -1;
@@ -221,7 +223,8 @@ function reportUnorderedProperties(
       ORDER,
       importedEmberName,
       importedInjectName,
-      importedObserverName
+      importedObserverName,
+      importedControllerName
     );
     const order = getOrder(ORDER, type);
 


Test patch:
diff --git a/tests/lib/rules/order-in-controllers.js b/tests/lib/rules/order-in-controllers.js
index 9fcd9f9e..af735cd8 100644
--- a/tests/lib/rules/order-in-controllers.js
+++ b/tests/lib/rules/order-in-controllers.js
@@ -20,6 +20,7 @@ eslintTester.run('order-in-controllers', rule, {
     'export default Controller.extend({ ...foo });',
     `
       import {inject as service} from '@ember/service';
+      import {inject as controller} from '@ember/controller';
       export default Controller.extend({
         application: controller(),
         currentUser: service(),
@@ -87,7 +88,8 @@ eslintTester.run('order-in-controllers', rule, {
       ],
     },
     {
-      code: `export default Controller.extend({
+      code: `import {inject as controller} from '@ember/controller';
+      export default Controller.extend({
         queryParams: [],
         application: controller(),
       });`,
@@ -259,12 +261,14 @@ eslintTester.run('order-in-controllers', rule, {
       ],
     },
     {
-      code: `import {inject as service} from '@ember/service';
+      code: `import {inject as controller} from '@ember/controller';
+      import {inject as service} from '@ember/service';
       export default Controller.extend({
         currentUser: service(),
         application: controller()
       });`,
-      output: `import {inject as service} from '@ember/service';
+      output: `import {inject as controller} from '@ember/controller';
+      import {inject as service} from '@ember/service';
       export default Controller.extend({
         application: controller(),
               currentUser: service(),
@@ -272,8 +276,8 @@ eslintTester.run('order-in-controllers', rule, {
       errors: [
         {
           message:
-            'The "application" controller injection should be above the "currentUser" service injection on line 3',
-          line: 4,
+            'The "application" controller injection should be above the "currentUser" service injection on line 4',
+          line: 5,
         },
       ],
     },
diff --git a/tests/lib/utils/ember-test.js b/tests/lib/utils/ember-test.js
index 64aa4690..edab2dc5 100644
--- a/tests/lib/utils/ember-test.js
+++ b/tests/lib/utils/ember-test.js
@@ -1040,12 +1040,16 @@ describe('isInjectedControllerProp', () => {
   describe('classic classes', () => {
     it("should check if it's an injected controller prop with destructed import", () => {
       const context = new FauxContext(`
+        import {inject as controller} from '@ember/controller';
         export default Controller.extend({
           application: controller(),
         });
       `);
-      const node = context.ast.body[0].declaration.arguments[0].properties[0];
-      expect(emberUtils.isInjectedControllerProp(node)).toBeTruthy();
+      const importControllerName = context.ast.body[0].specifiers[0].local.name;
+      const node = context.ast.body[1].declaration.arguments[0].properties[0];
+      expect(
+        emberUtils.isInjectedControllerProp(node, undefined, importControllerName)
+      ).toBeTruthy();
     });
 
     it("should check if it's an injected controller prop with full import", () => {
@@ -1055,9 +1059,19 @@ describe('isInjectedControllerProp', () => {
           application: Ember.inject.controller(),
         });
       `);
-      const importName = context.ast.body[0].specifiers[0].local.name;
+      const importEmberName = context.ast.body[0].specifiers[0].local.name;
       const node = context.ast.body[1].declaration.arguments[0].properties[0];
-      expect(emberUtils.isInjectedControllerProp(node, importName)).toBeTruthy();
+      expect(emberUtils.isInjectedControllerProp(node, importEmberName)).toBeTruthy();
+    });
+
+    it("should check if it's not an injected controller prop without import", () => {
+      const context = new FauxContext(`
+        export default Controller.extend({
+          application: controller(),
+        });
+      `);
+      const node = context.ast.body[0].declaration.arguments[0].properties[0];
+      expect(emberUtils.isInjectedControllerProp(node)).toBeFalsy();
     });
 
     it("should check if it's not an injected controller prop without full import", () => {
@@ -1083,13 +1097,27 @@ describe('isInjectedControllerProp', () => {
 
   describe('native classes', () => {
     it("should check if it's an injected controller prop with decorator", () => {
+      const context = new FauxContext(`
+        import {inject as controller} from '@ember/controller';
+        class MyController extends Controller {
+          @controller application;
+        }
+      `);
+      const importControllerName = context.ast.body[0].specifiers[0].local.name;
+      const node = context.ast.body[1].body.body[0];
+      expect(
+        emberUtils.isInjectedControllerProp(node, undefined, importControllerName)
+      ).toBeTruthy();
+    });
+
+    it("should check if it's not an injected controller prop with decorator without import", () => {
       const context = new FauxContext(`
         class MyController extends Controller {
           @controller application;
         }
       `);
       const node = context.ast.body[0].body.body[0];
-      expect(emberUtils.isInjectedControllerProp(node)).toBeTruthy();
+      expect(emberUtils.isInjectedControllerProp(node)).toBeFalsy();
     });
 
     it("should check that it's not an injected controller prop", () => {
diff --git a/tests/lib/utils/property-order-test.js b/tests/lib/utils/property-order-test.js
index bc3fb6b7..35b9c5a3 100644
--- a/tests/lib/utils/property-order-test.js
+++ b/tests/lib/utils/property-order-test.js
@@ -78,12 +78,24 @@ describe('determinePropertyType', () => {
 
     it('should determine controller-type props', () => {
       const context = new FauxContext(
-        `export default Controller.extend({
+        `import {inject as controller} from '@ember/controller';
+        export default Controller.extend({
           application: controller(),
         });`
       );
-      const node = context.ast.body[0].declaration.arguments[0].properties[0];
-      expect(propertyOrder.determinePropertyType(node, 'controller')).toStrictEqual('controller');
+      const importControllerName = context.ast.body[0].specifiers[0].local.name;
+      const node = context.ast.body[1].declaration.arguments[0].properties[0];
+      expect(
+        propertyOrder.determinePropertyType(
+          node,
+          'controller',
+          [],
+          undefined,
+          undefined,
+          undefined,
+          importControllerName
+        )
+      ).toStrictEqual('controller');
     });
 
     it('should determine init-type props', () => {
@@ -318,12 +330,24 @@ describe('determinePropertyType', () => {
 
     it('should determine controller-type props', () => {
       const context = new FauxContext(
-        `class MyController extends Controller {
+        `import {inject as controller} from '@ember/controller';
+        class MyController extends Controller {
           @controller application;
         }`
       );
-      const node = context.ast.body[0].body.body[0];
-      expect(propertyOrder.determinePropertyType(node, 'controller')).toStrictEqual('controller');
+      const importControllerName = context.ast.body[0].specifiers[0].local.name;
+      const node = context.ast.body[1].body.body[0];
+      expect(
+        propertyOrder.determinePropertyType(
+          node,
+          'controller',
+          [],
+          undefined,
+          undefined,
+          undefined,
+          importControllerName
+        )
+      ).toStrictEqual('controller');
     });
 
     it('should determine init-type props', () => {
@@ -431,7 +455,8 @@ describe('reportUnorderedProperties', () => {
       const order = ['controller', 'service', 'query-params'];
       const context = new FauxContext(
         `import {inject as service} from '@ember/service';
-          export default Controller.extend({
+        import {inject as controller} from '@ember/controller';
+        export default Controller.extend({
           application: controller(),
           currentUser: service(),
           queryParams: [],
@@ -440,7 +465,8 @@ describe('reportUnorderedProperties', () => {
         jest.fn()
       );
       const importInjectName = context.ast.body[0].specifiers[0].local.name;
-      const node = context.ast.body[1].declaration;
+      const importControllerName = context.ast.body[1].specifiers[0].local.name;
+      const node = context.ast.body[2].declaration;
 
       propertyOrder.reportUnorderedProperties(
         node,
@@ -449,7 +475,8 @@ describe('reportUnorderedProperties', () => {
         order,
         undefined,
         importInjectName,
-        undefined
+        undefined,
+        importControllerName
       );
       expect(context.report).not.toHaveBeenCalled();
     });
@@ -458,7 +485,8 @@ describe('reportUnorderedProperties', () => {
       const order = ['controller', 'service', 'query-params'];
       const context = new FauxContext(
         `import {inject as service} from '@ember/service';
-          export default Controller.extend({
+        import {inject as controller} from '@ember/controller';
+        export default Controller.extend({
             currentUser: service(),
             application: controller(),
             queryParams: [],
@@ -467,7 +495,8 @@ describe('reportUnorderedProperties', () => {
         jest.fn()
       );
       const importInjectName = context.ast.body[0].specifiers[0].local.name;
-      const node = context.ast.body[1].declaration;
+      const importControllerName = context.ast.body[1].specifiers[0].local.name;
+      const node = context.ast.body[2].declaration;
 
       propertyOrder.reportUnorderedProperties(
         node,
@@ -475,7 +504,9 @@ describe('reportUnorderedProperties', () => {
         'controller',
         order,
         undefined,
-        importInjectName
+        importInjectName,
+        undefined,
+        importControllerName
       );
       expect(context.report).toHaveBeenCalled(); // eslint-disable-line jest/prefer-called-with
     });
@@ -486,7 +517,8 @@ describe('reportUnorderedProperties', () => {
       const order = ['controller', 'service', 'query-params'];
       const context = new FauxContext(
         `import {inject as service} from '@ember/service';
-          export default class MyController extends Controller {
+        import {inject as controller} from '@ember/controller';
+        export default class MyController extends Controller {
             @controller application;
             @service currentUser;
             queryParams = [];
@@ -495,7 +527,8 @@ describe('reportUnorderedProperties', () => {
         jest.fn()
       );
       const importInjectName = context.ast.body[0].specifiers[0].local.name;
-      const node = context.ast.body[1].declaration;
+      const importControllerName = context.ast.body[1].specifiers[0].local.name;
+      const node = context.ast.body[2].declaration;
 
       propertyOrder.reportUnorderedProperties(
         node,
@@ -503,7 +536,9 @@ describe('reportUnorderedProperties', () => {
         'controller',
         order,
         undefined,
-        importInjectName
+        importInjectName,
+        undefined,
+        importControllerName
       );
       expect(context.report).not.toHaveBeenCalled();
     });
@@ -512,7 +547,8 @@ describe('reportUnorderedProperties', () => {
       const order = ['controller', 'service', 'query-params'];
       const context = new FauxContext(
         `import {inject as service} from '@ember/service';
-          export default class MyController extends Controller {
+        import {inject as controller} from '@ember/controller';
+        export default class MyController extends Controller {
             @service currentUser;
             @controller application;
             queryParams = [];
@@ -521,7 +557,8 @@ describe('reportUnorderedProperties', () => {
         jest.fn()
       );
       const importInjectName = context.ast.body[0].specifiers[0].local.name;
-      const node = context.ast.body[1].declaration;
+      const importControllerName = context.ast.body[1].specifiers[0].local.name;
+      const node = context.ast.body[2].declaration;
 
       propertyOrder.reportUnorderedProperties(
         node,
@@ -529,7 +566,9 @@ describe('reportUnorderedProperties', () => {
         'controller',
         order,
         undefined,
-        importInjectName
+        importInjectName,
+        undefined,
+        importControllerName
       );
       expect(context.report).toHaveBeenCalled(); // eslint-disable-line jest/prefer-called-with
     });