Skip to content

Commit c072c89

Browse files
authored
Merge pull request #1562 from davazp/add-forbid-dom-props-rule
Add a forbid-dom-props rule
2 parents af6ccb0 + 268a704 commit c072c89

File tree

6 files changed

+259
-0
lines changed

6 files changed

+259
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ Enable the rules that you would like to use.
9393
* [react/destructuring-assignment](docs/rules/destructuring-assignment.md): Rule enforces consistent usage of destructuring assignment in component
9494
* [react/display-name](docs/rules/display-name.md): Prevent missing `displayName` in a React component definition
9595
* [react/forbid-component-props](docs/rules/forbid-component-props.md): Forbid certain props on Components
96+
* [react/forbid-dom-props](docs/rules/forbid-dom-props.md): Forbid certain props on DOM Nodes
9697
* [react/forbid-elements](docs/rules/forbid-elements.md): Forbid certain elements
9798
* [react/forbid-prop-types](docs/rules/forbid-prop-types.md): Forbid certain propTypes
9899
* [react/forbid-foreign-prop-types](docs/rules/forbid-foreign-prop-types.md): Forbid foreign propTypes

docs/rules/forbid-component-props.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,8 @@ The following patterns are **not** considered warnings:
4242
### `forbid`
4343

4444
An array of strings, with the names of props that are forbidden. The default value of this option is `['className', 'style']`.
45+
46+
47+
### Related rules
48+
49+
- [forbid-dom-props](./forbid-dom-props.md)

docs/rules/forbid-dom-props.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Forbid certain props on DOM Nodes (react/forbid-dom-props)
2+
3+
This rule prevents passing of props to elements. This rule only applies to DOM Nodes (e.g. `<div />`) and not Components (e.g. `<Component />`).
4+
The list of forbidden props can be customized with the `forbid` option.
5+
6+
## Rule Details
7+
8+
This rule checks all JSX elements and verifies that no forbidden props are used
9+
on DOM Nodes. This rule is off by default.
10+
11+
The following patterns are considered warnings:
12+
13+
```jsx
14+
// [1, { "forbid": ["id"] }]
15+
<div id='Joe' />
16+
```
17+
18+
```jsx
19+
// [1, { "forbid": ["style"] }]
20+
<div style={{color: 'red'}} />
21+
```
22+
23+
The following patterns are **not** considered warnings:
24+
25+
```jsx
26+
// [1, { "forbid": ["id"] }]
27+
<Hello id='foo' />
28+
```
29+
30+
```jsx
31+
// [1, { "forbid": ["id"] }]
32+
<Hello id={{color: 'red'}} />
33+
```
34+
35+
## Rule Options
36+
37+
```js
38+
...
39+
"react/forbid-dom-props": [<enabled>, { "forbid": [<string>] }]
40+
...
41+
```
42+
43+
### `forbid`
44+
45+
An array of strings, with the names of props that are forbidden. The default value of this option `[]`.
46+
47+
48+
### Related rules
49+
50+
- [forbid-component-props](./forbid-component-props.md)

index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const allRules = {
88
'destructuring-assignment': require('./lib/rules/destructuring-assignment'),
99
'display-name': require('./lib/rules/display-name'),
1010
'forbid-component-props': require('./lib/rules/forbid-component-props'),
11+
'forbid-dom-props': require('./lib/rules/forbid-dom-props'),
1112
'forbid-elements': require('./lib/rules/forbid-elements'),
1213
'forbid-prop-types': require('./lib/rules/forbid-prop-types'),
1314
'forbid-foreign-prop-types': require('./lib/rules/forbid-foreign-prop-types'),

lib/rules/forbid-dom-props.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/**
2+
* @fileoverview Forbid certain props on DOM Nodes
3+
* @author David Vázquez
4+
*/
5+
'use strict';
6+
7+
// ------------------------------------------------------------------------------
8+
// Constants
9+
// ------------------------------------------------------------------------------
10+
11+
const DEFAULTS = [];
12+
13+
// ------------------------------------------------------------------------------
14+
// Rule Definition
15+
// ------------------------------------------------------------------------------
16+
17+
module.exports = {
18+
meta: {
19+
docs: {
20+
description: 'Forbid certain props on DOM Nodes',
21+
category: 'Best Practices',
22+
recommended: false
23+
},
24+
25+
schema: [{
26+
type: 'object',
27+
properties: {
28+
forbid: {
29+
type: 'array',
30+
items: {
31+
type: 'string',
32+
minLength: 1
33+
},
34+
uniqueItems: true
35+
}
36+
},
37+
additionalProperties: false
38+
}]
39+
},
40+
41+
create: function(context) {
42+
function isForbidden(prop) {
43+
const configuration = context.options[0] || {};
44+
45+
const forbid = configuration.forbid || DEFAULTS;
46+
return forbid.indexOf(prop) >= 0;
47+
}
48+
49+
return {
50+
JSXAttribute: function(node) {
51+
const tag = node.parent.name.name;
52+
if (!(tag && tag[0] !== tag[0].toUpperCase())) {
53+
// This is a Component, not a DOM node, so exit.
54+
return;
55+
}
56+
57+
const prop = node.name.name;
58+
59+
if (!isForbidden(prop)) {
60+
return;
61+
}
62+
63+
context.report({
64+
node: node,
65+
message: `Prop \`${prop}\` is forbidden on DOM Nodes`
66+
});
67+
}
68+
};
69+
}
70+
};

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

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/**
2+
* @fileoverview Tests for forbid-dom-props
3+
*/
4+
'use strict';
5+
6+
// -----------------------------------------------------------------------------
7+
// Requirements
8+
// -----------------------------------------------------------------------------
9+
10+
const rule = require('../../../lib/rules/forbid-dom-props');
11+
const RuleTester = require('eslint').RuleTester;
12+
13+
const parserOptions = {
14+
ecmaVersion: 8,
15+
sourceType: 'module',
16+
ecmaFeatures: {
17+
experimentalObjectRestSpread: true,
18+
jsx: true
19+
}
20+
};
21+
22+
require('babel-eslint');
23+
24+
// -----------------------------------------------------------------------------
25+
// Tests
26+
// -----------------------------------------------------------------------------
27+
28+
const ID_ERROR_MESSAGE = 'Prop `id` is forbidden on DOM Nodes';
29+
30+
const ruleTester = new RuleTester({parserOptions});
31+
ruleTester.run('forbid-element-props', rule, {
32+
33+
valid: [{
34+
code: [
35+
'var First = createReactClass({',
36+
' render: function() {',
37+
' return <Foo id="foo" />;',
38+
' }',
39+
'});'
40+
].join('\n'),
41+
options: [{forbid: ['id']}]
42+
}, {
43+
code: [
44+
'var First = createReactClass({',
45+
' propTypes: externalPropTypes,',
46+
' render: function() {',
47+
' return <Foo id="bar" style={{color: "red"}} />;',
48+
' }',
49+
'});'
50+
].join('\n'),
51+
options: [{forbid: ['style', 'id']}]
52+
}, {
53+
code: [
54+
'var First = createReactClass({',
55+
' propTypes: externalPropTypes,',
56+
' render: function() {',
57+
' return <this.Foo bar="baz" />;',
58+
' }',
59+
'});'
60+
].join('\n'),
61+
options: [{forbid: ['id']}]
62+
}, {
63+
code: [
64+
'class First extends createReactClass {',
65+
' render() {',
66+
' return <this.foo id="bar" />;',
67+
' }',
68+
'}'
69+
].join('\n'),
70+
options: [{forbid: ['id']}]
71+
}, {
72+
code: [
73+
'const First = (props) => (',
74+
' <this.Foo {...props} />',
75+
');'
76+
].join('\n'),
77+
options: [{forbid: ['id']}]
78+
}, {
79+
code: [
80+
'const First = (props) => (',
81+
' <div name="foo" />',
82+
');'
83+
].join('\n'),
84+
options: [{forbid: ['id']}]
85+
}],
86+
87+
invalid: [{
88+
code: [
89+
'var First = createReactClass({',
90+
' propTypes: externalPropTypes,',
91+
' render: function() {',
92+
' return <div id="bar" />;',
93+
' }',
94+
'});'
95+
].join('\n'),
96+
options: [{forbid: ['id']}],
97+
errors: [{
98+
message: ID_ERROR_MESSAGE,
99+
line: 4,
100+
column: 17,
101+
type: 'JSXAttribute'
102+
}]
103+
}, {
104+
code: [
105+
'class First extends createReactClass {',
106+
' render() {',
107+
' return <div id="bar" />;',
108+
' }',
109+
'}'
110+
].join('\n'),
111+
options: [{forbid: ['id']}],
112+
errors: [{
113+
message: ID_ERROR_MESSAGE,
114+
line: 3,
115+
column: 17,
116+
type: 'JSXAttribute'
117+
}]
118+
}, {
119+
code: [
120+
'const First = (props) => (',
121+
' <div id="foo" />',
122+
');'
123+
].join('\n'),
124+
options: [{forbid: ['id']}],
125+
errors: [{
126+
message: ID_ERROR_MESSAGE,
127+
line: 2,
128+
column: 8,
129+
type: 'JSXAttribute'
130+
}]
131+
}]
132+
});

0 commit comments

Comments
 (0)