Skip to content

Commit

Permalink
Add a forbid-dom-props rule
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
davazp committed Nov 22, 2017
1 parent 6829c5c commit 1ae0a99
Show file tree
Hide file tree
Showing 5 changed files with 219 additions and 0 deletions.
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
45 changes: 45 additions & 0 deletions docs/rules/forbid-dom-props.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# 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 `[]`.
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
68 changes: 68 additions & 0 deletions lib/rules/forbid-dom-props.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* @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'
}
}
},
additionalProperties: true
}]
},

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`
});
}
};
}
};
104 changes: 104 additions & 0 deletions tests/lib/rules/forbid-dom-props.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/**
* @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'
}]
}]
});

0 comments on commit 1ae0a99

Please sign in to comment.