Skip to content

Commit 25d74d5

Browse files
committed
Fix: change multiline-always to proportional-always
- If the node is multiline then require newline - If the node is singleline then require space Signed-off-by: Sebastian Malton <[email protected]>
1 parent c297a96 commit 25d74d5

File tree

3 files changed

+84
-64
lines changed

3 files changed

+84
-64
lines changed

lib/rules/jsx-tag-spacing.js

Lines changed: 62 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,9 @@ function validateBeforeSelfClosing(context, node, option) {
101101
const leftToken = getTokenBeforeClosingBracket(node);
102102
const closingSlash = sourceCode.getTokenAfter(leftToken);
103103

104-
if (node.loc.start.line !== node.loc.end.line && option === 'multiline-always') {
104+
if (node.loc.start.line !== node.loc.end.line && option === 'proportional-always') {
105105
if (leftToken.loc.end.line === closingSlash.loc.start.line) {
106-
report(context, messages.beforeSelfCloseNeedNewline, 'beforeSelfCloseNeedNewline', {
106+
return report(context, messages.beforeSelfCloseNeedNewline, 'beforeSelfCloseNeedNewline', {
107107
node,
108108
loc: leftToken.loc.end,
109109
fix(fixer) {
@@ -117,15 +117,17 @@ function validateBeforeSelfClosing(context, node, option) {
117117
return;
118118
}
119119

120-
if (option === 'always' && !sourceCode.isSpaceBetweenTokens(leftToken, closingSlash)) {
120+
const adjacent = !sourceCode.isSpaceBetweenTokens(leftToken, closingSlash);
121+
122+
if ((option === 'always' || option === 'proportional-always') && adjacent) {
121123
report(context, messages.beforeSelfCloseNeedSpace, 'beforeSelfCloseNeedSpace', {
122124
node,
123125
loc: closingSlash.loc.start,
124126
fix(fixer) {
125127
return fixer.insertTextBefore(closingSlash, ' ');
126128
},
127129
});
128-
} else if (option === 'never' && sourceCode.isSpaceBetweenTokens(leftToken, closingSlash)) {
130+
} else if (option === 'never' && !adjacent) {
129131
report(context, messages.beforeSelfCloseNoSpace, 'beforeSelfCloseNoSpace', {
130132
node,
131133
loc: closingSlash.loc.start,
@@ -178,54 +180,68 @@ function validateAfterOpening(context, node, option) {
178180

179181
function validateBeforeClosing(context, node, option) {
180182
// Don't enforce this rule for self closing tags
181-
if (!node.selfClosing) {
182-
const sourceCode = context.getSourceCode();
183-
const lastTokens = sourceCode.getLastTokens(node, 2);
184-
const closingToken = lastTokens[1];
185-
const leftToken = lastTokens[0];
186-
187-
if (node.loc.start.line !== node.loc.end.line && option === 'multiline-always') {
188-
if (leftToken.loc.end.line === closingToken.loc.start.line) {
189-
report(context, messages.beforeCloseNeedNewline, 'beforeCloseNeedNewline', {
190-
node,
191-
loc: leftToken.loc.end,
192-
fix(fixer) {
193-
return fixer.insertTextBefore(closingToken, '\n');
194-
},
195-
});
196-
}
197-
}
198-
199-
if (leftToken.loc.start.line !== closingToken.loc.start.line) {
200-
return;
201-
}
183+
if (node.selfClosing) {
184+
return;
185+
}
202186

203-
const adjacent = !sourceCode.isSpaceBetweenTokens(leftToken, closingToken);
187+
const sourceCode = context.getSourceCode();
188+
const leftToken = option === 'proportional-always'
189+
? getTokenBeforeClosingBracket(node)
190+
: sourceCode.getLastTokens(node, 2)[0];
191+
const closingToken = sourceCode.getTokenAfter(leftToken);
204192

205-
if (option === 'never' && !adjacent) {
206-
report(context, messages.beforeCloseNoSpace, 'beforeCloseNoSpace', {
193+
if (node.loc.start.line !== node.loc.end.line && option === 'proportional-always') {
194+
if (leftToken.loc.end.line === closingToken.loc.start.line) {
195+
return report(context, messages.beforeCloseNeedNewline, 'beforeCloseNeedNewline', {
207196
node,
208-
loc: {
209-
start: leftToken.loc.end,
210-
end: closingToken.loc.start,
211-
},
212-
fix(fixer) {
213-
return fixer.removeRange([leftToken.range[1], closingToken.range[0]]);
214-
},
215-
});
216-
} else if (option === 'always' && adjacent) {
217-
report(context, messages.beforeCloseNeedSpace, 'beforeCloseNeedSpace', {
218-
node,
219-
loc: {
220-
start: leftToken.loc.end,
221-
end: closingToken.loc.start,
222-
},
197+
loc: leftToken.loc.end,
223198
fix(fixer) {
224-
return fixer.insertTextBefore(closingToken, ' ');
199+
return fixer.insertTextBefore(closingToken, '\n');
225200
},
226201
});
227202
}
228203
}
204+
205+
if (leftToken.loc.start.line !== closingToken.loc.start.line) {
206+
return;
207+
}
208+
209+
const adjacent = !sourceCode.isSpaceBetweenTokens(leftToken, closingToken);
210+
211+
if (option === 'never' && !adjacent) {
212+
report(context, messages.beforeCloseNoSpace, 'beforeCloseNoSpace', {
213+
node,
214+
loc: {
215+
start: leftToken.loc.end,
216+
end: closingToken.loc.start,
217+
},
218+
fix(fixer) {
219+
return fixer.removeRange([leftToken.range[1], closingToken.range[0]]);
220+
},
221+
});
222+
} else if (option === 'always' && adjacent) {
223+
report(context, messages.beforeCloseNeedSpace, 'beforeCloseNeedSpace', {
224+
node,
225+
loc: {
226+
start: leftToken.loc.end,
227+
end: closingToken.loc.start,
228+
},
229+
fix(fixer) {
230+
return fixer.insertTextBefore(closingToken, ' ');
231+
},
232+
});
233+
} else if (option === 'proportional-always' && node.type === 'JSXOpeningElement' && adjacent !== (node.loc.start.line === node.loc.end.line)) {
234+
report(context, messages.beforeCloseNeedSpace, 'beforeCloseNeedSpace', {
235+
node,
236+
loc: {
237+
start: leftToken.loc.end,
238+
end: closingToken.loc.start,
239+
},
240+
fix(fixer) {
241+
return fixer.insertTextBefore(closingToken, ' ');
242+
},
243+
});
244+
}
229245
}
230246

231247
// ------------------------------------------------------------------------------
@@ -259,13 +275,13 @@ module.exports = {
259275
enum: ['always', 'never', 'allow'],
260276
},
261277
beforeSelfClosing: {
262-
enum: ['always', 'multiline-always', 'never', 'allow'],
278+
enum: ['always', 'proportional-always', 'never', 'allow'],
263279
},
264280
afterOpening: {
265281
enum: ['always', 'allow-multiline', 'never', 'allow'],
266282
},
267283
beforeClosing: {
268-
enum: ['always', 'multiline-always', 'never', 'allow'],
284+
enum: ['always', 'proportional-always', 'never', 'allow'],
269285
},
270286
},
271287
default: optionDefaults,

lib/util/getTokenBeforeClosingBracket.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*/
88
function getTokenBeforeClosingBracket(node) {
99
const attributes = node.attributes;
10-
if (attributes.length === 0) {
10+
if (!attributes || attributes.length === 0) {
1111
return node.name;
1212
}
1313
return attributes[attributes.length - 1];

tests/lib/rules/jsx-tag-spacing.js

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -114,21 +114,13 @@ ruleTester.run('jsx-tag-spacing', rule, {
114114
code: '<App/>',
115115
options: beforeSelfClosingOptions('never'),
116116
},
117-
{
118-
code: '<App/>',
119-
options: beforeSelfClosingOptions('multiline-always'),
120-
},
121117
{
122118
code: '<App />',
123-
options: beforeSelfClosingOptions('multiline-always'),
124-
},
125-
{
126-
code: '<App foo/>',
127-
options: beforeSelfClosingOptions('multiline-always'),
119+
options: beforeSelfClosingOptions('proportional-always'),
128120
},
129121
{
130122
code: '<App foo />',
131-
options: beforeSelfClosingOptions('multiline-always'),
123+
options: beforeSelfClosingOptions('proportional-always'),
132124
},
133125
{
134126
code: `
@@ -139,23 +131,23 @@ ruleTester.run('jsx-tag-spacing', rule, {
139131
hello
140132
</App>
141133
`,
142-
options: beforeClosingOptions('multiline-always'),
134+
options: beforeClosingOptions('proportional-always'),
143135
},
144136
{
145137
code: `
146138
<App foo={bar}>
147139
hello
148140
</App>
149141
`,
150-
options: beforeClosingOptions('multiline-always'),
142+
options: beforeClosingOptions('proportional-always'),
151143
},
152144
{
153145
code: `
154146
<App
155147
foo={bar}
156148
/>
157149
`,
158-
options: beforeSelfClosingOptions('multiline-always'),
150+
options: beforeSelfClosingOptions('proportional-always'),
159151
},
160152
{
161153
code: '<App foo/>',
@@ -345,6 +337,18 @@ ruleTester.run('jsx-tag-spacing', rule, {
345337
options: beforeSelfClosingOptions('never'),
346338
errors: [{ messageId: 'beforeSelfCloseNoSpace' }],
347339
},
340+
{
341+
code: '<App/>',
342+
output: '<App />',
343+
options: beforeSelfClosingOptions('proportional-always'),
344+
errors: [{ messageId: 'beforeSelfCloseNeedSpace' }],
345+
},
346+
{
347+
code: '<App foo/>',
348+
output: '<App foo />',
349+
options: beforeSelfClosingOptions('proportional-always'),
350+
errors: [{ messageId: 'beforeSelfCloseNeedSpace' }],
351+
},
348352
{
349353
code: `
350354
<App
@@ -353,7 +357,7 @@ ruleTester.run('jsx-tag-spacing', rule, {
353357
<App
354358
foo={bar}
355359
/>`,
356-
options: beforeSelfClosingOptions('multiline-always'),
360+
options: beforeSelfClosingOptions('proportional-always'),
357361
errors: [{ messageId: 'beforeSelfCloseNeedNewline' }],
358362
},
359363
{
@@ -364,7 +368,7 @@ ruleTester.run('jsx-tag-spacing', rule, {
364368
<App
365369
foo={bar}${' '}
366370
/>`,
367-
options: beforeSelfClosingOptions('multiline-always'),
371+
options: beforeSelfClosingOptions('proportional-always'),
368372
errors: [{ messageId: 'beforeSelfCloseNeedNewline' }],
369373
},
370374
{
@@ -383,7 +387,7 @@ ruleTester.run('jsx-tag-spacing', rule, {
383387
hello
384388
</App>
385389
`,
386-
options: beforeClosingOptions('multiline-always'),
390+
options: beforeClosingOptions('proportional-always'),
387391
errors: [{ messageId: 'beforeCloseNeedNewline' }],
388392
},
389393
{
@@ -400,7 +404,7 @@ ruleTester.run('jsx-tag-spacing', rule, {
400404
hello
401405
</App>
402406
`,
403-
options: beforeClosingOptions('multiline-always'),
407+
options: beforeClosingOptions('proportional-always'),
404408
errors: [{ messageId: 'beforeCloseNeedNewline' }],
405409
},
406410
{

0 commit comments

Comments
 (0)