Skip to content

Commit f302f05

Browse files
committed
Handle JSX attribute indentation in jsx-indent
1 parent 8ef86c5 commit f302f05

File tree

3 files changed

+85
-3
lines changed

3 files changed

+85
-3
lines changed

lib/rules/jsx-indent.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,11 +242,23 @@ module.exports = {
242242
checkNodesIndent(node, peerElementIndent);
243243
}
244244

245+
function handleAttribute(node) {
246+
if (node.value.type !== 'JSXExpressionContainer') {
247+
return;
248+
}
249+
const nameIndent = getNodeIndent(node.name);
250+
const lastToken = sourceCode.getLastToken(node.value);
251+
const firstInLine = astUtil.getFirstNodeInLine(context, lastToken);
252+
const indent = node.name.loc.start.line === firstInLine.loc.start.line ? 0 : nameIndent;
253+
checkNodesIndent(firstInLine, indent);
254+
}
255+
245256
return {
246257
JSXOpeningElement: handleOpeningElement,
247258
JSXOpeningFragment: handleOpeningElement,
248259
JSXClosingElement: handleClosingElement,
249260
JSXClosingFragment: handleClosingElement,
261+
JSXAttribute: handleAttribute,
250262
JSXExpressionContainer: function(node) {
251263
if (!node.parent) {
252264
return;

lib/util/ast.js

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,14 @@ function getComponentProperties(node) {
6868
}
6969
}
7070

71+
7172
/**
72-
* Checks if the node is the first in its line, excluding whitespace.
73+
* Gets the first node in a line from the initial node, excluding whitespace.
7374
* @param {Object} context The node to check
7475
* @param {ASTNode} node The node to check
75-
* @return {Boolean} true if it's the first node in its line
76+
* @return {ASTNode} the first node in the line
7677
*/
77-
function isNodeFirstInLine(context, node) {
78+
function getFirstNodeInLine(context, node) {
7879
const sourceCode = context.getSourceCode();
7980
let token = node;
8081
let lines;
@@ -87,7 +88,17 @@ function isNodeFirstInLine(context, node) {
8788
token.type === 'JSXText' &&
8889
/^\s*$/.test(lines[lines.length - 1])
8990
);
91+
return token;
92+
}
9093

94+
/**
95+
* Checks if the node is the first in its line, excluding whitespace.
96+
* @param {Object} context The node to check
97+
* @param {ASTNode} node The node to check
98+
* @return {Boolean} true if it's the first node in its line
99+
*/
100+
function isNodeFirstInLine(context, node) {
101+
const token = getFirstNodeInLine(context, node);
91102
const startLine = node.loc.start.line;
92103
const endLine = token ? token.loc.end.line : -1;
93104
return startLine !== endLine;
@@ -131,6 +142,7 @@ function isClass(node) {
131142

132143
module.exports = {
133144
findReturnStatement: findReturnStatement,
145+
getFirstNodeInLine: getFirstNodeInLine,
134146
getPropertyName: getPropertyName,
135147
getPropertyNameNode: getPropertyNameNode,
136148
getComponentProperties: getComponentProperties,

tests/lib/rules/jsx-indent.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1478,5 +1478,63 @@ ruleTester.run('jsx-indent', rule, {
14781478
errors: [
14791479
{message: 'Expected indentation of 4 space characters but found 2.'}
14801480
]
1481+
}, {
1482+
code: `
1483+
const Component = () => (
1484+
<View
1485+
ListFooterComponent={(
1486+
<View
1487+
rowSpan={3}
1488+
placeholder="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do"
1489+
/>
1490+
)}
1491+
/>
1492+
);
1493+
`,
1494+
output: `
1495+
const Component = () => (
1496+
<View
1497+
ListFooterComponent={(
1498+
<View
1499+
rowSpan={3}
1500+
placeholder="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do"
1501+
/>
1502+
)}
1503+
/>
1504+
);
1505+
`,
1506+
options: [2],
1507+
errors: [
1508+
{message: 'Expected indentation of 8 space characters but found 4.'}
1509+
]
1510+
}, {
1511+
code: `
1512+
const Component = () => (
1513+
\t<View
1514+
\t\tListFooterComponent={(
1515+
\t\t\t<View
1516+
\t\t\t\trowSpan={3}
1517+
\t\t\t\tplaceholder="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do"
1518+
\t\t\t/>
1519+
)}
1520+
\t/>
1521+
);
1522+
`,
1523+
output: `
1524+
const Component = () => (
1525+
\t<View
1526+
\t\tListFooterComponent={(
1527+
\t\t\t<View
1528+
\t\t\t\trowSpan={3}
1529+
\t\t\t\tplaceholder="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do"
1530+
\t\t\t/>
1531+
\t\t)}
1532+
\t/>
1533+
);
1534+
`,
1535+
options: ['tab'],
1536+
errors: [
1537+
{message: 'Expected indentation of 2 tab characters but found 0.'}
1538+
]
14811539
}]
14821540
});

0 commit comments

Comments
 (0)