Repository: yannickcr/eslint-plugin-react (js)

Issue:
forbid-component-props should have a component whitelist
For custom components it makes sense to have the rule, but when using third-party components violating the rule (`ReactModal` using `className` is probably one of the more prominent examples) there isn't much you can do about it...

Having to add `eslint-disable react/forbid-component-props` comments isn't a very pretty solution.

Pull request description:
forbid-component-props: add component whitelist
Docs are still missing ;)

fixes #1732

Patch:
diff --git a/docs/rules/forbid-component-props.md b/docs/rules/forbid-component-props.md
index eb557df8..8e0ece52 100644
--- a/docs/rules/forbid-component-props.md
+++ b/docs/rules/forbid-component-props.md
@@ -35,13 +35,21 @@ The following patterns are **not** considered warnings:
 
 ```js
 ...
-"react/forbid-component-props": [<enabled>, { "forbid": [<string>] }]
+"react/forbid-component-props": [<enabled>, { "forbid": [<string>|<object>] }]
 ...
 ```
 
 ### `forbid`
 
-An array of strings, with the names of props that are forbidden. The default value of this option is `['className', 'style']`.
+An array specifying the names of props that are forbidden. The default value of this option is `['className', 'style']`.
+Each array element can either be a string with the property name or object specifying the property name and a component whitelist:
+
+```js
+{
+  "propName": "someProp",
+  "allowedFor": [SomeComponent, AnotherComponent]
+}
+```
 
 
 ### Related rules
diff --git a/docs/rules/jsx-max-depth.md b/docs/rules/jsx-max-depth.md
index 0426c09b..492d055e 100644
--- a/docs/rules/jsx-max-depth.md
+++ b/docs/rules/jsx-max-depth.md
@@ -23,7 +23,7 @@ It takes an option as the second parameter which can be a positive number for de
 
 ```js
 ...
-"react/jsx-max-depth": [<enabled>, { "max": <number> }]
+"react/jsx-no-depth": [<enabled>, { "max": <number> }]
 ...
 ```
 
diff --git a/lib/rules/forbid-component-props.js b/lib/rules/forbid-component-props.js
index 9c0b0729..7bf1431d 100644
--- a/lib/rules/forbid-component-props.js
+++ b/lib/rules/forbid-component-props.js
@@ -31,20 +31,41 @@ module.exports = {
         forbid: {
           type: 'array',
           items: {
-            type: 'string'
+            oneOf: [{
+              type: 'string'
+            }, {
+              type: 'object',
+              properties: {
+                propName: {
+                  type: 'string'
+                },
+                allowedFor: {
+                  type: 'array',
+                  uniqueItems: true,
+                  items: {
+                    type: 'string'
+                  }
+                }
+              }
+            }]
           }
         }
-      },
-      additionalProperties: true
+      }
     }]
   },
 
   create: function(context) {
-    function isForbidden(prop) {
-      const configuration = context.options[0] || {};
+    const configuration = context.options[0] || {};
+    const forbid = new Map((configuration.forbid || DEFAULTS).map(value => {
+      const propName = typeof value === 'string' ? value : value.propName;
+      const whitelist = typeof value === 'string' ? [] : (value.allowedFor || []);
+      return [propName, whitelist];
+    }));
 
-      const forbid = configuration.forbid || DEFAULTS;
-      return forbid.indexOf(prop) >= 0;
+    function isForbidden(prop, tagName) {
+      const whitelist = forbid.get(prop);
+      // if the tagName is undefined (`<this.something>`), we assume it's a forbidden element
+      return typeof whitelist !== 'undefined' && (typeof tagName === 'undefined' || whitelist.indexOf(tagName) === -1);
     }
 
     return {
@@ -57,7 +78,7 @@ module.exports = {
 
         const prop = node.name.name;
 
-        if (!isForbidden(prop)) {
+        if (!isForbidden(prop, tag)) {
           return;
         }
 


Test patch:
diff --git a/tests/lib/rules/forbid-component-props.js b/tests/lib/rules/forbid-component-props.js
index dc7012ab..1c9fc6b8 100644
--- a/tests/lib/rules/forbid-component-props.js
+++ b/tests/lib/rules/forbid-component-props.js
@@ -101,6 +101,11 @@ ruleTester.run('forbid-component-props', rule, {
       '  <this.Foo {...props} />',
       ');'
     ].join('\n')
+  }, {
+    code: 'const item = (<ReactModal className="foo" />);',
+    options: [{
+      forbid: [{propName: 'className', allowedFor: ['ReactModal']}]
+    }]
   }],
 
   invalid: [{
@@ -165,5 +170,27 @@ ruleTester.run('forbid-component-props', rule, {
       column: 17,
       type: 'JSXAttribute'
     }]
+  }, {
+    code: 'const item = (<Foo className="foo" />);',
+    options: [{
+      forbid: [{propName: 'className', allowedFor: ['ReactModal']}]
+    }],
+    errors: [{
+      message: CLASSNAME_ERROR_MESSAGE,
+      line: 1,
+      column: 20,
+      type: 'JSXAttribute'
+    }]
+  }, {
+    code: 'const item = (<this.ReactModal className="foo" />);',
+    options: [{
+      forbid: [{propName: 'className', allowedFor: ['ReactModal']}]
+    }],
+    errors: [{
+      message: CLASSNAME_ERROR_MESSAGE,
+      line: 1,
+      column: 32,
+      type: 'JSXAttribute'
+    }]
   }]
 });