Skip to content

Commit

Permalink
Merge pull request #1562 from davazp/add-forbid-dom-props-rule
Browse files Browse the repository at this point in the history
Add a forbid-dom-props rule
  • Loading branch information
ljharb committed Nov 28, 2017
2 parents af6ccb0 + 268a704 commit c072c89
Show file tree
Hide file tree
Showing 6 changed files with 259 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ Enable the rules that you would like to use.
* [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',
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'
}]
}]
});

0 comments on commit c072c89

Please sign in to comment.