Skip to content

Commit

Permalink
Add multiline-always option for jsx-tag-spacing
Browse files Browse the repository at this point in the history
- This option enforces that the closingTag or the selfClosingTag is on a
  new line if the entire tag is a multiline tag

Signed-off-by: Sebastian Malton <sebastian@malton.name>
  • Loading branch information
Nokel81 committed Apr 1, 2022
1 parent 5bc571d commit 7440098
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 3 deletions.
2 changes: 1 addition & 1 deletion lib/rules/jsx-max-props-per-line.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ module.exports = {
},
multi: {
type: 'integer',
minimum: 1,
minimum: 0,
},
},
},
Expand Down
30 changes: 28 additions & 2 deletions lib/rules/jsx-tag-spacing.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ const messages = {
closeSlashNeedSpace: 'Whitespace is required between `<` and `/`; write `< /`',
beforeSelfCloseNoSpace: 'A space is forbidden before closing bracket',
beforeSelfCloseNeedSpace: 'A space is required before closing bracket',
beforeSelfCloseNeedNewline: 'A newline is required before closing bracket',
afterOpenNoSpace: 'A space is forbidden after opening bracket',
afterOpenNeedSpace: 'A space is required after opening bracket',
beforeCloseNoSpace: 'A space is forbidden before closing bracket',
beforeCloseNeedSpace: 'Whitespace is required before closing bracket',
beforeCloseNeedNewline: 'A newline is required before closing bracket',
};

// ------------------------------------------------------------------------------
Expand Down Expand Up @@ -99,6 +101,18 @@ function validateBeforeSelfClosing(context, node, option) {
const leftToken = getTokenBeforeClosingBracket(node);
const closingSlash = sourceCode.getTokenAfter(leftToken);

if (node.loc.start.line !== node.loc.end.line && option === 'multiline-always') {
if (leftToken.loc.end.line === closingSlash.loc.start.line) {
report(context, messages.beforeSelfCloseNeedNewline, 'beforeSelfCloseNeedNewline', {
node,
loc: leftToken.loc.end,
fix(fixer) {
return fixer.insertTextBefore(closingSlash, '\n');
},
});
}
}

if (leftToken.loc.end.line !== closingSlash.loc.start.line) {
return;
}
Expand Down Expand Up @@ -170,6 +184,18 @@ function validateBeforeClosing(context, node, option) {
const closingToken = lastTokens[1];
const leftToken = lastTokens[0];

if (node.loc.start.line !== node.loc.end.line && option === 'multiline-always') {
if (leftToken.loc.end.line === closingToken.loc.start.line) {
report(context, messages.beforeCloseNeedNewline, 'beforeCloseNeedNewline', {
node,
loc: leftToken.loc.end,
fix(fixer) {
return fixer.insertTextBefore(closingToken, '\n');
},
});
}
}

if (leftToken.loc.start.line !== closingToken.loc.start.line) {
return;
}
Expand Down Expand Up @@ -233,13 +259,13 @@ module.exports = {
enum: ['always', 'never', 'allow'],
},
beforeSelfClosing: {
enum: ['always', 'never', 'allow'],
enum: ['always', 'multiline-always', 'never', 'allow'],
},
afterOpening: {
enum: ['always', 'allow-multiline', 'never', 'allow'],
},
beforeClosing: {
enum: ['always', 'never', 'allow'],
enum: ['always', 'multiline-always', 'never', 'allow'],
},
},
default: optionDefaults,
Expand Down
97 changes: 97 additions & 0 deletions tests/lib/rules/jsx-tag-spacing.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,49 @@ ruleTester.run('jsx-tag-spacing', rule, {
code: '<App/>',
options: beforeSelfClosingOptions('never'),
},
{
code: '<App/>',
options: beforeSelfClosingOptions('multiline-always'),
},
{
code: '<App />',
options: beforeSelfClosingOptions('multiline-always'),
},
{
code: '<App foo/>',
options: beforeSelfClosingOptions('multiline-always'),
},
{
code: '<App foo />',
options: beforeSelfClosingOptions('multiline-always'),
},
{
code: `
<App
foo={bar}
blat
>
hello
</App>
`,
options: beforeClosingOptions('multiline-always'),
},
{
code: `
<App foo={bar}>
hello
</App>
`,
options: beforeClosingOptions('multiline-always'),
},
{
code: `
<App
foo={bar}
/>
`,
options: beforeSelfClosingOptions('multiline-always'),
},
{
code: '<App foo/>',
options: beforeSelfClosingOptions('never'),
Expand Down Expand Up @@ -302,6 +345,60 @@ ruleTester.run('jsx-tag-spacing', rule, {
options: beforeSelfClosingOptions('never'),
errors: [{ messageId: 'beforeSelfCloseNoSpace' }],
},
{
code: `
<App
foo={bar}/>`,
output: `
<App
foo={bar}\n/>`,
options: beforeSelfClosingOptions('multiline-always'),
errors: [{ messageId: 'beforeSelfCloseNeedNewline' }],
},
{
code: `
<App
foo={bar} />`,
output: `
<App
foo={bar} \n/>`,
options: beforeSelfClosingOptions('multiline-always'),
errors: [{ messageId: 'beforeSelfCloseNeedNewline' }],
},
{
code: `
<App
foo={bar}
blat >
hello
</App>
`,
output: `
<App
foo={bar}
blat \n>
hello
</App>
`,
options: beforeClosingOptions('multiline-always'),
errors: [{ messageId: 'beforeCloseNeedNewline' }],
},
{
code: `
<App
foo={bar}>
hello
</App>
`,
output: `
<App
foo={bar}\n>
hello
</App>
`,
options: beforeClosingOptions('multiline-always'),
errors: [{ messageId: 'beforeCloseNeedNewline' }],
},
{
code: '<App {...props} />',
output: '<App {...props}/>',
Expand Down

0 comments on commit 7440098

Please sign in to comment.