Skip to content

Commit eaf1bd4

Browse files
author
Carlux
committed
[feat] update rule to accept both adn line rules
1 parent 9799131 commit eaf1bd4

File tree

3 files changed

+255
-16
lines changed

3 files changed

+255
-16
lines changed

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ Examples of **correct** code for this rule:
3939
...
4040
"react/jsx-max-props-per-line": [<enabled>, { "maximum": <number>, "when": <string> }]
4141
...
42+
43+
// OR
44+
45+
...
46+
"react/jsx-max-props-per-line": [<enabled>, { "maximum": { single <number> multi: <number> } }]
47+
...
4248
```
4349

4450
### `maximum`
@@ -62,8 +68,12 @@ Examples of **correct** code for this rule:
6268
/>;
6369
```
6470

71+
Maximum can be specified as object `{ single: 1, multi: 1 }` to specify maximum allowed number of props for single line and multiple line tags.
72+
6573
### `when`
6674

75+
_when only applied if `maximum` is specified as number._
76+
6777
Possible values:
6878
- `always` (default) - Always check for max props per line.
6979
- `multiline` - Only check for max props per line when jsx tag spans multiple lines.

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

Lines changed: 65 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,24 +26,61 @@ module.exports = {
2626
},
2727

2828
schema: [{
29-
type: 'object',
30-
properties: {
31-
maximum: {
32-
type: 'integer',
33-
minimum: 1
29+
anyOf: [{
30+
type: 'object',
31+
properties: {
32+
maximum: {
33+
oneOf: [{
34+
type: 'integer',
35+
minimum: 1
36+
}, {
37+
type: 'object',
38+
properties: {
39+
single: {
40+
type: 'integer',
41+
minimum: 1
42+
},
43+
multi: {
44+
type: 'integer',
45+
minimum: 1
46+
}
47+
}
48+
}]
49+
}
3450
},
35-
when: {
36-
type: 'string',
37-
enum: ['always', 'multiline']
51+
additionalProperties: false
52+
}, {
53+
type: 'object',
54+
properties: {
55+
maximum: {
56+
type: 'number',
57+
minimum: 1
58+
},
59+
when: {
60+
type: 'string',
61+
enum: ['always', 'multiline']
62+
}
3863
}
39-
}
64+
}]
4065
}]
4166
},
4267

4368
create(context) {
4469
const configuration = context.options[0] || {};
4570
const maximum = configuration.maximum || 1;
46-
const when = configuration.when || 'always';
71+
let maximumSingle = null;
72+
let maximumMulti = null;
73+
74+
const isExtendedConfig = typeof maximum !== 'number';
75+
76+
if (isExtendedConfig) {
77+
maximumSingle = maximum.single || Infinity;
78+
maximumMulti = maximum.multi || Infinity;
79+
}
80+
81+
const when = isExtendedConfig
82+
? 'always'
83+
: configuration.when || 'always';
4784

4885
function getPropName(propNode) {
4986
if (propNode.type === 'JSXSpreadAttribute') {
@@ -57,6 +94,7 @@ module.exports = {
5794
const output = [];
5895
const front = line[0].range[0];
5996
const back = line[line.length - 1].range[1];
97+
6098
for (let i = 0; i < line.length; i += max) {
6199
const nodes = line.slice(i, i + max);
62100
output.push(nodes.reduce((prev, curr) => {
@@ -66,7 +104,9 @@ module.exports = {
66104
return `${prev} ${sourceCode.getText(curr)}`;
67105
}, ''));
68106
}
107+
69108
const code = output.join('\n');
109+
70110
return function fix(fixer) {
71111
return fixer.replaceTextRange([front, back], code);
72112
};
@@ -78,7 +118,9 @@ module.exports = {
78118
return;
79119
}
80120

81-
if (when === 'multiline' && node.loc.start.line === node.loc.end.line) {
121+
const isSingleLineTag = node.loc.start.line === node.loc.end.line;
122+
123+
if (when === 'multiline' && isSingleLineTag) {
82124
return;
83125
}
84126

@@ -94,16 +136,24 @@ module.exports = {
94136
return decl;
95137
});
96138

139+
let maxPropsCountPerLine = maximum;
140+
97141
linePartitionedProps.forEach((propsInLine) => {
98-
if (propsInLine.length > maximum) {
99-
const name = getPropName(propsInLine[maximum]);
142+
if (isExtendedConfig) {
143+
maxPropsCountPerLine = isSingleLineTag && propsInLine[0].loc.start.line === node.loc.start.line
144+
? maximumSingle
145+
: maximumMulti;
146+
}
147+
148+
if (propsInLine.length > maxPropsCountPerLine) {
149+
const name = getPropName(propsInLine[maxPropsCountPerLine]);
100150
context.report({
101-
node: propsInLine[maximum],
151+
node: propsInLine[maxPropsCountPerLine],
102152
messageId: 'newLine',
103153
data: {
104154
prop: name
105155
},
106-
fix: generateFixFunction(propsInLine, maximum)
156+
fix: generateFixFunction(propsInLine, maxPropsCountPerLine)
107157
});
108158
}
109159
});

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

Lines changed: 180 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,70 @@ ruleTester.run('jsx-max-props-per-line', rule, {
6060
'/>'
6161
].join('\n'),
6262
options: [{maximum: 2}]
63-
}],
63+
}, {
64+
code: [
65+
'<App',
66+
' foo bar',
67+
' baz',
68+
'/>'
69+
].join('\n'),
70+
options: [{maximum: {multi: 2}}]
71+
}, {
72+
code: [
73+
'<App',
74+
' bar',
75+
' baz',
76+
'/>'
77+
].join('\n'),
78+
options: [{maximum: {multi: 2, single: 1}}]
79+
}, {
80+
code: '<App foo baz bar />',
81+
options: [{maximum: {multi: 2, single: 3}}]
82+
}, {
83+
code: '<App {...this.props} bar />',
84+
options: [{maximum: {single: 2}}]
85+
}, {
86+
code: [
87+
'<App',
88+
' foo bar',
89+
' baz bor',
90+
'/>'
91+
].join('\n'),
92+
options: [{maximum: {multi: 2, single: 1}}]
93+
}, {
94+
code: '<App foo baz bar />',
95+
options: [{maximum: {multi: 2}}]
96+
}, {
97+
code: [
98+
'<App',
99+
' foo bar',
100+
' baz bor',
101+
'/>'
102+
].join('\n'),
103+
options: [{maximum: {single: 1}}]
104+
}, {
105+
code: [
106+
'<App foo bar',
107+
' baz bor',
108+
'/>'
109+
].join('\n'),
110+
options: [{maximum: {single: 2, multi: 2}}]
111+
}, {
112+
code: [
113+
'<App foo bar',
114+
' baz bor',
115+
'/>'
116+
].join('\n'),
117+
options: [{maximum: 2}]
118+
}, {
119+
code: [
120+
'<App foo',
121+
' bar',
122+
'/>'
123+
].join('\n'),
124+
options: [{maximum: 1, when: 'multiline'}]
125+
}
126+
],
64127

65128
invalid: [{
66129
code: '<App foo bar baz />;',
@@ -266,5 +329,121 @@ ruleTester.run('jsx-max-props-per-line', rule, {
266329
messageId: 'newLine',
267330
data: {prop: 'baz'}
268331
}]
332+
},
333+
{
334+
code: '<App foo bar baz />',
335+
output: [
336+
'<App foo',
337+
'bar',
338+
'baz />'
339+
].join('\n'),
340+
options: [{maximum: {single: 1, multi: 1}}],
341+
errors: [{
342+
messageId: 'newLine',
343+
data: {prop: 'bar'}
344+
}]
345+
}, {
346+
code: [
347+
'<App',
348+
' foo bar baz',
349+
'/>'
350+
].join('\n'),
351+
output: [
352+
'<App',
353+
' foo',
354+
'bar',
355+
'baz',
356+
'/>'
357+
].join('\n'),
358+
options: [{maximum: {single: 1, multi: 1}}],
359+
errors: [{
360+
messageId: 'newLine',
361+
data: {prop: 'bar'}
362+
}]
363+
}, {
364+
code: [
365+
'<App foo',
366+
' bar baz',
367+
'/>'
368+
].join('\n'),
369+
output: [
370+
'<App foo',
371+
' bar',
372+
'baz',
373+
'/>'
374+
].join('\n'),
375+
options: [{maximum: {single: 1, multi: 1}}],
376+
errors: [{
377+
messageId: 'newLine',
378+
data: {prop: 'baz'}
379+
}]
380+
}, {
381+
code: [
382+
'<App foo bar',
383+
' bar baz bor',
384+
'/>'
385+
].join('\n'),
386+
output: [
387+
'<App foo bar',
388+
' bar baz',
389+
'bor',
390+
'/>'
391+
].join('\n'),
392+
options: [{maximum: {single: 1, multi: 2}}],
393+
errors: [
394+
{
395+
messageId: 'newLine',
396+
data: {prop: 'bor'}
397+
}]
398+
}, {
399+
code: '<App foo bar baz bor />',
400+
output: [
401+
'<App foo bar baz',
402+
'bor />'
403+
].join('\n'),
404+
options: [{maximum: {single: 3, multi: 2}}],
405+
errors: [
406+
{
407+
messageId: 'newLine',
408+
data: {prop: 'bor'}
409+
}]
410+
}, {
411+
code: [
412+
'<App',
413+
' foo={{',
414+
' }} bar baz bor',
415+
'/>'
416+
].join('\n'),
417+
output: [
418+
'<App',
419+
' foo={{',
420+
' }} bar',
421+
'baz bor',
422+
'/>'
423+
].join('\n'),
424+
options: [{maximum: {multi: 2}}],
425+
errors: [{
426+
messageId: 'newLine',
427+
data: {prop: 'baz'}
428+
}]
429+
}, {
430+
code: [
431+
'<App boz fuz',
432+
' foo={{',
433+
' }} bar baz bor',
434+
'/>'
435+
].join('\n'),
436+
output: [
437+
'<App boz fuz',
438+
' foo={{',
439+
' }} bar',
440+
'baz bor',
441+
'/>'
442+
].join('\n'),
443+
options: [{maximum: {multi: 2, single: 1}}],
444+
errors: [{
445+
messageId: 'newLine',
446+
data: {prop: 'baz'}
447+
}]
269448
}]
270449
});

0 commit comments

Comments
 (0)