diff --git a/CHANGELOG.md b/CHANGELOG.md index ca44284b72..d0e15af06c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange ## Unreleased ### Added +* [`forbid-dom-props`]: add `disallowedFor` option ([#3336][] @TildaDares) * [`jsx-newline`]: add `allowMultiline` option when prevent option is true ([#3311][] @TildaDares) ### Fixed @@ -18,6 +19,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange * [Tests] [`jsx-indent`], [`jsx-one-expression-per-line`]: add passing test cases ([#3314][] @ROSSROSALES) * [Refactor] `boolean-prop-naming`, `jsx-indent`: avoid assigning to arguments ([#3316][] @caroline223) +[#3336]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3336 [#3321]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3321 [#3320]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3320 [#3317]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3317 diff --git a/docs/rules/forbid-dom-props.md b/docs/rules/forbid-dom-props.md index 5e89b84ae7..ef687c72ed 100644 --- a/docs/rules/forbid-dom-props.md +++ b/docs/rules/forbid-dom-props.md @@ -43,12 +43,13 @@ Examples of **correct** code for this rule: ### `forbid` An array of strings, with the names of props that are forbidden. The default value of this option `[]`. -Each array element can either be a string with the property name or object specifying the property name and an optional -custom message: +Each array element can either be a string with the property name or object specifying the property name, an optional +custom message, and a DOM nodes blacklist(e.g. `
`): ```js { "propName": "someProp", + "disallowedFor": [DOMNode, AnotherDOMNode], "message": "Avoid using someProp" } ``` diff --git a/lib/rules/forbid-dom-props.js b/lib/rules/forbid-dom-props.js index 45beef4083..bd9cbf9d6f 100644 --- a/lib/rules/forbid-dom-props.js +++ b/lib/rules/forbid-dom-props.js @@ -47,6 +47,13 @@ module.exports = { propName: { type: 'string', }, + disallowedFor: { + type: 'array', + uniqueItems: true, + items: { + type: 'string', + }, + }, message: { type: 'string', }, @@ -66,13 +73,20 @@ module.exports = { const forbid = new Map((configuration.forbid || DEFAULTS).map((value) => { const propName = typeof value === 'string' ? value : value.propName; const options = { + disallowList: typeof value === 'string' ? [] : (value.disallowedFor || []), message: typeof value === 'string' ? null : value.message, }; return [propName, options]; })); - function isForbidden(prop) { - return forbid.has(prop); + function isForbidden(prop, tagName) { + const options = forbid.get(prop); + const disallowList = options ? options.disallowList : undefined; + return typeof disallowList !== 'undefined' + && (typeof tagName === 'undefined' + || disallowList.length === 0 + || (disallowList.length > 0 + && disallowList.indexOf(tagName) !== -1)); } return { @@ -85,7 +99,7 @@ module.exports = { const prop = node.name.name; - if (!isForbidden(prop)) { + if (!isForbidden(prop, tag)) { return; } diff --git a/tests/lib/rules/forbid-dom-props.js b/tests/lib/rules/forbid-dom-props.js index f95a0fe20a..157e4950be 100644 --- a/tests/lib/rules/forbid-dom-props.js +++ b/tests/lib/rules/forbid-dom-props.js @@ -95,6 +95,23 @@ ruleTester.run('forbid-dom-props', rule, { `, options: [{ forbid: ['id'] }], }, + { + code: ` + const First = (props) => ( +
+ ); + `, + options: [ + { + forbid: [ + { + propName: 'otherProp', + disallowedFor: ['span'], + }, + ], + }, + ], + }, ]), invalid: parsers.all([ @@ -237,5 +254,75 @@ ruleTester.run('forbid-dom-props', rule, { }, ], }, + { + code: ` + const First = (props) => ( +
+ + +
+ ); + `, + options: [ + { + forbid: [{ + propName: 'accept', + disallowedFor: ['form'], + message: 'Avoid using the accept attribute on
', + }], + }, + ], + errors: [ + { + message: 'Avoid using the accept attribute on ', + line: 3, + column: 17, + type: 'JSXAttribute', + }, + ], + }, + { + code: ` + const First = (props) => ( +
+ + Foobar +
+
+ ); + `, + options: [ + { + forbid: [ + { + propName: 'className', + disallowedFor: ['div', 'span'], + message: 'Please use class instead of ClassName', + }, + { propName: 'otherProp', message: 'Avoid using otherProp' }, + ], + }, + ], + errors: [ + { + message: 'Please use class instead of ClassName', + line: 3, + column: 16, + type: 'JSXAttribute', + }, + { + message: 'Please use class instead of ClassName', + line: 5, + column: 19, + type: 'JSXAttribute', + }, + { + message: 'Avoid using otherProp', + line: 6, + column: 18, + type: 'JSXAttribute', + }, + ], + }, ]), });