diff --git a/lib/rules/jsx-closing-bracket-location.js b/lib/rules/jsx-closing-bracket-location.js
index fb25c4f4db..9da181467e 100644
--- a/lib/rules/jsx-closing-bracket-location.js
+++ b/lib/rules/jsx-closing-bracket-location.js
@@ -146,6 +146,33 @@ module.exports = {
}
}
+ /**
+ * Get the characters used for indentation on the line to be matched
+ * @param {Object} tokens Locations of the opening bracket, closing bracket and last prop
+ * @param {String} expectedLocation Expected location for the closing bracket
+ * @param {Number} correctColumn Expected column for the closing bracket
+ * @return {String} The characters used for indentation
+ */
+ function getIndentation(tokens, expectedLocation, correctColumn) {
+ var indentation, spaces = [];
+ switch (expectedLocation) {
+ case 'props-aligned':
+ indentation = /^\s*/.exec(sourceCode.lines[tokens.lastProp.firstLine - 1])[0];
+ break;
+ case 'tag-aligned':
+ case 'line-aligned':
+ indentation = /^\s*/.exec(sourceCode.lines[tokens.opening.line - 1])[0];
+ break;
+ default:
+ indentation = '';
+ }
+ if (indentation.length + 1 < correctColumn) {
+ // Non-whitespace characters were included in the column offset
+ spaces = new Array(+correctColumn + 1 - indentation.length);
+ }
+ return indentation + spaces.join(' ');
+ }
+
/**
* Get the locations of the opening bracket, closing bracket, last prop, and
* start of opening line.
@@ -244,9 +271,8 @@ module.exports = {
case 'props-aligned':
case 'tag-aligned':
case 'line-aligned':
- var spaces = new Array(+correctColumn + 1);
return fixer.replaceTextRange([cachedLastAttributeEndPos, node.end],
- '\n' + spaces.join(' ') + closingTag);
+ '\n' + getIndentation(tokens, expectedLocation, correctColumn) + closingTag);
default:
return true;
}
diff --git a/tests/lib/rules/jsx-closing-bracket-location.js b/tests/lib/rules/jsx-closing-bracket-location.js
index 9a2f2a147d..7571a1e580 100644
--- a/tests/lib/rules/jsx-closing-bracket-location.js
+++ b/tests/lib/rules/jsx-closing-bracket-location.js
@@ -398,6 +398,334 @@ ruleTester.run('jsx-closing-bracket-location', rule, {
].join('\n'),
options: [{location: 'tag-aligned'}],
parserOptions: parserOptions
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ parserOptions: parserOptions
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ options: ['after-props'],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ options: ['props-aligned'],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ options: [{location: 'after-props'}],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ options: [{location: 'tag-aligned'}],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ options: [{location: 'line-aligned'}],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ options: [{location: 'props-aligned'}],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ options: [{location: 'tag-aligned'}],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ options: [{location: 'line-aligned'}],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ options: [{location: 'props-aligned'}],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ options: [{location: 'after-props'}],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ options: [{location: 'props-aligned'}],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ options: [{location: 'tag-aligned'}],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ options: [{location: 'line-aligned'}],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ options: [{location: 'after-props'}],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ options: [{location: 'props-aligned'}],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ options: [{location: 'tag-aligned'}],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ options: [{location: 'line-aligned'}],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ '',
+ '\t',
+ ''
+ ].join('\n'),
+ options: [{selfClosing: 'after-props'}],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ '',
+ '\t',
+ ''
+ ].join('\n'),
+ options: [{selfClosing: 'after-props'}],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ '',
+ '\t',
+ ''
+ ].join('\n'),
+ options: [{nonEmpty: 'after-props'}],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ '',
+ '\t',
+ ''
+ ].join('\n'),
+ options: [{selfClosing: 'props-aligned'}],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ '',
+ '\t',
+ ''
+ ].join('\n'),
+ options: [{nonEmpty: 'props-aligned'}],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ 'var x = function() {',
+ '\treturn ',
+ '\t\t\tbar',
+ '\t ',
+ '}'
+ ].join('\n'),
+ options: [{location: 'tag-aligned'}],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ 'var x = function() {',
+ '\treturn ',
+ '}'
+ ].join('\n'),
+ options: [{location: 'tag-aligned'}],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ 'var x = '
+ ].join('\n'),
+ options: [{location: 'tag-aligned'}],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ 'var x = function() {',
+ '\treturn ',
+ '}'
+ ].join('\n'),
+ options: [{location: 'line-aligned'}],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ 'var x = '
+ ].join('\n'),
+ options: [{location: 'line-aligned'}],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ '',
+ '\t',
+ ''
+ ].join('\n'),
+ options: [{location: 'line-aligned'}],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ '',
+ '\t{baz && }',
+ ''
+ ].join('\n'),
+ options: [{location: 'line-aligned'}],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ '',
+ '\t',
+ '\t',
+ '\t',
+ ''
+ ].join('\n'),
+ options: [{
+ nonEmpty: false,
+ selfClosing: 'after-props'
+ }],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ '',
+ '\t',
+ '\t',
+ '\t',
+ ''
+ ].join('\n'),
+ options: [{
+ nonEmpty: 'after-props',
+ selfClosing: false
+ }],
+ parserOptions: parserOptions
+ }, {
+ code: [
+ '
',
+ '\tSome text',
+ '
'
+ ].join('\n'),
+ options: [{location: 'tag-aligned'}],
+ parserOptions: parserOptions
}],
invalid: [{
@@ -959,5 +1287,534 @@ ruleTester.run('jsx-closing-bracket-location', rule, {
line: 4,
column: 7
}]
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ output: [
+ ''
+ ].join('\n'),
+ options: [{location: 'props-aligned'}],
+ parserOptions: parserOptions,
+ errors: [{
+ message: messageWithDetails(MESSAGE_PROPS_ALIGNED, 2, true),
+ line: 2,
+ column: 6
+ }]
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ output: [
+ ''
+ ].join('\n'),
+ options: [{location: 'tag-aligned'}],
+ parserOptions: parserOptions,
+ errors: [{
+ message: messageWithDetails(MESSAGE_TAG_ALIGNED, 1, true),
+ line: 2,
+ column: 6
+ }]
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ output: [
+ ''
+ ].join('\n'),
+ options: [{location: 'line-aligned'}],
+ parserOptions: parserOptions,
+ errors: [{
+ message: messageWithDetails(MESSAGE_LINE_ALIGNED, 1, true),
+ line: 2,
+ column: 6
+ }]
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ output: [
+ ''
+ ].join('\n'),
+ options: [{location: 'after-props'}],
+ parserOptions: parserOptions,
+ errors: MESSAGE_AFTER_PROPS
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ output: [
+ ''
+ ].join('\n'),
+ options: [{location: 'props-aligned'}],
+ parserOptions: parserOptions,
+ errors: [{
+ message: messageWithDetails(MESSAGE_PROPS_ALIGNED, 2, false),
+ line: 3,
+ column: 1
+ }]
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ output: [
+ ''
+ ].join('\n'),
+ options: [{location: 'after-props'}],
+ parserOptions: parserOptions,
+ errors: MESSAGE_AFTER_PROPS
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ output: [
+ ''
+ ].join('\n'),
+ options: [{location: 'tag-aligned'}],
+ parserOptions: parserOptions,
+ errors: [{
+ message: messageWithDetails(MESSAGE_TAG_ALIGNED, 1, false),
+ line: 3,
+ column: 2
+ }]
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ output: [
+ ''
+ ].join('\n'),
+ options: [{location: 'line-aligned'}],
+ parserOptions: parserOptions,
+ errors: [{
+ message: messageWithDetails(MESSAGE_LINE_ALIGNED, 1, false),
+ line: 3,
+ column: 2
+ }]
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ output: [
+ ''
+ ].join('\n'),
+ options: [{location: 'after-props'}],
+ parserOptions: parserOptions,
+ errors: MESSAGE_AFTER_PROPS
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ output: [
+ ''
+ ].join('\n'),
+ options: [{location: 'props-aligned'}],
+ parserOptions: parserOptions,
+ errors: [{
+ message: messageWithDetails(MESSAGE_PROPS_ALIGNED, 2, false),
+ line: 3,
+ column: 1
+ }]
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ output: [
+ ''
+ ].join('\n'),
+ options: [{location: 'after-props'}],
+ parserOptions: parserOptions,
+ errors: MESSAGE_AFTER_PROPS
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ output: [
+ ''
+ ].join('\n'),
+ options: [{location: 'tag-aligned'}],
+ parserOptions: parserOptions,
+ errors: [{
+ message: messageWithDetails(MESSAGE_TAG_ALIGNED, 1, false),
+ line: 3,
+ column: 2
+ }]
+ }, {
+ code: [
+ ''
+ ].join('\n'),
+ output: [
+ ''
+ ].join('\n'),
+ options: [{location: 'line-aligned'}],
+ parserOptions: parserOptions,
+ errors: [{
+ message: messageWithDetails(MESSAGE_LINE_ALIGNED, 1, false),
+ line: 3,
+ column: 2
+ }]
+ }, {
+ code: [
+ '', // <--
+ '\t',
+ ''
+ ].join('\n'),
+ output: [
+ '',
+ '\t',
+ ''
+ ].join('\n'),
+ options: [{selfClosing: 'props-aligned'}],
+ parserOptions: parserOptions,
+ errors: [{
+ message: messageWithDetails(MESSAGE_TAG_ALIGNED, 1, true),
+ line: 2,
+ column: 7
+ }]
+ }, {
+ code: [
+ 'const Button = function(props) {',
+ '\treturn (',
+ '\t\t',
+ '\t);',
+ '};'
+ ].join('\n'),
+ output: [
+ 'const Button = function(props) {',
+ '\treturn (',
+ '\t\t',
+ '\t);',
+ '};'
+ ].join('\n'),
+ options: ['props-aligned'],
+ parserOptions: parserOptions,
+ errors: [{
+ message: messageWithDetails(MESSAGE_PROPS_ALIGNED, 4, false),
+ line: 6,
+ column: 19
+ }]
+ }, {
+ code: [
+ 'const Button = function(props) {',
+ '\treturn (',
+ '\t\t',
+ '\t);',
+ '};'
+ ].join('\n'),
+ output: [
+ 'const Button = function(props) {',
+ '\treturn (',
+ '\t\t',
+ '\t);',
+ '};'
+ ].join('\n'),
+ options: ['tag-aligned'],
+ parserOptions: parserOptions,
+ errors: [{
+ message: messageWithDetails(MESSAGE_TAG_ALIGNED, 3, false),
+ line: 6,
+ column: 19
+ }]
+ }, {
+ code: [
+ 'const Button = function(props) {',
+ '\treturn (',
+ '\t\t',
+ '\t);',
+ '};'
+ ].join('\n'),
+ output: [
+ 'const Button = function(props) {',
+ '\treturn (',
+ '\t\t',
+ '\t);',
+ '};'
+ ].join('\n'),
+ options: ['line-aligned'],
+ parserOptions: parserOptions,
+ errors: [{
+ message: messageWithDetails(MESSAGE_LINE_ALIGNED, 3, false),
+ line: 6,
+ column: 19
+ }]
+ }, {
+ code: [
+ '',
+ '\t', // <--
+ ''
+ ].join('\n'),
+ output: [
+ '',
+ '\t',
+ ''
+ ].join('\n'),
+ options: [{nonEmpty: 'props-aligned'}],
+ parserOptions: parserOptions,
+ errors: [{
+ message: messageWithDetails(MESSAGE_TAG_ALIGNED, 2, false),
+ line: 6,
+ column: 3
+ }]
+ }, {
+ code: [
+ '', // <--
+ '\t',
+ ''
+ ].join('\n'),
+ output: [
+ '',
+ '\t',
+ ''
+ ].join('\n'),
+ options: [{selfClosing: 'after-props'}],
+ parserOptions: parserOptions,
+ errors: [{
+ message: messageWithDetails(MESSAGE_TAG_ALIGNED, 1, true),
+ line: 2,
+ column: 7
+ }]
+ }, {
+ code: [
+ '',
+ '\t', // <--
+ ''
+ ].join('\n'),
+ output: [
+ '',
+ '\t', // <--
+ ''
+ ].join('\n'),
+ options: [{nonEmpty: 'after-props'}],
+ parserOptions: parserOptions,
+ errors: [{
+ message: messageWithDetails(MESSAGE_TAG_ALIGNED, 2, false),
+ line: 5,
+ column: 3
+ }]
+ }, {
+ code: [
+ 'var x = function() {',
+ '\treturn ',
+ '}'
+ ].join('\n'),
+ output: [
+ 'var x = function() {',
+ '\treturn ',
+ '}'
+ ].join('\n'),
+ options: [{location: 'line-aligned'}],
+ parserOptions: parserOptions,
+ errors: [{
+ message: messageWithDetails(MESSAGE_LINE_ALIGNED, 2, false),
+ line: 4,
+ column: 6
+ }]
+ }, {
+ code: [
+ 'var x = '
+ ].join('\n'),
+ output: [
+ 'var x = '
+ ].join('\n'),
+ options: [{location: 'line-aligned'}],
+ parserOptions: parserOptions,
+ errors: [{
+ message: messageWithDetails(MESSAGE_LINE_ALIGNED, 1, false),
+ line: 3,
+ column: 9
+ }]
+ }, {
+ code: [
+ 'var x = (',
+ '\t',
+ ')'
+ ].join('\n'),
+ output: [
+ 'var x = (',
+ '\t',
+ ')'
+ ].join('\n'),
+ options: [{location: 'line-aligned'}],
+ parserOptions: parserOptions,
+ errors: [{
+ message: messageWithDetails(MESSAGE_LINE_ALIGNED, 2, true),
+ line: 4,
+ column: 14
+ }]
+ }, {
+ code: [
+ 'var x = (',
+ '\t} />',
+ ')'
+ ].join('\n'),
+ output: [
+ 'var x = (',
+ '\t}',
+ '\t/>',
+ ')'
+ ].join('\n'),
+ options: [{location: 'line-aligned'}],
+ parserOptions: parserOptions,
+ errors: [{
+ message: messageWithDetails(MESSAGE_LINE_ALIGNED, 2, true),
+ line: 3,
+ column: 21
+ }]
+ }, {
+ code: [
+ 'var x = (',
+ '\t',
+ ')'
+ ].join('\n'),
+ output: [
+ 'var x = (',
+ '\t',
+ ')'
+ ].join('\n'),
+ options: [{location: 'line-aligned'}],
+ parserOptions: parserOptions,
+ errors: [MESSAGE_AFTER_TAG]
+ }, {
+ code: [
+ '',
+ '\tSome text',
+ '
'
+ ].join('\n'),
+ output: [
+ '',
+ '\tSome text',
+ '
'
+ ].join('\n'),
+ options: [{location: 'tag-aligned'}],
+ parserOptions: parserOptions,
+ errors: [{
+ message: messageWithDetails(MESSAGE_TAG_ALIGNED, 1, true),
+ line: 4,
+ column: 6
+ }]
}]
});