Skip to content

Commit 45bf4df

Browse files
author
Alex Lopatin
committed
Add 'line-aligned' option for jsx-closing-bracket-location
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
1 parent 832a153 commit 45bf4df

File tree

3 files changed

+243
-8
lines changed

3 files changed

+243
-8
lines changed

docs/rules/jsx-closing-bracket-location.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ The second form allows you to distinguish between non-empty and self-closing tag
5555
Enforced location for the closing bracket.
5656

5757
* `tag-aligned`: must be aligned with the opening tag.
58+
* `line-aligned`: must be aligned with the line containing the opening tag.
5859
* `after-props`: must be placed right after the last prop.
5960
* `props-aligned`: must be aligned with the last prop.
6061

@@ -67,6 +68,7 @@ The following patterns are considered warnings:
6768
```jsx
6869
// 'jsx-closing-bracket-location': 1
6970
// 'jsx-closing-bracket-location': [1, 'tag-aligned']
71+
// 'jsx-closing-bracket-location': [1, 'line-aligned']
7072
<Hello
7173
firstName="John"
7274
lastName="Smith"
@@ -78,6 +80,37 @@ The following patterns are considered warnings:
7880
Hello
7981
</Say>;
8082

83+
// 'jsx-closing-bracket-location': 1
84+
// 'jsx-closing-bracket-location': [1, 'tag-aligned']
85+
var x = <Hello
86+
firstName="John"
87+
lastName="Smith"
88+
/>;
89+
90+
var x = function() {
91+
return <Say
92+
firstName="John"
93+
lastName="Smith"
94+
>
95+
Hello
96+
</Say>;
97+
};
98+
99+
// 'jsx-closing-bracket-location': [1, 'line-aligned']
100+
var x = <Hello
101+
firstName="John"
102+
lastName="Smith"
103+
/>;
104+
105+
var x = function() {
106+
return <Say
107+
firstName="John"
108+
lastName="Smith"
109+
>
110+
Hello
111+
</Say>;
112+
};
113+
81114
// 'jsx-closing-bracket-location': [1, 'after-props']
82115
<Hello
83116
firstName="John"
@@ -108,6 +141,7 @@ The following patterns are not considered warnings:
108141
```jsx
109142
// 'jsx-closing-bracket-location': 1
110143
// 'jsx-closing-bracket-location': [1, 'tag-aligned']
144+
// 'jsx-closing-bracket-location': [1, 'line-aligned']
111145
<Hello
112146
firstName="John"
113147
lastName="Smith"
@@ -120,6 +154,37 @@ The following patterns are not considered warnings:
120154
Hello
121155
</Say>;
122156

157+
// 'jsx-closing-bracket-location': 1
158+
// 'jsx-closing-bracket-location': [1, 'tag-aligned']
159+
var x = <Hello
160+
firstName="John"
161+
lastName="Smith"
162+
/>;
163+
164+
var x = function() {
165+
return <Say
166+
firstName="John"
167+
lastName="Smith"
168+
>
169+
Hello
170+
</Say>;
171+
};
172+
173+
// 'jsx-closing-bracket-location': [1, 'line-aligned']
174+
var x = <Hello
175+
firstName="John"
176+
lastName="Smith"
177+
/>;
178+
179+
var x = function() {
180+
return <Say
181+
firstName="John"
182+
lastName="Smith"
183+
>
184+
Hello
185+
</Say>;
186+
};
187+
123188
// 'jsx-closing-bracket-location': [1, {selfClosing: 'after-props'}]
124189
<Hello
125190
firstName="John"

lib/rules/jsx-closing-bracket-location.js

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ module.exports = function(context) {
1414
'after-props': 'placed after the last prop',
1515
'after-tag': 'placed after the opening tag',
1616
'props-aligned': 'aligned with the last prop',
17-
'tag-aligned': 'aligned with the opening tag'
17+
'tag-aligned': 'aligned with the opening tag',
18+
'line-aligned': 'aligned with the line containing the opening tag'
1819
};
1920
var DEFAULT_LOCATION = 'tag-aligned';
2021

@@ -80,15 +81,19 @@ module.exports = function(context) {
8081
return tokens.lastProp.column === tokens.closing.column;
8182
case 'tag-aligned':
8283
return tokens.opening.column === tokens.closing.column;
84+
case 'line-aligned':
85+
return tokens.openingStartOfLine.column === tokens.closing.column;
8386
default:
8487
return true;
8588
}
8689
}
8790

8891
/**
89-
* Get the locations of the opening bracket, closing bracket and last prop
92+
* Get the locations of the opening bracket, closing bracket, last prop, and
93+
* start of opening line.
9094
* @param {ASTNode} node The node to check
91-
* @return {Object} Locations of the opening bracket, closing bracket and last prop
95+
* @return {Object} Locations of the opening bracket, closing bracket, last
96+
* prop and start of opening line.
9297
*/
9398
function getTokensLocations(node) {
9499
var opening = context.getFirstToken(node).loc.start;
@@ -102,12 +107,18 @@ module.exports = function(context) {
102107
line: context.getLastToken(lastProp).loc.end.line
103108
};
104109
}
110+
var openingLine = context.getSourceCode().lines[opening.line - 1];
111+
var openingStartOfLine = {
112+
column: /^\s*/.exec(openingLine)[0].length,
113+
line: opening.line
114+
};
105115
return {
106116
tag: tag,
107117
opening: opening,
108118
closing: closing,
109119
lastProp: lastProp,
110-
selfClosing: node.selfClosing
120+
selfClosing: node.selfClosing,
121+
openingStartOfLine: openingStartOfLine
111122
};
112123
}
113124

@@ -129,24 +140,24 @@ module.exports = function(context) {
129140
module.exports.schema = [{
130141
oneOf: [
131142
{
132-
enum: ['after-props', 'props-aligned', 'tag-aligned']
143+
enum: ['after-props', 'props-aligned', 'tag-aligned', 'line-aligned']
133144
},
134145
{
135146
type: 'object',
136147
properties: {
137148
location: {
138-
enum: ['after-props', 'props-aligned', 'tag-aligned']
149+
enum: ['after-props', 'props-aligned', 'tag-aligned', 'line-aligned']
139150
}
140151
},
141152
additionalProperties: false
142153
}, {
143154
type: 'object',
144155
properties: {
145156
nonEmpty: {
146-
enum: ['after-props', 'props-aligned', 'tag-aligned']
157+
enum: ['after-props', 'props-aligned', 'tag-aligned', 'line-aligned']
147158
},
148159
selfClosing: {
149-
enum: ['after-props', 'props-aligned', 'tag-aligned']
160+
enum: ['after-props', 'props-aligned', 'tag-aligned', 'line-aligned']
150161
}
151162
},
152163
additionalProperties: false

0 commit comments

Comments
 (0)