Skip to content

Commit b3a3937

Browse files
TildaDaresljharb
authored andcommitted
[New] forbid-dom-props: add disallowedFor option
1 parent 8baf0c5 commit b3a3937

File tree

4 files changed

+118
-10
lines changed

4 files changed

+118
-10
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
77

88
### Added
99
* [`jsx-newline`]: add `allowMultiline` option when prevent option is true ([#3311][] @TildaDares)
10+
* [`forbid-dom-props`]: add `disallowedFor` option ([#3338][] @TildaDares)
1011

1112
### Fixed
1213
* [`jsx-no-literals`]: properly error on children with noAttributeStrings: true ([#3317][] @TildaDares)
@@ -32,6 +33,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
3233
[#3347]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3347
3334
[#3344]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3344
3435
[#3339]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3339
36+
[#3338]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3338
3537
[#3335]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3335
3638
[#3331]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3331
3739
[#3328]: https://github.com/jsx-eslint/eslint-plugin-react/issues/3328

docs/rules/forbid-dom-props.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,13 @@ Examples of **correct** code for this rule:
4343
### `forbid`
4444

4545
An array of strings, with the names of props that are forbidden. The default value of this option `[]`.
46-
Each array element can either be a string with the property name or object specifying the property name and an optional
47-
custom message:
46+
Each array element can either be a string with the property name or object specifying the property name, an optional
47+
custom message, and a DOM nodes disallowed list (e.g. `<div />`):
4848

4949
```js
5050
{
5151
"propName": "someProp",
52+
"disallowedFor": ["DOMNode", "AnotherDOMNode"],
5253
"message": "Avoid using someProp"
5354
}
5455
```

lib/rules/forbid-dom-props.js

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,21 @@ const DEFAULTS = [];
1818
// Rule Definition
1919
// ------------------------------------------------------------------------------
2020

21+
/**
22+
* @param {Map<string, object>} forbidMap // { disallowList: null | string[], message: null | string }
23+
* @param {string} prop
24+
* @param {string} tagName
25+
* @returns {boolean}
26+
*/
27+
function isForbidden(forbidMap, prop, tagName) {
28+
const options = forbidMap.get(prop);
29+
return options && (
30+
typeof tagName === 'undefined'
31+
|| !options.disallowList
32+
|| options.disallowList.indexOf(tagName) !== -1
33+
);
34+
}
35+
2136
const messages = {
2237
propIsForbidden: 'Prop "{{prop}}" is forbidden on DOM Nodes',
2338
};
@@ -47,6 +62,13 @@ module.exports = {
4762
propName: {
4863
type: 'string',
4964
},
65+
disallowedFor: {
66+
type: 'array',
67+
uniqueItems: true,
68+
items: {
69+
type: 'string',
70+
},
71+
},
5072
message: {
5173
type: 'string',
5274
},
@@ -65,16 +87,12 @@ module.exports = {
6587
const configuration = context.options[0] || {};
6688
const forbid = new Map((configuration.forbid || DEFAULTS).map((value) => {
6789
const propName = typeof value === 'string' ? value : value.propName;
68-
const options = {
90+
return [propName, {
91+
disallowList: typeof value === 'string' ? null : (value.disallowedFor || null),
6992
message: typeof value === 'string' ? null : value.message,
70-
};
71-
return [propName, options];
93+
}];
7294
}));
7395

74-
function isForbidden(prop) {
75-
return forbid.has(prop);
76-
}
77-
7896
return {
7997
JSXAttribute(node) {
8098
const tag = node.parent.name.name;
@@ -85,7 +103,7 @@ module.exports = {
85103

86104
const prop = node.name.name;
87105

88-
if (!isForbidden(prop)) {
106+
if (!isForbidden(forbid, prop, tag)) {
89107
return;
90108
}
91109

tests/lib/rules/forbid-dom-props.js

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,23 @@ ruleTester.run('forbid-dom-props', rule, {
9595
`,
9696
options: [{ forbid: ['id'] }],
9797
},
98+
{
99+
code: `
100+
const First = (props) => (
101+
<div otherProp="bar" />
102+
);
103+
`,
104+
options: [
105+
{
106+
forbid: [
107+
{
108+
propName: 'otherProp',
109+
disallowedFor: ['span'],
110+
},
111+
],
112+
},
113+
],
114+
},
98115
]),
99116

100117
invalid: parsers.all([
@@ -237,5 +254,75 @@ ruleTester.run('forbid-dom-props', rule, {
237254
},
238255
],
239256
},
257+
{
258+
code: `
259+
const First = (props) => (
260+
<form accept='file'>
261+
<input type="file" id="videoFile" accept="video/*" />
262+
<input type="hidden" name="fullname" />
263+
</form>
264+
);
265+
`,
266+
options: [
267+
{
268+
forbid: [{
269+
propName: 'accept',
270+
disallowedFor: ['form'],
271+
message: 'Avoid using the accept attribute on <form>',
272+
}],
273+
},
274+
],
275+
errors: [
276+
{
277+
message: 'Avoid using the accept attribute on <form>',
278+
line: 3,
279+
column: 17,
280+
type: 'JSXAttribute',
281+
},
282+
],
283+
},
284+
{
285+
code: `
286+
const First = (props) => (
287+
<div className="foo">
288+
<input className="boo" />
289+
<span className="foobar">Foobar</span>
290+
<div otherProp="bar" />
291+
</div>
292+
);
293+
`,
294+
options: [
295+
{
296+
forbid: [
297+
{
298+
propName: 'className',
299+
disallowedFor: ['div', 'span'],
300+
message: 'Please use class instead of ClassName',
301+
},
302+
{ propName: 'otherProp', message: 'Avoid using otherProp' },
303+
],
304+
},
305+
],
306+
errors: [
307+
{
308+
message: 'Please use class instead of ClassName',
309+
line: 3,
310+
column: 16,
311+
type: 'JSXAttribute',
312+
},
313+
{
314+
message: 'Please use class instead of ClassName',
315+
line: 5,
316+
column: 19,
317+
type: 'JSXAttribute',
318+
},
319+
{
320+
message: 'Avoid using otherProp',
321+
line: 6,
322+
column: 18,
323+
type: 'JSXAttribute',
324+
},
325+
],
326+
},
240327
]),
241328
});

0 commit comments

Comments
 (0)