diff --git a/lib/rules/jsx-first-prop-new-line.js b/lib/rules/jsx-first-prop-new-line.js
index 4a37746572..16b623bcc2 100644
--- a/lib/rules/jsx-first-prop-new-line.js
+++ b/lib/rules/jsx-first-prop-new-line.js
@@ -15,14 +15,49 @@ module.exports = {
category: 'Stylistic Issues',
recommended: false
},
+ fixable: 'code',
- schema: [{
- enum: ['always', 'never', 'multiline']
- }]
+ schema: [
+ {
+ enum: ['always', 'never', 'multiline']
+ },
+ {
+ oneOf: [{
+ enum: ['tab']
+ }, {
+ type: 'integer'
+ }]
+ }
+ ]
},
create: function (context) {
var configuration = context.options[0];
+ var indentType = 'space';
+ var indentSize = 2;
+ var sourceCode = context.getSourceCode();
+
+ if (context.options.length > 1) {
+ if (context.options[1] === 'tab') {
+ indentSize = 1;
+ indentType = 'tab';
+ } else if (typeof context.options[1] === 'number') {
+ indentSize = context.options[1];
+ indentType = 'space';
+ }
+ }
+
+ function getNodeIndent(node) {
+ var src = sourceCode.getText(node, node.loc.start.column).split('\n')[0];
+ var regExp;
+ if (indentType === 'space') {
+ regExp = new RegExp('^[ ]+');
+ } else {
+ regExp = new RegExp('^[\t' + ']+');
+ }
+ var indent = regExp.exec(src);
+ return indent ? indent[0].length : 0;
+ }
function isMultilineJSX(jsxNode) {
return jsxNode.loc.start.line < jsxNode.loc.end.line;
@@ -35,7 +70,12 @@ module.exports = {
if (decl.loc.start.line === node.loc.start.line) {
context.report({
node: decl,
- message: 'Property should be placed on a new line'
+ message: 'Property should be placed on a new line',
+ fix: function(fixer) {
+ var neededIndent = getNodeIndent(node) + indentSize;
+ var insert = '\n' + Array(neededIndent + 1).join(indentType === 'space' ? ' ' : '\t');
+ return fixer.replaceTextRange([node.name.end, decl.start], insert);
+ }
});
}
});
@@ -44,7 +84,10 @@ module.exports = {
if (node.loc.start.line < firstNode.loc.start.line) {
context.report({
node: firstNode,
- message: 'Property should be placed on the same line as the component declaration'
+ message: 'Property should be placed on the same line as the component declaration',
+ fix: function(fixer) {
+ return fixer.replaceTextRange([node.name.end, firstNode.start], ' ');
+ }
});
return;
}
diff --git a/tests/lib/rules/jsx-first-prop-new-line.js b/tests/lib/rules/jsx-first-prop-new-line.js
index 2fd2dab2c1..43edaf30c0 100644
--- a/tests/lib/rules/jsx-first-prop-new-line.js
+++ b/tests/lib/rules/jsx-first-prop-new-line.js
@@ -120,6 +120,10 @@ ruleTester.run('jsx-first-prop-new-line', rule, {
invalid: [
{
code: '',
+ output: [
+ ''
+ ].join('\n'),
options: ['always'],
errors: [{message: 'Property should be placed on a new line'}],
parser: parserOptions
@@ -130,15 +134,58 @@ ruleTester.run('jsx-first-prop-new-line', rule, {
' propTwo="two"',
'/>'
].join('\n'),
+ output: [
+ ''
+ ].join('\n'),
options: ['always'],
errors: [{message: 'Property should be placed on a new line'}],
parser: parserOptions
},
+ {
+ code: [
+ ' '
+ ].join('\n'),
+ output: [
+ ' '
+ ].join('\n'),
+ options: ['always', 4],
+ errors: [{message: 'Property should be placed on a new line'}],
+ parser: parserOptions
+ },
+ {
+ code: [
+ '\t'
+ ].join('\n'),
+ output: [
+ '\t'
+ ].join('\n'),
+ options: ['always', 'tab'],
+ errors: [{message: 'Property should be placed on a new line'}],
+ parser: parserOptions
+ },
{
code: [
''
+ ].join('\n'),
+ output: [
+ ''
].join('\n'),
options: ['never'],