Skip to content

Commit f024c8d

Browse files
committed
Merge branch 'master' into customValidatorDetection
2 parents e6498ac + bed60d4 commit f024c8d

12 files changed

+343
-16
lines changed

History.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
3.0.0 / 2015-07-21
2+
==================
3+
4+
* add jsx-no-duplicate-props rule ([#161][] @hummlas)
5+
* add allowMultiline option to the jsx-curly-spacing rule ([#156][] @mathieumg)
6+
* breaking in jsx-curly-spacing braces spanning multiple lines are now allowed with never option ([#156][] @mathieumg)
7+
* fix multiple var and destructuring handling in props-types ([#159][])
8+
* fix crash when retrieving propType name ([#163][])
9+
10+
[#161]: https://github.com/yannickcr/eslint-plugin-react/pull/161
11+
[#156]: https://github.com/yannickcr/eslint-plugin-react/pull/156
12+
[#159]: https://github.com/yannickcr/eslint-plugin-react/issues/159
13+
[#163]: https://github.com/yannickcr/eslint-plugin-react/issues/163
14+
115
2.7.1 / 2015-07-16
216
==================
317

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ Finally, enable all of the rules that you would like to use.
4444
"rules": {
4545
"react/display-name": 1,
4646
"react/jsx-boolean-value": 1,
47+
"react/jsx-no-duplicate-props": 1,
4748
"react/jsx-no-undef": 1,
4849
"react/jsx-quotes": 1,
4950
"react/jsx-sort-prop-types": 1,
@@ -70,6 +71,7 @@ Finally, enable all of the rules that you would like to use.
7071
* [display-name](docs/rules/display-name.md): Prevent missing displayName in a React component definition
7172
* [jsx-boolean-value](docs/rules/jsx-boolean-value.md): Enforce boolean attributes notation in JSX
7273
* [jsx-curly-spacing](docs/rules/jsx-curly-spacing.md): Enforce or disallow spaces inside of curly braces in JSX attributes
74+
* [jsx-no-duplicate-props](docs/rules/jsx-no-duplicate-props.md): Prevent duplicate props in JSX
7375
* [jsx-no-undef](docs/rules/jsx-no-undef.md): Disallow undeclared variables in JSX
7476
* [jsx-quotes](docs/rules/jsx-quotes.md): Enforce quote style for JSX attributes
7577
* [jsx-sort-prop-types](docs/rules/jsx-sort-prop-types.md): Enforce propTypes declarations alphabetical sorting

docs/rules/jsx-curly-spacing.md

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,16 @@ When `"never"` is set, the following patterns are considered warnings:
2929
<Hello name={ firstname } />;
3030
<Hello name={ firstname} />;
3131
<Hello name={firstname } />;
32-
<Hello name={
33-
firstname
34-
} />;
3532
```
3633

3734
The following patterns are not warnings:
3835

3936
```js
4037
<Hello name={firstname} />;
4138
<Hello name={{ firstname: 'John', lastname: 'Doe' }} />;
39+
<Hello name={
40+
firstname
41+
} />;
4242
```
4343

4444
#### always
@@ -61,6 +61,51 @@ The following patterns are not warnings:
6161
} />;
6262
```
6363

64+
#### Braces spanning multiple lines
65+
66+
By default, braces spanning multiple lines are allowed with either setting. If you want to disallow them you can specify an additional `allowMultiline` property with the value `false`:
67+
68+
```json
69+
"jsx-curly-spacing": [2, "never", {"allowMultiline": false}]
70+
```
71+
72+
When `"never"` is used and `allowMultiline` is `false`, the following patterns are considered warnings:
73+
74+
```js
75+
<Hello name={ firstname } />;
76+
<Hello name={ firstname} />;
77+
<Hello name={firstname } />;
78+
<Hello name={
79+
firstname
80+
} />;
81+
```
82+
83+
The following patterns are not warnings:
84+
85+
```js
86+
<Hello name={firstname} />;
87+
<Hello name={{ firstname: 'John', lastname: 'Doe' }} />;
88+
```
89+
90+
When `"always"` is used and `allowMultiline` is `false`, the following patterns are considered warnings:
91+
92+
```js
93+
<Hello name={firstname} />;
94+
<Hello name={ firstname} />;
95+
<Hello name={firstname } />;
96+
<Hello name={
97+
firstname
98+
} />;
99+
```
100+
101+
The following patterns are not warnings:
102+
103+
```js
104+
<Hello name={ firstname } />;
105+
<Hello name={ {firstname: 'John', lastname: 'Doe'} } />;
106+
```
107+
108+
64109
## When Not To Use It
65110

66111
You can turn this rule off if you are not concerned with the consistency around the spacing inside of JSX attributes.

docs/rules/jsx-no-duplicate-props.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Prevent duplicate properties in JSX (jsx-no-duplicate-props)
2+
3+
Creating JSX elements with duplicate props can cause unexpected behavior in your application.
4+
5+
## Rule Details
6+
7+
The following patterns are considered warnings:
8+
9+
```js
10+
<Hello name="John" name="John" />;
11+
```
12+
13+
The following patterns are not considered warnings:
14+
15+
```js
16+
<Hello firstname="John" lastname="Doe" />;
17+
```
18+
19+
## Rule Options
20+
21+
```js
22+
...
23+
"jsx-no-duplicate-props": [<enabled>, { "ignoreCase": <boolean> }]
24+
...
25+
```
26+
27+
### `ignoreCase`
28+
29+
When `true` the rule ignores the case of the props. Default to `false`.
30+
31+
## When Not To Use It
32+
33+
If you are not using JSX then you can disable this rule.

index.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ module.exports = {
2121
'jsx-sort-prop-types': require('./lib/rules/jsx-sort-prop-types'),
2222
'jsx-boolean-value': require('./lib/rules/jsx-boolean-value'),
2323
'sort-comp': require('./lib/rules/sort-comp'),
24-
'require-extension': require('./lib/rules/require-extension')
24+
'require-extension': require('./lib/rules/require-extension'),
25+
'jsx-no-duplicate-props': require('./lib/rules/jsx-no-duplicate-props')
2526
},
2627
rulesConfig: {
2728
'jsx-uses-react': 0,
@@ -43,6 +44,7 @@ module.exports = {
4344
'jsx-sort-prop-types': 0,
4445
'jsx-boolean-value': 0,
4546
'sort-comp': 0,
46-
'require-extension': 0
47+
'require-extension': 0,
48+
'jsx-no-duplicate-props': 0
4749
}
4850
};

lib/rules/jsx-curly-spacing.js

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,24 @@
1010

1111
module.exports = function(context) {
1212
var spaced = context.options[0] === 'always';
13+
var multiline = context.options[1] ? context.options[1].allowMultiline : true;
1314

1415
// --------------------------------------------------------------------------
1516
// Helpers
1617
// --------------------------------------------------------------------------
1718

1819
/**
19-
* Determines whether two adjacent tokens are have whitespace between them.
20+
* Determines whether two adjacent tokens have a newline between them.
21+
* @param {Object} left - The left token object.
22+
* @param {Object} right - The right token object.
23+
* @returns {boolean} Whether or not there is a newline between the tokens.
24+
*/
25+
function isMultiline(left, right) {
26+
return left.loc.start.line !== right.loc.start.line;
27+
}
28+
29+
/**
30+
* Determines whether two adjacent tokens have whitespace between them.
2031
* @param {Object} left - The left token object.
2132
* @param {Object} right - The right token object.
2233
* @returns {boolean} Whether or not there is space between the tokens.
@@ -25,6 +36,28 @@ module.exports = function(context) {
2536
return left.range[1] < right.range[0];
2637
}
2738

39+
/**
40+
* Reports that there shouldn't be a newline after the first token
41+
* @param {ASTNode} node - The node to report in the event of an error.
42+
* @param {Token} token - The token to use for the report.
43+
* @returns {void}
44+
*/
45+
function reportNoBeginningNewline(node, token) {
46+
context.report(node, token.loc.start,
47+
'There should be no newline after \'' + token.value + '\'');
48+
}
49+
50+
/**
51+
* Reports that there shouldn't be a newline before the last token
52+
* @param {ASTNode} node - The node to report in the event of an error.
53+
* @param {Token} token - The token to use for the report.
54+
* @returns {void}
55+
*/
56+
function reportNoEndingNewline(node, token) {
57+
context.report(node, token.loc.start,
58+
'There should be no newline before \'' + token.value + '\'');
59+
}
60+
2861
/**
2962
* Reports that there shouldn't be a space after the first token
3063
* @param {ASTNode} node - The node to report in the event of an error.
@@ -79,16 +112,28 @@ module.exports = function(context) {
79112
* @returns {void}
80113
*/
81114
function validateBraceSpacing(node, first, second, penultimate, last) {
82-
if (spaced && !isSpaced(first, second)) {
83-
reportRequiredBeginningSpace(node, first);
115+
if (spaced) {
116+
if (!isSpaced(first, second)) {
117+
reportRequiredBeginningSpace(node, first);
118+
} else if (!multiline && isMultiline(first, second)) {
119+
reportNoBeginningNewline(node, first);
120+
}
121+
122+
if (!isSpaced(penultimate, last)) {
123+
reportRequiredEndingSpace(node, last);
124+
} else if (!multiline && isMultiline(penultimate, last)) {
125+
reportNoEndingNewline(node, last);
126+
}
127+
128+
return;
84129
}
85-
if (!spaced && isSpaced(first, second)) {
130+
131+
// "never" setting if we get here.
132+
if (isSpaced(first, second) && !(multiline && isMultiline(first, second))) {
86133
reportNoBeginningSpace(node, first);
87134
}
88-
if (spaced && !isSpaced(penultimate, last)) {
89-
reportRequiredEndingSpace(node, last);
90-
}
91-
if (!spaced && isSpaced(penultimate, last)) {
135+
136+
if (isSpaced(penultimate, last) && !(multiline && isMultiline(penultimate, last))) {
92137
reportNoEndingSpace(node, last);
93138
}
94139
}
@@ -111,4 +156,12 @@ module.exports = function(context) {
111156

112157
module.exports.schema = [{
113158
enum: ['always', 'never']
159+
}, {
160+
type: 'object',
161+
properties: {
162+
allowMultiline: {
163+
type: 'boolean'
164+
}
165+
},
166+
additionalProperties: false
114167
}];

lib/rules/jsx-no-duplicate-props.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/**
2+
* @fileoverview Enforce no duplicate props
3+
* @author Markus Ånöstam
4+
*/
5+
6+
'use strict';
7+
8+
// ------------------------------------------------------------------------------
9+
// Rule Definition
10+
// ------------------------------------------------------------------------------
11+
12+
module.exports = function (context) {
13+
14+
var configuration = context.options[0] || {};
15+
var ignoreCase = configuration.ignoreCase || false;
16+
17+
return {
18+
JSXOpeningElement: function (node) {
19+
var props = {};
20+
21+
node.attributes.forEach(function(decl) {
22+
if (decl.type === 'JSXSpreadAttribute') {
23+
return;
24+
}
25+
26+
var name = decl.name.name;
27+
28+
if (ignoreCase) {
29+
name = name.toLowerCase();
30+
}
31+
32+
if (props.hasOwnProperty(name)) {
33+
context.report(decl, 'No duplicate props allowed');
34+
} else {
35+
props[name] = 1;
36+
}
37+
});
38+
}
39+
};
40+
};
41+
42+
module.exports.schema = [{
43+
type: 'object',
44+
properties: {
45+
ignoreCase: {
46+
type: 'boolean'
47+
}
48+
},
49+
additionalProperties: false
50+
}];

lib/rules/prop-types.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ module.exports = function(context) {
480480
propTypes = null;
481481
}
482482
}
483-
if (propTypes) {
483+
if (propTypes && propTypes.property) {
484484
curDeclaredPropTypes[propTypes.property.name] =
485485
buildReactDeclarationTypes(propTypes.parent.right);
486486
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "eslint-plugin-react",
3-
"version": "2.7.1",
3+
"version": "3.0.0",
44
"author": "Yannick Croissant <[email protected]>",
55
"description": "React specific linting rules for ESLint",
66
"main": "index.js",

0 commit comments

Comments
 (0)