diff --git a/lib/rules/jsx-indent.js b/lib/rules/jsx-indent.js index fa81f8f673..bbdeaabce0 100644 --- a/lib/rules/jsx-indent.js +++ b/lib/rules/jsx-indent.js @@ -30,6 +30,8 @@ 'use strict'; +const matchAll = require('string.prototype.matchall'); + const astUtil = require('../util/ast'); const docsUrl = require('../util/docsUrl'); @@ -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 @@ -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); @@ -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, @@ -352,7 +390,9 @@ module.exports = { } const parentNodeIndent = getNodeIndent(node.parent); checkNodesIndent(node, parentNodeIndent + indentSize); - } + }, + Literal: handleLiteral, + JSXText: handleLiteral }; } }; diff --git a/package.json b/package.json index b314901aba..53f5eaeafc 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/tests/lib/rules/jsx-indent.js b/tests/lib/rules/jsx-indent.js index af01578abc..9a245f1e18 100644 --- a/tests/lib/rules/jsx-indent.js +++ b/tests/lib/rules/jsx-indent.js @@ -300,22 +300,21 @@ ruleTester.run('jsx-indent', rule, { ].join('\n'), parser: parsers.BABEL_ESLINT }, { - // Literals indentation is not touched code: [ '