Skip to content

Add a forbid-dom-props rule #1562

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Nov 28, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ Finally, enable all of the rules that you would like to use. Use [our preset](#
* [react/destructuring-assignment](docs/rules/destructuring-assignment.md): Rule enforces consistent usage of destructuring assignment in component
* [react/display-name](docs/rules/display-name.md): Prevent missing `displayName` in a React component definition
* [react/forbid-component-props](docs/rules/forbid-component-props.md): Forbid certain props on Components
* [react/forbid-dom-props](docs/rules/forbid-dom-props.md): Forbid certain props on DOM Nodes
* [react/forbid-elements](docs/rules/forbid-elements.md): Forbid certain elements
* [react/forbid-prop-types](docs/rules/forbid-prop-types.md): Forbid certain propTypes
* [react/forbid-foreign-prop-types](docs/rules/forbid-foreign-prop-types.md): Forbid foreign propTypes
Expand Down
5 changes: 5 additions & 0 deletions docs/rules/forbid-component-props.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,8 @@ The following patterns are **not** considered warnings:
### `forbid`

An array of strings, with the names of props that are forbidden. The default value of this option is `['className', 'style']`.


### Related rules

- [forbid-dom-props](./forbid-dom-props.md)
50 changes: 50 additions & 0 deletions docs/rules/forbid-dom-props.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Forbid certain props on DOM Nodes (react/forbid-dom-props)

This rule prevents passing of props to elements. This rule only applies to DOM Nodes (e.g. `<div />`) and not Components (e.g. `<Component />`).
The list of forbidden props can be customized with the `forbid` option.

## Rule Details

This rule checks all JSX elements and verifies that no forbidden props are used
on DOM Nodes. This rule is off by default.

The following patterns are considered warnings:

```jsx
// [1, { "forbid": ["id"] }]
<div id='Joe' />
```

```jsx
// [1, { "forbid": ["style"] }]
<div style={{color: 'red'}} />
```

The following patterns are **not** considered warnings:

```jsx
// [1, { "forbid": ["id"] }]
<Hello id='foo' />
```

```jsx
// [1, { "forbid": ["id"] }]
<Hello id={{color: 'red'}} />
```

## Rule Options

```js
...
"react/forbid-dom-props": [<enabled>, { "forbid": [<string>] }]
...
```

### `forbid`

An array of strings, with the names of props that are forbidden. The default value of this option `[]`.


### Related rules

- [forbid-component-props](./forbid-component-props.md)
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const allRules = {
'destructuring-assignment': require('./lib/rules/destructuring-assignment'),
'display-name': require('./lib/rules/display-name'),
'forbid-component-props': require('./lib/rules/forbid-component-props'),
'forbid-dom-props': require('./lib/rules/forbid-dom-props'),
'forbid-elements': require('./lib/rules/forbid-elements'),
'forbid-prop-types': require('./lib/rules/forbid-prop-types'),
'forbid-foreign-prop-types': require('./lib/rules/forbid-foreign-prop-types'),
Expand Down
70 changes: 70 additions & 0 deletions lib/rules/forbid-dom-props.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* @fileoverview Forbid certain props on DOM Nodes
* @author David Vázquez
*/
'use strict';

// ------------------------------------------------------------------------------
// Constants
// ------------------------------------------------------------------------------

const DEFAULTS = [];

// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------

module.exports = {
meta: {
docs: {
description: 'Forbid certain props on DOM Nodes',
category: 'Best Practices',
recommended: false
},

schema: [{
type: 'object',
properties: {
forbid: {
type: 'array',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this array should be forced to be unique

items: {
type: 'string',
minLength: 1
},
uniqueItems: true
}
},
additionalProperties: false
}]
},

create: function(context) {
function isForbidden(prop) {
const configuration = context.options[0] || {};

const forbid = configuration.forbid || DEFAULTS;
return forbid.indexOf(prop) >= 0;
}

return {
JSXAttribute: function(node) {
const tag = node.parent.name.name;
if (!(tag && tag[0] !== tag[0].toUpperCase())) {
// This is a Component, not a DOM node, so exit.
return;
}

const prop = node.name.name;

if (!isForbidden(prop)) {
return;
}

context.report({
node: node,
message: `Prop \`${prop}\` is forbidden on DOM Nodes`
});
}
};
}
};
132 changes: 132 additions & 0 deletions tests/lib/rules/forbid-dom-props.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/**
* @fileoverview Tests for forbid-dom-props
*/
'use strict';

// -----------------------------------------------------------------------------
// Requirements
// -----------------------------------------------------------------------------

const rule = require('../../../lib/rules/forbid-dom-props');
const RuleTester = require('eslint').RuleTester;

const parserOptions = {
ecmaVersion: 8,
sourceType: 'module',
ecmaFeatures: {
experimentalObjectRestSpread: true,
jsx: true
}
};

require('babel-eslint');

// -----------------------------------------------------------------------------
// Tests
// -----------------------------------------------------------------------------

const ID_ERROR_MESSAGE = 'Prop `id` is forbidden on DOM Nodes';

const ruleTester = new RuleTester({parserOptions});
ruleTester.run('forbid-element-props', rule, {

valid: [{
code: [
'var First = createReactClass({',
' render: function() {',
' return <Foo id="foo" />;',
' }',
'});'
].join('\n'),
options: [{forbid: ['id']}]
}, {
code: [
'var First = createReactClass({',
' propTypes: externalPropTypes,',
' render: function() {',
' return <Foo id="bar" style={{color: "red"}} />;',
' }',
'});'
].join('\n'),
options: [{forbid: ['style', 'id']}]
}, {
code: [
'var First = createReactClass({',
' propTypes: externalPropTypes,',
' render: function() {',
' return <this.Foo bar="baz" />;',
' }',
'});'
].join('\n'),
options: [{forbid: ['id']}]
}, {
code: [
'class First extends createReactClass {',
' render() {',
' return <this.foo id="bar" />;',
' }',
'}'
].join('\n'),
options: [{forbid: ['id']}]
}, {
code: [
'const First = (props) => (',
' <this.Foo {...props} />',
');'
].join('\n'),
options: [{forbid: ['id']}]
}, {
code: [
'const First = (props) => (',
' <div name="foo" />',
');'
].join('\n'),
options: [{forbid: ['id']}]
}],

invalid: [{
code: [
'var First = createReactClass({',
' propTypes: externalPropTypes,',
' render: function() {',
' return <div id="bar" />;',
' }',
'});'
].join('\n'),
options: [{forbid: ['id']}],
errors: [{
message: ID_ERROR_MESSAGE,
line: 4,
column: 17,
type: 'JSXAttribute'
}]
}, {
code: [
'class First extends createReactClass {',
' render() {',
' return <div id="bar" />;',
' }',
'}'
].join('\n'),
options: [{forbid: ['id']}],
errors: [{
message: ID_ERROR_MESSAGE,
line: 3,
column: 17,
type: 'JSXAttribute'
}]
}, {
code: [
'const First = (props) => (',
' <div id="foo" />',
');'
].join('\n'),
options: [{forbid: ['id']}],
errors: [{
message: ID_ERROR_MESSAGE,
line: 2,
column: 8,
type: 'JSXAttribute'
}]
}]
});