diff --git a/README.md b/README.md
index 1f1441a5a5..bd7b856be9 100644
--- a/README.md
+++ b/README.md
@@ -128,7 +128,7 @@ Finally, enable all of the rules that you would like to use. Use [our preset](#
* [react/jsx-indent](docs/rules/jsx-indent.md): Validate JSX indentation (fixable)
* [react/jsx-indent-props](docs/rules/jsx-indent-props.md): Validate props indentation in JSX (fixable)
* [react/jsx-key](docs/rules/jsx-key.md): Validate JSX has key prop when in array or iterator
-* [react/jsx-max-props-per-line](docs/rules/jsx-max-props-per-line.md): Limit maximum of props on a single line in JSX
+* [react/jsx-max-props-per-line](docs/rules/jsx-max-props-per-line.md): Limit maximum of props on a single line in JSX (fixable)
* [react/jsx-no-bind](docs/rules/jsx-no-bind.md): Prevent usage of `.bind()` and arrow functions in JSX props
* [react/jsx-no-comment-textnodes](docs/rules/jsx-no-comment-textnodes.md): Prevent comments from being inserted as text nodes
* [react/jsx-no-duplicate-props](docs/rules/jsx-no-duplicate-props.md): Prevent duplicate props in JSX
diff --git a/docs/rules/jsx-max-props-per-line.md b/docs/rules/jsx-max-props-per-line.md
index 6857162503..d0a167c857 100644
--- a/docs/rules/jsx-max-props-per-line.md
+++ b/docs/rules/jsx-max-props-per-line.md
@@ -2,6 +2,8 @@
Limiting the maximum of props on a single line can improve readability.
+**Fixable:** This rule is automatically fixable using the `--fix` flag on the command line. However, fix does not include indentation. Please rerun lint to correct those errors.
+
## Rule Details
This rule checks all JSX elements and verifies that the number of props per line do not exceed the maximum allowed. Props are considered to be in a new line if there is a line break between the start of the prop and the end of the previous prop. A spread attribute counts as one prop. This rule is off by default and when on the default maximum of props on one line is `1`.
diff --git a/lib/rules/jsx-max-props-per-line.js b/lib/rules/jsx-max-props-per-line.js
index c4344fd8f2..88bd8370e3 100644
--- a/lib/rules/jsx-max-props-per-line.js
+++ b/lib/rules/jsx-max-props-per-line.js
@@ -16,7 +16,7 @@ module.exports = {
category: 'Stylistic Issues',
recommended: false
},
-
+ fixable: 'code',
schema: [{
type: 'object',
properties: {
@@ -46,6 +46,25 @@ module.exports = {
return propNode.name.name;
}
+ function generateFixFunction(line, max) {
+ var output = [];
+ var front = line[0].start;
+ var back = line[line.length - 1].end;
+ for (var i = 0; i < line.length; i += max) {
+ var nodes = line.slice(i, i + max);
+ output.push(nodes.reduce(function(prev, curr) {
+ if (prev === '') {
+ return sourceCode.getText(curr);
+ }
+ return `${prev} ${sourceCode.getText(curr)}`;
+ }, ''));
+ }
+ var code = output.join('\n');
+ return function(fixer) {
+ return fixer.replaceTextRange([front, back], code);
+ };
+ }
+
return {
JSXOpeningElement: function (node) {
if (!node.attributes.length) {
@@ -59,7 +78,7 @@ module.exports = {
var firstProp = node.attributes[0];
var linePartitionedProps = [[firstProp]];
- node.attributes.reduce(function(last, decl) {
+ node.attributes.reduce(function (last, decl) {
if (last.loc.end.line === decl.loc.start.line) {
linePartitionedProps[linePartitionedProps.length - 1].push(decl);
} else {
@@ -68,12 +87,13 @@ module.exports = {
return decl;
});
- linePartitionedProps.forEach(function(propsInLine) {
+ linePartitionedProps.forEach(function (propsInLine) {
if (propsInLine.length > maximum) {
var name = getPropName(propsInLine[maximum]);
context.report({
node: propsInLine[maximum],
- message: `Prop \`${name}\` must be placed on a new line`
+ message: `Prop \`${name}\` must be placed on a new line`,
+ fix: generateFixFunction(propsInLine, maximum)
});
}
});
diff --git a/tests/lib/rules/jsx-max-props-per-line.js b/tests/lib/rules/jsx-max-props-per-line.js
index 00ea0d42aa..1966e5e657 100644
--- a/tests/lib/rules/jsx-max-props-per-line.js
+++ b/tests/lib/rules/jsx-max-props-per-line.js
@@ -64,17 +64,37 @@ ruleTester.run('jsx-max-props-per-line', rule, {
invalid: [{
code: ';',
- errors: [{message: 'Prop `bar` must be placed on a new line'}]
+ output: [
+ ';'
+ ].join('\n'),
+ errors: [{message: 'Prop `bar` must be placed on a new line'}],
+ parserOptions: parserOptions
}, {
code: ';',
+ output: [
+ ';'
+ ].join('\n'),
options: [{maximum: 2}],
errors: [{message: 'Prop `baz` must be placed on a new line'}]
}, {
code: ';',
- errors: [{message: 'Prop `bar` must be placed on a new line'}]
+ output: [
+ ';'
+ ].join('\n'),
+ errors: [{message: 'Prop `bar` must be placed on a new line'}],
+ parserOptions: parserOptions
}, {
code: ';',
- errors: [{message: 'Prop `this.props` must be placed on a new line'}]
+ output: [
+ ';'
+ ].join('\n'),
+ errors: [{message: 'Prop `this.props` must be placed on a new line'}],
+ parserOptions: parserOptions
}, {
code: [
''
].join('\n'),
- errors: [{message: 'Prop `bar` must be placed on a new line'}]
+ output: [
+ ''
+ ].join('\n'),
+ errors: [{message: 'Prop `bar` must be placed on a new line'}],
+ parserOptions: parserOptions
}, {
code: [
''
].join('\n'),
- errors: [{message: 'Prop `this.props` must be placed on a new line'}]
+ output: [
+ ''
+ ].join('\n'),
+ errors: [{message: 'Prop `this.props` must be placed on a new line'}],
+ parserOptions: parserOptions
}, {
code: [
''
].join('\n'),
- errors: [{message: 'Prop `bar` must be placed on a new line'}]
+ output: [
+ ''
+ ].join('\n'),
+ errors: [{message: 'Prop `bar` must be placed on a new line'}],
+ parserOptions: parserOptions
}, {
code: [
''
].join('\n'),
- errors: [{message: 'Prop `bar` must be placed on a new line'}]
+ output: [
+ ''
+ ].join('\n'),
+ errors: [{message: 'Prop `bar` must be placed on a new line'}],
+ parserOptions: parserOptions
}, {
code: [
''
].join('\n'),
+ output: [
+ ''
+ ].join('\n'),
options: [{maximum: 2}],
errors: [{message: 'Prop `baz` must be placed on a new line'}]
}, {
@@ -117,14 +172,27 @@ ruleTester.run('jsx-max-props-per-line', rule, {
''
].join('\n'),
- errors: [{message: 'Prop `rest` must be placed on a new line'}]
+ output: [
+ ''
+ ].join('\n'),
+ errors: [{message: 'Prop `rest` must be placed on a new line'}],
+ parserOptions: parserOptions
}, {
code: [
''
].join('\n'),
- errors: [{message: 'Prop `bar` must be placed on a new line'}]
+ output: [
+ ''
+ ].join('\n'),
+ errors: [{message: 'Prop `bar` must be placed on a new line'}],
+ parserOptions: parserOptions
}, {
code: [
''
].join('\n'),
- errors: [{message: 'Prop `rest` must be placed on a new line'}]
+ output: [
+ ''
+ ].join('\n'),
+ errors: [{message: 'Prop `rest` must be placed on a new line'}],
+ parserOptions: parserOptions
}, {
code: [
''
+ ].join('\n'),
+ output: [
+ ''
].join('\n'),
options: [{maximum: 2}],