Repository: ember-cli/eslint-plugin-ember
Pull request #913 (2020-08-13 19:48:14)

Add `catchUnsafeObjects` option (default false) to `no-get` rule to catch `foo.get('bar')`
Add option for this who want to catch this situation where we aren't sure if the object is an Ember object.

Before:

```js
foo.get('bar');
```

After:

```js
foo.bar;
```

Follow-up to adding `catchSafeObjects` in #912.


Patch:
diff --git a/docs/rules/no-get.md b/docs/rules/no-get.md
index 6c979842..391dcee4 100644
--- a/docs/rules/no-get.md
+++ b/docs/rules/no-get.md
@@ -95,6 +95,7 @@ This rule takes an optional object containing:
 * `boolean` -- `ignoreNestedPaths` -- whether the rule should ignore `this.get('some.nested.property')` (default `false`)
 * `boolean` -- `useOptionalChaining` -- whether the rule should use the [optional chaining operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining) `?.` to autofix nested paths such as `this.get('some.nested.property')` to `this.some?.nested?.property` (when this option is off, these nested paths won't be autofixed at all) (default `false`)
 * `boolean` -- `catchSafeObjects` -- whether the rule should catch `get(foo, 'bar')` (default `false`, TODO: enable in next major release)
+* `boolean` -- `catchUnsafeObjects` -- whether the rule should catch `foo.get('bar')` even though we don't know for sure if `foo` is an Ember object (default `false`)
 
 ## Related Rules
 
diff --git a/lib/rules/no-get.js b/lib/rules/no-get.js
index 8f7fac97..994f2bef 100644
--- a/lib/rules/no-get.js
+++ b/lib/rules/no-get.js
@@ -106,6 +106,10 @@ module.exports = {
             type: 'boolean',
             default: false,
           },
+          catchUnsafeObjects: {
+            type: 'boolean',
+            default: false,
+          },
         },
         additionalProperties: false,
       },
@@ -117,6 +121,7 @@ module.exports = {
     const ignoreNestedPaths = context.options[0] && context.options[0].ignoreNestedPaths;
     const useOptionalChaining = context.options[0] && context.options[0].useOptionalChaining;
     const catchSafeObjects = context.options[0] && context.options[0].catchSafeObjects;
+    const catchUnsafeObjects = context.options[0] && context.options[0].catchUnsafeObjects;
 
     if (ignoreNestedPaths && useOptionalChaining) {
       assert(
@@ -199,7 +204,7 @@ module.exports = {
 
         if (
           types.isMemberExpression(node.callee) &&
-          types.isThisExpression(node.callee.object) &&
+          (types.isThisExpression(node.callee.object) || catchUnsafeObjects) &&
           types.isIdentifier(node.callee.property) &&
           node.callee.property.name === 'get' &&
           node.arguments.length === 1 &&
@@ -207,13 +212,14 @@ module.exports = {
           (!node.arguments[0].value.includes('.') || !ignoreNestedPaths)
         ) {
           // Example: this.get('foo');
+          const sourceCode = context.getSourceCode();
           reportGet({
             node,
             context,
             path: node.arguments[0].value,
             isImportedGet: false,
             useOptionalChaining,
-            objectText: 'this',
+            objectText: sourceCode.getText(node.callee.object),
           });
         }
 
@@ -247,7 +253,7 @@ module.exports = {
 
         if (
           types.isMemberExpression(node.callee) &&
-          types.isThisExpression(node.callee.object) &&
+          (types.isThisExpression(node.callee.object) || catchUnsafeObjects) &&
           types.isIdentifier(node.callee.property) &&
           node.callee.property.name === 'getProperties' &&
           validateGetPropertiesArguments(node.arguments, ignoreNestedPaths)


Test patch:
diff --git a/tests/lib/rules/no-get.js b/tests/lib/rules/no-get.js
index 6727d50a..217232c5 100644
--- a/tests/lib/rules/no-get.js
+++ b/tests/lib/rules/no-get.js
@@ -190,6 +190,12 @@ ruleTester.run('no-get', rule, {
       output: 'this.foo;',
       errors: [{ message: ERROR_MESSAGE_GET, type: 'CallExpression' }],
     },
+    {
+      code: "foo1.foo2.get('bar');",
+      options: [{ catchUnsafeObjects: true }],
+      output: 'foo1.foo2.bar;',
+      errors: [{ message: ERROR_MESSAGE_GET, type: 'CallExpression' }],
+    },
     {
       code: `
       import { get } from '@ember/object';
@@ -272,6 +278,12 @@ ruleTester.run('no-get', rule, {
       output: null,
       errors: [{ message: ERROR_MESSAGE_GET_PROPERTIES, type: 'CallExpression' }],
     },
+    {
+      code: "foo.getProperties('prop1', 'prop2');",
+      options: [{ catchUnsafeObjects: true }],
+      output: null,
+      errors: [{ message: ERROR_MESSAGE_GET_PROPERTIES, type: 'CallExpression' }],
+    },
     {
       code: "this.getProperties(['prop1', 'prop2']);", // With parameters in array.
       output: null,