Skip to content

Commit

Permalink
[Fix] jsx-indent: Does not check indents for JSXText
Browse files Browse the repository at this point in the history
Fixes #2467. Fixes #2484. Fixes #1136.
  • Loading branch information
toshi-toma authored and ljharb committed Jan 28, 2020
1 parent e69b113 commit 137abcd
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 7 deletions.
39 changes: 38 additions & 1 deletion lib/rules/jsx-indent.js
Expand Up @@ -30,6 +30,8 @@

'use strict';

const matchAll = require('string.prototype.matchall');

const astUtil = require('../util/ast');
const docsUrl = require('../util/docsUrl');

Expand Down Expand Up @@ -97,6 +99,11 @@ module.exports = {
function getFixerFunction(node, needed) {
return function fix(fixer) {
const indent = Array(needed + 1).join(indentChar);
if (node.type === 'JSXText') {
const regExp = /\n[\t ]*(\S)/g;
const fixedText = node.raw.replace(regExp, (match, p1) => `\n${indent}${p1}`);
return fixer.replaceText(node, fixedText);
}
return fixer.replaceTextRange(
[node.range[0] - node.loc.start.column, node.range[0]],
indent
Expand All @@ -108,7 +115,7 @@ module.exports = {
* Reports a given indent violation and properly pluralizes the message
* @param {ASTNode} node Node violating the indent rule
* @param {Number} needed Expected indentation character count
* @param {Number} gotten Indentation character count in the actual node/code
* @param {Number|Array<number>} gotten Indentation character count in the actual node/code
* @param {Object} [loc] Error line and column location
*/
function report(node, needed, gotten, loc) {
Expand Down Expand Up @@ -290,6 +297,29 @@ module.exports = {
}
}

/**
* Check indent for JSXText
* @param {ASTNode} node The node to check
* @param {Number} indent needed indent
*/
function checkJSXTextNodeIndent(node, indent) {
const value = node.value;
const regExp = indentType === 'space' ? /\n( *)[\t ]*\S/g : /\n(\t*)[\t ]*\S/g;
const nodeIndentsPerLine = Array.from(
matchAll(value, regExp),
([, firstMatch]) => (firstMatch ? firstMatch.length : 0)
);
const hasFirstInLineNode = nodeIndentsPerLine.length > 0;
if (
hasFirstInLineNode &&
!nodeIndentsPerLine.every(actualIndent => actualIndent === indent)
) {
nodeIndentsPerLine.forEach((nodeIndent) => {
report(node, indent, nodeIndent);
});
}
}

function handleOpeningElement(node) {
const sourceCode = context.getSourceCode();
let prevToken = sourceCode.getTokenBefore(node);
Expand Down Expand Up @@ -352,6 +382,13 @@ module.exports = {
}
const parentNodeIndent = getNodeIndent(node.parent);
checkNodesIndent(node, parentNodeIndent + indentSize);
},
JSXText(node) {
if (!node.parent) {
return;
}
const parentNodeIndent = getNodeIndent(node.parent);
checkJSXTextNodeIndent(node, parentNodeIndent + indentSize);
}
};
}
Expand Down
3 changes: 2 additions & 1 deletion package.json
Expand Up @@ -34,7 +34,8 @@
"object.fromentries": "^2.0.2",
"object.values": "^1.1.1",
"prop-types": "^15.7.2",
"resolve": "^1.14.2"
"resolve": "^1.14.2",
"string.prototype.matchall": "^4.0.2"
},
"devDependencies": {
"@types/eslint": "^6.1.3",
Expand Down
94 changes: 89 additions & 5 deletions tests/lib/rules/jsx-indent.js
Expand Up @@ -300,13 +300,12 @@ ruleTester.run('jsx-indent', rule, {
].join('\n'),
parser: parsers.BABEL_ESLINT
}, {
// Literals indentation is not touched
code: [
'<div>',
'bar <div>',
' bar',
' bar {foo}',
'bar </div>',
' bar <div>',
' bar',
' bar {foo}',
' bar </div>',
'</div>'
].join('\n')
}, {
Expand Down Expand Up @@ -956,9 +955,53 @@ const Component = () => (
}
`,
options: [2, {indentLogicalExpressions: true}]
}, {
code: [
'<App>',
' text',
'</App>'
].join('\n')
}, {
code: [
'<App>',
' text',
' text',
' text',
'</App>'
].join('\n')
}, {
code: [
'<App>',
'\ttext',
'</App>'
].join('\n'),
options: ['tab']
}],

invalid: [{
code: [
'<div>',
'bar <div>',
' bar',
' bar {foo}',
' bar </div>',
'</div>'
].join('\n'),
output: [
'<div>',
' bar <div>',
' bar',
' bar {foo}',
' bar </div>',
'</div>'
].join('\n'),
errors: [
{message: 'Expected indentation of 4 space characters but found 0.'},
{message: 'Expected indentation of 4 space characters but found 3.'},
{message: 'Expected indentation of 4 space characters but found 3.'},
{message: 'Expected indentation of 4 space characters but found 3.'}
]
}, {
code: [
'<App>',
' <Foo />',
Expand Down Expand Up @@ -1883,5 +1926,46 @@ const Component = () => (
errors: [
{message: 'Expected indentation of 8 space characters but found 4.'}
]
}, {
code: [
'<div>',
'text',
'</div>'
].join('\n'),
errors: [
{message: 'Expected indentation of 4 space characters but found 0.'}
]
}, {
code: [
'<div>',
' text',
'text',
'</div>'
].join('\n'),
errors: [
{message: 'Expected indentation of 4 space characters but found 2.'},
{message: 'Expected indentation of 4 space characters but found 0.'}
]
}, {
code: [
'<div>',
'\t text',
' \t text',
'</div>'
].join('\n'),
errors: [
{message: 'Expected indentation of 4 space characters but found 0.'},
{message: 'Expected indentation of 4 space characters but found 2.'}
]
}, {
code: [
'<div>',
'\t\ttext',
'</div>'
].join('\n'),
options: ['tab'],
errors: [
{message: 'Expected indentation of 1 tab character but found 2.'}
]
}]
});

0 comments on commit 137abcd

Please sign in to comment.