Skip to content

Commit 0fb170b

Browse files
committed
autofix for max-props-per-line
1 parent 45e3b9f commit 0fb170b

File tree

4 files changed

+122
-16
lines changed

4 files changed

+122
-16
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ Finally, enable all of the rules that you would like to use. Use [our preset](#
128128
* [react/jsx-indent](docs/rules/jsx-indent.md): Validate JSX indentation (fixable)
129129
* [react/jsx-indent-props](docs/rules/jsx-indent-props.md): Validate props indentation in JSX (fixable)
130130
* [react/jsx-key](docs/rules/jsx-key.md): Validate JSX has key prop when in array or iterator
131-
* [react/jsx-max-props-per-line](docs/rules/jsx-max-props-per-line.md): Limit maximum of props on a single line in JSX
131+
* [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)
132132
* [react/jsx-no-bind](docs/rules/jsx-no-bind.md): Prevent usage of `.bind()` and arrow functions in JSX props
133133
* [react/jsx-no-comment-textnodes](docs/rules/jsx-no-comment-textnodes.md): Prevent comments from being inserted as text nodes
134134
* [react/jsx-no-duplicate-props](docs/rules/jsx-no-duplicate-props.md): Prevent duplicate props in JSX

docs/rules/jsx-max-props-per-line.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
Limiting the maximum of props on a single line can improve readability.
44

5+
**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.
6+
57
## Rule Details
68

79
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`.

lib/rules/jsx-max-props-per-line.js

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ module.exports = {
1616
category: 'Stylistic Issues',
1717
recommended: false
1818
},
19-
19+
fixable: 'code',
2020
schema: [{
2121
type: 'object',
2222
properties: {
@@ -46,6 +46,25 @@ module.exports = {
4646
return propNode.name.name;
4747
}
4848

49+
function generateFixFunction(line, max) {
50+
var output = [];
51+
var front = line[0].start;
52+
var back = line[line.length - 1].end;
53+
for (var i = 0; i < line.length; i += max) {
54+
var nodes = line.slice(i, i + max);
55+
output.push(nodes.reduce(function(prev, curr) {
56+
if (prev === '') {
57+
return sourceCode.getText(curr);
58+
}
59+
return `${prev} ${sourceCode.getText(curr)}`;
60+
}, ''));
61+
}
62+
var code = output.join('\n');
63+
return function(fixer) {
64+
return fixer.replaceTextRange([front, back], code);
65+
};
66+
}
67+
4968
return {
5069
JSXOpeningElement: function (node) {
5170
if (!node.attributes.length) {
@@ -59,7 +78,7 @@ module.exports = {
5978
var firstProp = node.attributes[0];
6079
var linePartitionedProps = [[firstProp]];
6180

62-
node.attributes.reduce(function(last, decl) {
81+
node.attributes.reduce(function (last, decl) {
6382
if (last.loc.end.line === decl.loc.start.line) {
6483
linePartitionedProps[linePartitionedProps.length - 1].push(decl);
6584
} else {
@@ -68,12 +87,13 @@ module.exports = {
6887
return decl;
6988
});
7089

71-
linePartitionedProps.forEach(function(propsInLine) {
90+
linePartitionedProps.forEach(function (propsInLine) {
7291
if (propsInLine.length > maximum) {
7392
var name = getPropName(propsInLine[maximum]);
7493
context.report({
7594
node: propsInLine[maximum],
76-
message: `Prop \`${name}\` must be placed on a new line`
95+
message: `Prop \`${name}\` must be placed on a new line`,
96+
fix: generateFixFunction(propsInLine, maximum)
7797
});
7898
}
7999
});

tests/lib/rules/jsx-max-props-per-line.js

Lines changed: 95 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -64,67 +64,135 @@ ruleTester.run('jsx-max-props-per-line', rule, {
6464

6565
invalid: [{
6666
code: '<App foo bar baz />;',
67-
errors: [{message: 'Prop `bar` must be placed on a new line'}]
67+
output: [
68+
'<App foo',
69+
'bar',
70+
'baz />;'
71+
].join('\n'),
72+
errors: [{message: 'Prop `bar` must be placed on a new line'}],
73+
parserOptions: parserOptions
6874
}, {
6975
code: '<App foo bar baz />;',
76+
output: [
77+
'<App foo bar',
78+
'baz />;'
79+
].join('\n'),
7080
options: [{maximum: 2}],
7181
errors: [{message: 'Prop `baz` must be placed on a new line'}]
7282
}, {
7383
code: '<App {...this.props} bar />;',
74-
errors: [{message: 'Prop `bar` must be placed on a new line'}]
84+
output: [
85+
'<App {...this.props}',
86+
'bar />;'
87+
].join('\n'),
88+
errors: [{message: 'Prop `bar` must be placed on a new line'}],
89+
parserOptions: parserOptions
7590
}, {
7691
code: '<App bar {...this.props} />;',
77-
errors: [{message: 'Prop `this.props` must be placed on a new line'}]
92+
output: [
93+
'<App bar',
94+
'{...this.props} />;'
95+
].join('\n'),
96+
errors: [{message: 'Prop `this.props` must be placed on a new line'}],
97+
parserOptions: parserOptions
7898
}, {
7999
code: [
80100
'<App',
81101
' foo bar',
82102
' baz',
83103
'/>'
84104
].join('\n'),
85-
errors: [{message: 'Prop `bar` must be placed on a new line'}]
105+
output: [
106+
'<App',
107+
' foo',
108+
'bar',
109+
' baz',
110+
'/>'
111+
].join('\n'),
112+
errors: [{message: 'Prop `bar` must be placed on a new line'}],
113+
parserOptions: parserOptions
86114
}, {
87115
code: [
88116
'<App',
89117
' foo {...this.props}',
90118
' baz',
91119
'/>'
92120
].join('\n'),
93-
errors: [{message: 'Prop `this.props` must be placed on a new line'}]
121+
output: [
122+
'<App',
123+
' foo',
124+
'{...this.props}',
125+
' baz',
126+
'/>'
127+
].join('\n'),
128+
errors: [{message: 'Prop `this.props` must be placed on a new line'}],
129+
parserOptions: parserOptions
94130
}, {
95131
code: [
96132
'<App',
97133
' foo={{',
98134
' }} bar',
99135
'/>'
100136
].join('\n'),
101-
errors: [{message: 'Prop `bar` must be placed on a new line'}]
137+
output: [
138+
'<App',
139+
' foo={{',
140+
' }}',
141+
'bar',
142+
'/>'
143+
].join('\n'),
144+
errors: [{message: 'Prop `bar` must be placed on a new line'}],
145+
parserOptions: parserOptions
102146
}, {
103147
code: [
104148
'<App foo={{',
105149
'}} bar />'
106150
].join('\n'),
107-
errors: [{message: 'Prop `bar` must be placed on a new line'}]
151+
output: [
152+
'<App foo={{',
153+
'}}',
154+
'bar />'
155+
].join('\n'),
156+
errors: [{message: 'Prop `bar` must be placed on a new line'}],
157+
parserOptions: parserOptions
108158
}, {
109159
code: [
110160
'<App foo bar={{',
111161
'}} baz />'
112162
].join('\n'),
163+
output: [
164+
'<App foo bar={{',
165+
'}}',
166+
'baz />'
167+
].join('\n'),
113168
options: [{maximum: 2}],
114169
errors: [{message: 'Prop `baz` must be placed on a new line'}]
115170
}, {
116171
code: [
117172
'<App foo={{',
118173
'}} {...rest} />'
119174
].join('\n'),
120-
errors: [{message: 'Prop `rest` must be placed on a new line'}]
175+
output: [
176+
'<App foo={{',
177+
'}}',
178+
'{...rest} />'
179+
].join('\n'),
180+
errors: [{message: 'Prop `rest` must be placed on a new line'}],
181+
parserOptions: parserOptions
121182
}, {
122183
code: [
123184
'<App {',
124185
' ...this.props',
125186
'} bar />'
126187
].join('\n'),
127-
errors: [{message: 'Prop `bar` must be placed on a new line'}]
188+
output: [
189+
'<App {',
190+
' ...this.props',
191+
'}',
192+
'bar />'
193+
].join('\n'),
194+
errors: [{message: 'Prop `bar` must be placed on a new line'}],
195+
parserOptions: parserOptions
128196
}, {
129197
code: [
130198
'<App {',
@@ -133,12 +201,28 @@ ruleTester.run('jsx-max-props-per-line', rule, {
133201
' ...rest',
134202
'} />'
135203
].join('\n'),
136-
errors: [{message: 'Prop `rest` must be placed on a new line'}]
204+
output: [
205+
'<App {',
206+
' ...this.props',
207+
'}',
208+
'{',
209+
' ...rest',
210+
'} />'
211+
].join('\n'),
212+
errors: [{message: 'Prop `rest` must be placed on a new line'}],
213+
parserOptions: parserOptions
137214
}, {
138215
code: [
139216
'<App',
140217
' foo={{',
141-
' }} bar baz',
218+
' }} bar baz bor',
219+
'/>'
220+
].join('\n'),
221+
output: [
222+
'<App',
223+
' foo={{',
224+
' }} bar',
225+
'baz bor',
142226
'/>'
143227
].join('\n'),
144228
options: [{maximum: 2}],

0 commit comments

Comments
 (0)