Skip to content

Commit 1ae0a99

Browse files
committed
Add a forbid-dom-props rule
A new rule forbid-dom-props was added. It is based on forbid-component-props but it only forbid property on DOM Node elements. This can be useful to enforce some good practices, as not using 'id' attributes or inline styles.
1 parent 6829c5c commit 1ae0a99

File tree

5 files changed

+219
-0
lines changed

5 files changed

+219
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ Finally, enable all of the rules that you would like to use. Use [our preset](#
8888
* [react/destructuring-assignment](docs/rules/destructuring-assignment.md): Rule enforces consistent usage of destructuring assignment in component
8989
* [react/display-name](docs/rules/display-name.md): Prevent missing `displayName` in a React component definition
9090
* [react/forbid-component-props](docs/rules/forbid-component-props.md): Forbid certain props on Components
91+
* [react/forbid-dom-props](docs/rules/forbid-dom-props.md): Forbid certain props on DOM Nodes
9192
* [react/forbid-elements](docs/rules/forbid-elements.md): Forbid certain elements
9293
* [react/forbid-prop-types](docs/rules/forbid-prop-types.md): Forbid certain propTypes
9394
* [react/forbid-foreign-prop-types](docs/rules/forbid-foreign-prop-types.md): Forbid foreign propTypes

docs/rules/forbid-dom-props.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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 `[]`.

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: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
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+
}
33+
}
34+
},
35+
additionalProperties: true
36+
}]
37+
},
38+
39+
create: function(context) {
40+
function isForbidden(prop) {
41+
const configuration = context.options[0] || {};
42+
43+
const forbid = configuration.forbid || DEFAULTS;
44+
return forbid.indexOf(prop) >= 0;
45+
}
46+
47+
return {
48+
JSXAttribute: function(node) {
49+
const tag = node.parent.name.name;
50+
if (!(tag && tag[0] !== tag[0].toUpperCase())) {
51+
// This is a Component, not a DOM node, so exit.
52+
return;
53+
}
54+
55+
const prop = node.name.name;
56+
57+
if (!isForbidden(prop)) {
58+
return;
59+
}
60+
61+
context.report({
62+
node: node,
63+
message: `Prop \`${prop}\` is forbidden on DOM Nodes`
64+
});
65+
}
66+
};
67+
}
68+
};

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

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
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+
});

0 commit comments

Comments
 (0)