Skip to content

Commit 66593e5

Browse files
Sebastian Zimmerljharb
Sebastian Zimmer
authored andcommitted
[New] jsx-indent-props: add ignoreTernaryOperator option
Fixes #2841.
1 parent 816e344 commit 66593e5

File tree

4 files changed

+92
-7
lines changed

4 files changed

+92
-7
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
1010
* [`jsx-newline`]: add new rule ([#2693][] @jzabala)
1111
* [`jsx-no-constructed-context-values`]: add new rule which checks when the value passed to a Context Provider will cause needless rerenders ([#2763][] @dylanOshima)
1212
* [`jsx-wrap-multilines`]: fix crash with `declaration`s that are on a new line after `=` ([#2875][] @ljharb)
13+
* [`jsx-indent-props`]: add `ignoreTernaryOperator` option ([#2846][] @SebastianZimmer)
1314

1415
### Fixed
1516
* [`display-name`]/component detection: avoid a crash on anonymous components ([#2840][] @ljharb)
@@ -36,6 +37,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
3637
[#2869]: https://github.com/yannickcr/eslint-plugin-react/issues/2869
3738
[#2852]: https://github.com/yannickcr/eslint-plugin-react/pull/2852
3839
[#2851]: https://github.com/yannickcr/eslint-plugin-react/issues/2851
40+
[#2846]: https://github.com/yannickcr/eslint-plugin-react/pull/2846
3941
[#2843]: https://github.com/yannickcr/eslint-plugin-react/pull/2843
4042
[#2840]: https://github.com/yannickcr/eslint-plugin-react/issues/2840
4143
[#2835]: https://github.com/yannickcr/eslint-plugin-react/pull/2835

docs/rules/jsx-indent-props.md

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,15 @@ firstName="John"
2929

3030
## Rule Options
3131

32-
It takes an option as the second parameter which can be `"tab"` for tab-based indentation, a positive number for space indentations or `"first"` for aligning the first prop for each line with the tag's first prop.
32+
It takes an option as the second parameter which can either be the indent mode or an object to define further settings.
33+
The indent mode can be `"tab"` for tab-based indentation, a positive number for space indentations or `"first"` for aligning the first prop for each line with the tag's first prop.
3334
Note that using the `"first"` option allows very inconsistent indentation unless you also enable a rule that enforces the position of the first prop.
35+
If the second parameter is an object, it can be used to specify the indent mode as well as the option `ignoreTernaryOperator`, which causes the indent level not to be increased by a `?` or `:` operator (default is `false`).
36+
3437

3538
```js
3639
...
37-
"react/jsx-indent-props": [<enabled>, 'tab'|<number>|'first']
40+
"react/jsx-indent-props": [<enabled>, 'tab'|<number>|'first'|<object>]
3841
...
3942
```
4043

@@ -100,6 +103,20 @@ firstName="John"
100103

101104
<Hello firstName="Jane"
102105
lastName="Doe" />
106+
107+
// indent level increase on ternary operator (default setting)
108+
// [2, 2]
109+
? <Hello
110+
firstName="John"
111+
lastName="Doe"
112+
/>
113+
114+
// no indent level increase on ternary operator
115+
// [2, { indentMode: 2, ignoreTernaryOperator: true} ]
116+
? <Hello
117+
firstName="John"
118+
lastName="Doe"
119+
/>
103120
```
104121
105122
## When not to use

lib/rules/jsx-indent-props.js

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,20 @@ module.exports = {
5151
enum: ['tab', 'first']
5252
}, {
5353
type: 'integer'
54+
}, {
55+
type: 'object',
56+
properties: {
57+
indentMode: {
58+
oneOf: [{
59+
enum: ['tab', 'first']
60+
}, {
61+
type: 'integer'
62+
}]
63+
},
64+
ignoreTernaryOperator: {
65+
type: 'boolean'
66+
}
67+
}
5468
}]
5569
}]
5670
},
@@ -66,18 +80,28 @@ module.exports = {
6680
isUsingOperator: false,
6781
currentOperator: false
6882
};
83+
let ignoreTernaryOperator = false;
6984

7085
if (context.options.length) {
71-
if (context.options[0] === 'first') {
86+
const isConfigObject = typeof context.options[0] === 'object';
87+
const indentMode = isConfigObject
88+
? context.options[0].indentMode
89+
: context.options[0];
90+
91+
if (indentMode === 'first') {
7292
indentSize = 'first';
7393
indentType = 'space';
74-
} else if (context.options[0] === 'tab') {
94+
} else if (indentMode === 'tab') {
7595
indentSize = 1;
7696
indentType = 'tab';
77-
} else if (typeof context.options[0] === 'number') {
78-
indentSize = context.options[0];
97+
} else if (typeof indentMode === 'number') {
98+
indentSize = indentMode;
7999
indentType = 'space';
80100
}
101+
102+
if (isConfigObject && context.options[0].ignoreTernaryOperator) {
103+
ignoreTernaryOperator = true;
104+
}
81105
}
82106

83107
/**
@@ -145,7 +169,7 @@ module.exports = {
145169
function checkNodesIndent(nodes, indent) {
146170
nodes.forEach((node) => {
147171
const nodeIndent = getNodeIndent(node);
148-
if (line.isUsingOperator && !line.currentOperator && indentSize !== 'first') {
172+
if (line.isUsingOperator && !line.currentOperator && indentSize !== 'first' && !ignoreTernaryOperator) {
149173
indent += indentSize;
150174
line.isUsingOperator = false;
151175
}

tests/lib/rules/jsx-indent-props.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,48 @@ ruleTester.run('jsx-indent-props', rule, {
153153
'/>'
154154
].join('\n'),
155155
options: ['first']
156+
}, {
157+
code: [
158+
'{this.props.ignoreTernaryOperatorFalse',
159+
' ? <span',
160+
' className="value"',
161+
' some={{aaa}}',
162+
' />',
163+
' : null}'
164+
].join('\n'),
165+
output: [
166+
'{this.props.ignoreTernaryOperatorFalse',
167+
' ? <span',
168+
' className="value"',
169+
' some={{aaa}}',
170+
' />',
171+
' : null}'
172+
].join('\n'),
173+
options: [{
174+
indentMode: 2,
175+
ignoreTernaryOperator: false
176+
}]
177+
}, {
178+
code: [
179+
'{this.props.ignoreTernaryOperatorTrue',
180+
' ? <span',
181+
' className="value"',
182+
' some={{aaa}}',
183+
' />',
184+
' : null}'
185+
].join('\n'),
186+
output: [
187+
'{this.props.ignoreTernaryOperatorTrue',
188+
' ? <span',
189+
' className="value"',
190+
' some={{aaa}}',
191+
' />',
192+
' : null}'
193+
].join('\n'),
194+
options: [{
195+
indentMode: 2,
196+
ignoreTernaryOperator: true
197+
}]
156198
}],
157199

158200
invalid: [{

0 commit comments

Comments
 (0)