Repository: ember-cli/eslint-plugin-ember
Pull request #565 (2019-11-02 20:43:47)

Add `ignoreNestedPaths` option (default true) to `no-get` rule
Having this rule ignore nested paths like `this.get('some.nested.property')` (which is the default behavior) can be helpful while adopting this rule to avoid breaking existing code. But long-term, developers may want to entirely get rid of `get()` usage, and can use this new option to do so.


Patch:
diff --git a/docs/rules/no-get.md b/docs/rules/no-get.md
index 918c43eb..56b4e49d 100644
--- a/docs/rules/no-get.md
+++ b/docs/rules/no-get.md
@@ -60,6 +60,7 @@ const foo = { prop1: this.prop1, prop2: this.prop2 };
 This rule takes an optional object containing:
 
 - `boolean` -- `ignoreGetProperties` -- whether the rule should ignore `getProperties` (default `false`)
+- `boolean` -- `ignoreNestedPaths` -- whether the rule should ignore `this.get('some.nested.property')` (default `true`) (this option is enabled by default to make it easier/safer to adopt this rule)
 
 ## Related Rules
 
diff --git a/lib/rules/no-get.js b/lib/rules/no-get.js
index 4b9df273..6468eba3 100644
--- a/lib/rules/no-get.js
+++ b/lib/rules/no-get.js
@@ -28,6 +28,10 @@ module.exports = {
             type: 'boolean',
             default: false,
           },
+          ignoreNestedPaths: {
+            type: 'boolean',
+            default: true,
+          },
         },
         additionalProperties: false,
       },
@@ -36,6 +40,7 @@ module.exports = {
   create(context) {
     // Options:
     const ignoreGetProperties = context.options[0] && context.options[0].ignoreGetProperties;
+    const ignoreNestedPaths = !context.options[0] || context.options[0].ignoreNestedPaths;
 
     return {
       // eslint-disable-next-line complexity
@@ -51,7 +56,7 @@ module.exports = {
           node.callee.property.name === 'get' &&
           node.arguments.length === 1 &&
           types.isStringLiteral(node.arguments[0]) &&
-          !node.arguments[0].value.includes('.')
+          (!node.arguments[0].value.includes('.') || !ignoreNestedPaths)
         ) {
           // Example: this.get('foo');
           context.report(node, makeErrorMessageForGet(node.arguments[0].value), false);
@@ -63,7 +68,7 @@ module.exports = {
           node.arguments.length === 2 &&
           types.isThisExpression(node.arguments[0]) &&
           types.isStringLiteral(node.arguments[1]) &&
-          !node.arguments[1].value.includes('.')
+          (!node.arguments[1].value.includes('.') || !ignoreNestedPaths)
         ) {
           // Example: get(this, 'foo');
           context.report(node, makeErrorMessageForGet(node.arguments[1].value, true));
@@ -82,7 +87,7 @@ module.exports = {
           types.isThisExpression(node.callee.object) &&
           types.isIdentifier(node.callee.property) &&
           node.callee.property.name === 'getProperties' &&
-          validateGetPropertiesArguments(node.arguments)
+          validateGetPropertiesArguments(node.arguments, ignoreNestedPaths)
         ) {
           // Example: this.getProperties('foo', 'bar');
           context.report(node, ERROR_MESSAGE_GET_PROPERTIES);
@@ -92,7 +97,7 @@ module.exports = {
           types.isIdentifier(node.callee) &&
           node.callee.name === 'getProperties' &&
           types.isThisExpression(node.arguments[0]) &&
-          validateGetPropertiesArguments(node.arguments.slice(1))
+          validateGetPropertiesArguments(node.arguments.slice(1), ignoreNestedPaths)
         ) {
           // Example: getProperties(this, 'foo', 'bar');
           context.report(node, ERROR_MESSAGE_GET_PROPERTIES);
@@ -102,10 +107,13 @@ module.exports = {
   },
 };
 
-function validateGetPropertiesArguments(args) {
+function validateGetPropertiesArguments(args, ignoreNestedPaths) {
   if (args.length === 1 && types.isArrayExpression(args[0])) {
-    return validateGetPropertiesArguments(args[0].elements);
+    return validateGetPropertiesArguments(args[0].elements, ignoreNestedPaths);
   }
   // We can only handle string arguments without nested property paths.
-  return args.every(argument => types.isStringLiteral(argument) && !argument.value.includes('.'));
+  return args.every(
+    argument =>
+      types.isStringLiteral(argument) && (!argument.value.includes('.') || !ignoreNestedPaths)
+  );
 }


Test patch:
diff --git a/tests/lib/rules/no-get.js b/tests/lib/rules/no-get.js
index 9874fa2b..4655f52b 100644
--- a/tests/lib/rules/no-get.js
+++ b/tests/lib/rules/no-get.js
@@ -146,5 +146,31 @@ ruleTester.run('no-get', rule, {
       output: null,
       errors: [{ message: ERROR_MESSAGE_GET_PROPERTIES, type: 'CallExpression' }],
     },
+
+    // With ignoreNestedPaths: false
+    {
+      code: "this.get('foo.bar');",
+      output: null,
+      options: [{ ignoreNestedPaths: false }],
+      errors: [{ message: makeErrorMessageForGet('foo.bar', false), type: 'CallExpression' }],
+    },
+    {
+      code: "get(this, 'foo.bar');",
+      output: null,
+      options: [{ ignoreNestedPaths: false }],
+      errors: [{ message: makeErrorMessageForGet('foo.bar', true), type: 'CallExpression' }],
+    },
+    {
+      code: "this.getProperties('foo.bar');",
+      output: null,
+      options: [{ ignoreNestedPaths: false }],
+      errors: [{ message: ERROR_MESSAGE_GET_PROPERTIES, type: 'CallExpression' }],
+    },
+    {
+      code: "getProperties(this, 'foo.bar');",
+      output: null,
+      options: [{ ignoreNestedPaths: false }],
+      errors: [{ message: ERROR_MESSAGE_GET_PROPERTIES, type: 'CallExpression' }],
+    },
   ],
 });