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 14, 2020
1 parent 182b045 commit ffdf69a
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 11 deletions.
42 changes: 41 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' || node.type === 'Literal') {
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 Down Expand Up @@ -290,6 +297,29 @@ module.exports = {
}
}

/**
* Check indent for Literal Node or JSXText Node
* @param {ASTNode} node The node to check
* @param {Number} indent needed indent
*/
function checkLiteralNodeIndent(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),
match => (match[1] ? match[1].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 @@ -340,6 +370,14 @@ module.exports = {
checkNodesIndent(firstInLine, indent);
}

function handleLiteral(node) {
if (!node.parent) {
return;
}
const parentNodeIndent = getNodeIndent(node.parent);
checkLiteralNodeIndent(node, parentNodeIndent + indentSize);
}

return {
JSXOpeningElement: handleOpeningElement,
JSXOpeningFragment: handleOpeningElement,
Expand All @@ -352,7 +390,9 @@ module.exports = {
}
const parentNodeIndent = getNodeIndent(node.parent);
checkNodesIndent(node, parentNodeIndent + indentSize);
}
},
Literal: handleLiteral,
JSXText: handleLiteral
};
}
};
3 changes: 2 additions & 1 deletion package.json
Expand Up @@ -36,7 +36,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
125 changes: 116 additions & 9 deletions tests/lib/rules/jsx-indent.js
Expand Up @@ -300,22 +300,21 @@ 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')
}, {
code: [
'<>',
'bar <>',
' bar',
' bar {foo}',
'bar </>',
' bar <>',
' bar',
' bar {foo}',
' bar </>',
'</>'
].join('\n'),
parser: parsers.BABEL_ESLINT
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,69 @@ const Component = () => (
errors: [
{message: 'Expected indentation of 8 space characters but found 4.'}
]
}, {
code: [
'<div>',
'text',
'</div>'
].join('\n'),
output: [
'<div>',
' text',
'</div>'
].join('\n'),
errors: [
{message: 'Expected indentation of 4 space characters but found 0.'}
]
}, {
code: [
'<div>',
' text',
'text',
'</div>'
].join('\n'),
output: [
'<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'),
output: [
'<div>',
' text',
' 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'),
parser: parsers.BABEL_ESLINT,
options: ['tab'],
output: [
'<div>',
'\ttext',
'</div>'
].join('\n'),
errors: [
{message: 'Expected indentation of 1 tab character but found 2.'}
]
}]
});

0 comments on commit ffdf69a

Please sign in to comment.