Skip to content

Commit bda68ce

Browse files
committed
Merge remote-tracking branch 'upstream/master' into spaces
2 parents 5b2e1d4 + 27b8279 commit bda68ce

32 files changed

+2387
-709
lines changed

docs/rules/button-has-type.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Prevent usage of `button` elements without an explicit `type` attribute (react/button-has-type)
2+
3+
The default value of `type` attribute for `button` HTML element is `"submit"` which is often not the desired behavior and may lead to unexpected page reloads.
4+
This rules enforces an explicit `type` attribute for all the `button` elements and checks that its value is valid per spec (i.e., is one of `"button"`, `"submit"`, and `"reset"`).
5+
6+
## Rule Details
7+
8+
The following patterns are considered errors:
9+
10+
```jsx
11+
var Hello = <button>Hello</button>
12+
var Hello = <button type="foo">Hello</button>
13+
14+
var Hello = React.createElement('button', {}, 'Hello')
15+
var Hello = React.createElement('button', {type: 'foo'}, 'Hello')
16+
```
17+
18+
The following patterns are **not** considered errors:
19+
20+
```jsx
21+
var Hello = <span>Hello</span>
22+
var Hello = <span type="foo">Hello</span>
23+
var Hello = <button type="button">Hello</button>
24+
var Hello = <button type="submit">Hello</button>
25+
var Hello = <button type="reset">Hello</button>
26+
27+
var Hello = React.createElement('span', {}, 'Hello')
28+
var Hello = React.createElement('span', {type: 'foo'}, 'Hello')
29+
var Hello = React.createElement('button', {type: 'button'}, 'Hello')
30+
var Hello = React.createElement('button', {type: 'submit'}, 'Hello')
31+
var Hello = React.createElement('button', {type: 'reset'}, 'Hello')
32+
```
33+
34+
## Rule Options
35+
36+
```js
37+
...
38+
"react/button-has-type": [<enabled>, {
39+
"button": <boolean>,
40+
"submit": <boolean>,
41+
"reset": <boolean>
42+
}]
43+
...
44+
```
45+
46+
You can forbid particular type attribute values by passing `false` as corresponding option (by default all of them are `true`).
47+
48+
The following patterns are considered errors when using `"react/button-has-type": ["error", {reset: false}]`:
49+
50+
```jsx
51+
var Hello = <button type="reset">Hello</button>
52+
53+
var Hello = React.createElement('button', {type: 'reset'}, 'Hello')
54+
```
55+
56+
## When Not To Use It
57+
58+
If you use only `"submit"` buttons, you can disable this rule

docs/rules/forbid-prop-types.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,22 @@ class Component extends React.Component {
4444

4545
```js
4646
...
47-
"react/forbid-prop-types": [<enabled>, { "forbid": [<string>] }]
47+
"react/forbid-prop-types": [<enabled>, { "forbid": [<string>], checkContextTypes: <boolean>, checkChildContextTypes: <boolean> }]
4848
...
4949
```
5050

5151
### `forbid`
5252

5353
An array of strings, with the names of `PropTypes` keys that are forbidden. The default value for this option is `['any', 'array', 'object']`.
5454

55+
### `checkContextTypes`
56+
57+
Whether or not to check `contextTypes` for forbidden prop types. The default value is false.
58+
59+
### `checkChildContextTypes`
60+
61+
Whether or not to check `childContextTypes` for forbidden prop types. The default value is false.
62+
5563
## When not to use
5664

5765
This rule is a formatting/documenting preference and not following it won't negatively affect the quality of your code. This rule encourages prop types that more specifically document their usage.

docs/rules/no-deprecated.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ const propTypes = {
2323
foo: PropTypes.bar,
2424
};
2525

26+
//Any factories under React.DOM
27+
React.DOM.div();
28+
2629
import React, { PropTypes } from 'react';
2730
```
2831

docs/rules/prefer-stateless-function.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Stateless functional components are simpler than class based components and will
66

77
This rule will check your class based React components for
88

9-
* methods/properties other than `displayName`, `propTypes`, `render` and useless constructor (same detection as ESLint [no-useless-constructor rule](http://eslint.org/docs/rules/no-useless-constructor))
9+
* methods/properties other than `displayName`, `propTypes`, `contextTypes`, `defaultProps`, `render` and useless constructor (same detection as ESLint [no-useless-constructor rule](http://eslint.org/docs/rules/no-useless-constructor))
1010
* instance property other than `this.props` and `this.context`
1111
* extension of `React.PureComponent` (if the `ignorePureComponents` flag is true)
1212
* presence of `ref` attribute in JSX

docs/rules/require-default-props.md

Lines changed: 98 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,19 @@ Greeting.defaultProps = {
102102
};
103103
```
104104

105+
```jsx
106+
type Props = {
107+
foo: string,
108+
bar?: string
109+
};
110+
111+
function MyStatelessComponent(props: Props) {
112+
return <div>Hello {props.foo} {props.bar}</div>;
113+
}
114+
```
115+
116+
The following patterns are **not** considered warnings:
117+
105118
```jsx
106119
class Greeting extends React.Component {
107120
render() {
@@ -121,19 +134,6 @@ class Greeting extends React.Component {
121134
}
122135
```
123136

124-
```jsx
125-
type Props = {
126-
foo: string,
127-
bar?: string
128-
};
129-
130-
function MyStatelessComponent(props: Props) {
131-
return <div>Hello {props.foo} {props.bar}</div>;
132-
}
133-
```
134-
135-
The following patterns are **not** considered warnings:
136-
137137
```jsx
138138
function MyStatelessComponent({ foo, bar }) {
139139
return <div>{foo}{bar}</div>;
@@ -184,6 +184,91 @@ NotAComponent.propTypes = {
184184
};
185185
```
186186

187+
## Rule Options
188+
189+
```js
190+
...
191+
"react/require-default-props": [<enabled>, { forbidDefaultForRequired: <boolean> }]
192+
...
193+
```
194+
195+
* `enabled`: for enabling the rule. 0=off, 1=warn, 2=error. Defaults to 0.
196+
* `forbidDefaultForRequired`: optional boolean to forbid prop default for a required prop. Defaults to false.
197+
198+
### `forbidDefaultForRequired`
199+
200+
Forbids setting a default for props that are marked as `isRequired`.
201+
202+
The following patterns are warnings:
203+
204+
```jsx
205+
class Greeting extends React.Component {
206+
render() {
207+
return (
208+
<h1>Hello, {this.props.foo} {this.props.bar}</h1>
209+
);
210+
}
211+
212+
static propTypes = {
213+
foo: PropTypes.string,
214+
bar: PropTypes.string.isRequired
215+
};
216+
217+
static defaultProps = {
218+
foo: "foo",
219+
bar: "bar"
220+
};
221+
}
222+
```
223+
224+
```jsx
225+
function MyStatelessComponent({ foo, bar }) {
226+
return <div>{foo}{bar}</div>;
227+
}
228+
229+
MyStatelessComponent.propTypes = {
230+
foo: PropTypes.string.isRequired,
231+
bar: PropTypes.string
232+
};
233+
234+
MyStatelessComponent.defaultProps = {
235+
foo: 'foo',
236+
bar: 'bar'
237+
};
238+
```
239+
240+
The following patterns are **not** warnings:
241+
242+
```jsx
243+
class Greeting extends React.Component {
244+
render() {
245+
return (
246+
<h1>Hello, {this.props.foo} {this.props.bar}</h1>
247+
);
248+
}
249+
250+
static propTypes = {
251+
foo: PropTypes.string,
252+
bar: PropTypes.string.isRequired
253+
};
254+
255+
static defaultProps = {
256+
foo: "foo"
257+
};
258+
}
259+
```
260+
261+
```jsx
262+
function MyStatelessComponent({ foo, bar }) {
263+
return <div>{foo}{bar}</div>;
264+
}
265+
266+
MyStatelessComponent.propTypes = {
267+
foo: PropTypes.string.isRequired,
268+
bar: PropTypes.string.isRequired
269+
};
270+
```
271+
187272
## When Not To Use It
188273

189274
If you don't care about using `defaultsProps` for your component's props that are not required, you can disable this rule.

index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const allRules = {
3030
'jsx-no-literals': require('./lib/rules/jsx-no-literals'),
3131
'jsx-no-target-blank': require('./lib/rules/jsx-no-target-blank'),
3232
'jsx-one-expression-per-line': require('./lib/rules/jsx-one-expression-per-line'),
33+
'button-has-type': require('./lib/rules/button-has-type'),
3334
'jsx-no-undef': require('./lib/rules/jsx-no-undef'),
3435
'jsx-curly-brace-presence': require('./lib/rules/jsx-curly-brace-presence'),
3536
'jsx-pascal-case': require('./lib/rules/jsx-pascal-case'),

lib/rules/boolean-prop-naming.js

Lines changed: 4 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
const has = require('has');
88
const Components = require('../util/Components');
9+
const propsUtil = require('../util/props');
910

1011
// ------------------------------------------------------------------------------
1112
// Rule Definition
@@ -49,32 +50,6 @@ module.exports = {
4950
// Remembers all Flowtype object definitions
5051
const objectTypeAnnotations = new Map();
5152

52-
/**
53-
* Checks if node is `propTypes` declaration
54-
* @param {ASTNode} node The AST node being checked.
55-
* @returns {Boolean} True if node is `propTypes` declaration, false if not.
56-
*/
57-
function isPropTypesDeclaration(node) {
58-
// Special case for class properties
59-
// (babel-eslint does not expose property name so we have to rely on tokens)
60-
if (node && node.type === 'ClassProperty') {
61-
const tokens = context.getFirstTokens(node, 2);
62-
if (tokens[0].value === 'propTypes' || (tokens[1] && tokens[1].value === 'propTypes')) {
63-
return true;
64-
}
65-
// Flow support
66-
if (node.typeAnnotation && node.key.name === 'props') {
67-
return true;
68-
}
69-
return false;
70-
}
71-
72-
return Boolean(
73-
node &&
74-
node.name === 'propTypes'
75-
);
76-
}
77-
7853
/**
7954
* Returns the prop key to ensure we handle the following cases:
8055
* propTypes: {
@@ -169,7 +144,7 @@ module.exports = {
169144

170145
return {
171146
ClassProperty: function(node) {
172-
if (!rule || !isPropTypesDeclaration(node)) {
147+
if (!rule || !propsUtil.isPropTypesDeclaration(node)) {
173148
return;
174149
}
175150
if (node.value && node.value.properties) {
@@ -181,7 +156,7 @@ module.exports = {
181156
},
182157

183158
MemberExpression: function(node) {
184-
if (!rule || !isPropTypesDeclaration(node.property)) {
159+
if (!rule || !propsUtil.isPropTypesDeclaration(node)) {
185160
return;
186161
}
187162
const component = utils.getRelatedComponent(node);
@@ -198,7 +173,7 @@ module.exports = {
198173

199174
// Search for the proptypes declaration
200175
node.properties.forEach(property => {
201-
if (!isPropTypesDeclaration(property.key)) {
176+
if (!propsUtil.isPropTypesDeclaration(property)) {
202177
return;
203178
}
204179
validatePropNaming(node, property.value.properties);

0 commit comments

Comments
 (0)