Skip to content

Commit

Permalink
Add 'line-aligned' option for jsx-closing-bracket-location
Browse files Browse the repository at this point in the history
Summary:
'line-aligned' acts like 'tag-aligned' except when the opening JSX tag
is preceeded by other code on the same line.

This commit adds the rules, the corresponding tests, and updates the
documentation.

Test Plan:
npm install
npm run test

Reviewers: csilvers

Reviewed By: csilvers

Subscribers:

Differential Revision: https://phabricator.khanacademy.org/D22843
  • Loading branch information
Alex Lopatin committed Oct 29, 2015
1 parent 832a153 commit 45bf4df
Show file tree
Hide file tree
Showing 3 changed files with 243 additions and 8 deletions.
65 changes: 65 additions & 0 deletions docs/rules/jsx-closing-bracket-location.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ The second form allows you to distinguish between non-empty and self-closing tag
Enforced location for the closing bracket.

* `tag-aligned`: must be aligned with the opening tag.
* `line-aligned`: must be aligned with the line containing the opening tag.
* `after-props`: must be placed right after the last prop.
* `props-aligned`: must be aligned with the last prop.

Expand All @@ -67,6 +68,7 @@ The following patterns are considered warnings:
```jsx
// 'jsx-closing-bracket-location': 1
// 'jsx-closing-bracket-location': [1, 'tag-aligned']
// 'jsx-closing-bracket-location': [1, 'line-aligned']
<Hello
firstName="John"
lastName="Smith"
Expand All @@ -78,6 +80,37 @@ The following patterns are considered warnings:
Hello
</Say>;

// 'jsx-closing-bracket-location': 1
// 'jsx-closing-bracket-location': [1, 'tag-aligned']
var x = <Hello
firstName="John"
lastName="Smith"
/>;

var x = function() {
return <Say
firstName="John"
lastName="Smith"
>
Hello
</Say>;
};

// 'jsx-closing-bracket-location': [1, 'line-aligned']
var x = <Hello
firstName="John"
lastName="Smith"
/>;

var x = function() {
return <Say
firstName="John"
lastName="Smith"
>
Hello
</Say>;
};

// 'jsx-closing-bracket-location': [1, 'after-props']
<Hello
firstName="John"
Expand Down Expand Up @@ -108,6 +141,7 @@ The following patterns are not considered warnings:
```jsx
// 'jsx-closing-bracket-location': 1
// 'jsx-closing-bracket-location': [1, 'tag-aligned']
// 'jsx-closing-bracket-location': [1, 'line-aligned']
<Hello
firstName="John"
lastName="Smith"
Expand All @@ -120,6 +154,37 @@ The following patterns are not considered warnings:
Hello
</Say>;

// 'jsx-closing-bracket-location': 1
// 'jsx-closing-bracket-location': [1, 'tag-aligned']
var x = <Hello
firstName="John"
lastName="Smith"
/>;

var x = function() {
return <Say
firstName="John"
lastName="Smith"
>
Hello
</Say>;
};

// 'jsx-closing-bracket-location': [1, 'line-aligned']
var x = <Hello
firstName="John"
lastName="Smith"
/>;

var x = function() {
return <Say
firstName="John"
lastName="Smith"
>
Hello
</Say>;
};

// 'jsx-closing-bracket-location': [1, {selfClosing: 'after-props'}]
<Hello
firstName="John"
Expand Down
27 changes: 19 additions & 8 deletions lib/rules/jsx-closing-bracket-location.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ module.exports = function(context) {
'after-props': 'placed after the last prop',
'after-tag': 'placed after the opening tag',
'props-aligned': 'aligned with the last prop',
'tag-aligned': 'aligned with the opening tag'
'tag-aligned': 'aligned with the opening tag',
'line-aligned': 'aligned with the line containing the opening tag'
};
var DEFAULT_LOCATION = 'tag-aligned';

Expand Down Expand Up @@ -80,15 +81,19 @@ module.exports = function(context) {
return tokens.lastProp.column === tokens.closing.column;
case 'tag-aligned':
return tokens.opening.column === tokens.closing.column;
case 'line-aligned':
return tokens.openingStartOfLine.column === tokens.closing.column;
default:
return true;
}
}

/**
* Get the locations of the opening bracket, closing bracket and last prop
* Get the locations of the opening bracket, closing bracket, last prop, and
* start of opening line.
* @param {ASTNode} node The node to check
* @return {Object} Locations of the opening bracket, closing bracket and last prop
* @return {Object} Locations of the opening bracket, closing bracket, last
* prop and start of opening line.
*/
function getTokensLocations(node) {
var opening = context.getFirstToken(node).loc.start;
Expand All @@ -102,12 +107,18 @@ module.exports = function(context) {
line: context.getLastToken(lastProp).loc.end.line
};
}
var openingLine = context.getSourceCode().lines[opening.line - 1];
var openingStartOfLine = {
column: /^\s*/.exec(openingLine)[0].length,
line: opening.line
};
return {
tag: tag,
opening: opening,
closing: closing,
lastProp: lastProp,
selfClosing: node.selfClosing
selfClosing: node.selfClosing,
openingStartOfLine: openingStartOfLine
};
}

Expand All @@ -129,24 +140,24 @@ module.exports = function(context) {
module.exports.schema = [{
oneOf: [
{
enum: ['after-props', 'props-aligned', 'tag-aligned']
enum: ['after-props', 'props-aligned', 'tag-aligned', 'line-aligned']
},
{
type: 'object',
properties: {
location: {
enum: ['after-props', 'props-aligned', 'tag-aligned']
enum: ['after-props', 'props-aligned', 'tag-aligned', 'line-aligned']
}
},
additionalProperties: false
}, {
type: 'object',
properties: {
nonEmpty: {
enum: ['after-props', 'props-aligned', 'tag-aligned']
enum: ['after-props', 'props-aligned', 'tag-aligned', 'line-aligned']
},
selfClosing: {
enum: ['after-props', 'props-aligned', 'tag-aligned']
enum: ['after-props', 'props-aligned', 'tag-aligned', 'line-aligned']
}
},
additionalProperties: false
Expand Down

0 comments on commit 45bf4df

Please sign in to comment.