Skip to content

Commit 591c7af

Browse files
mussinbenarbiaMussin Benarbia
andauthored
Add selfClosingTag option to vue/html-closing-bracket-newline (#2346)
Co-authored-by: Mussin Benarbia <[email protected]>
1 parent 0ac61d9 commit 591c7af

File tree

3 files changed

+230
-12
lines changed

3 files changed

+230
-12
lines changed

docs/rules/html-closing-bracket-newline.md

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ title: vue/html-closing-bracket-newline
55
description: require or disallow a line break before tag's closing brackets
66
since: v4.1.0
77
---
8+
89
# vue/html-closing-bracket-newline
910

1011
> require or disallow a line break before tag's closing brackets
@@ -58,19 +59,31 @@ This rule aims to warn the right angle brackets which are at the location other
5859

5960
```json
6061
{
61-
"vue/html-closing-bracket-newline": ["error", {
62-
"singleline": "never",
63-
"multiline": "always"
64-
}]
62+
"vue/html-closing-bracket-newline": [
63+
"error",
64+
{
65+
"singleline": "never",
66+
"multiline": "always",
67+
"selfClosingTag": {
68+
"singleline": "never",
69+
"multiline": "always"
70+
}
71+
}
72+
]
6573
}
6674
```
6775

68-
- `singleline` ... the configuration for single-line elements. It's a single-line element if the element does not have attributes or the last attribute is on the same line as the opening bracket.
69-
- `"never"` (default) ... disallow line breaks before the closing bracket.
70-
- `"always"` ... require one line break before the closing bracket.
71-
- `multiline` ... the configuration for multiline elements. It's a multiline element if the last attribute is not on the same line of the opening bracket.
72-
- `"never"` ... disallow line breaks before the closing bracket.
73-
- `"always"` (default) ... require one line break before the closing bracket.
76+
- `singleline` (`"never"` by default) ... the configuration for single-line elements. It's a single-line element if the element does not have attributes or the last attribute is on the same line as the opening bracket.
77+
- `multiline` (`"always"` by default) ... the configuration for multiline elements. It's a multiline element if the last attribute is not on the same line of the opening bracket.
78+
- `selfClosingTag.singleline` ... the configuration for single-line self closing elements.
79+
- `selfClosingTag.multiline` ... the configuration for multiline self closing elements.
80+
81+
Every option can be set to one of the following values:
82+
83+
- `"always"` ... require one line break before the closing bracket.
84+
- `"never"` ... disallow line breaks before the closing bracket.
85+
86+
If `selfClosingTag` is not specified, the `singleline` and `multiline` options are inherited for self-closing tags.
7487

7588
Plus, you can use [`vue/html-indent`](./html-indent.md) rule to enforce indent-level of the closing brackets.
7689

@@ -95,6 +108,25 @@ Plus, you can use [`vue/html-indent`](./html-indent.md) rule to enforce indent-l
95108

96109
</eslint-code-block>
97110

111+
### `"selfClosingTag": { "multiline": "always" }`
112+
113+
<eslint-code-block fix :rules="{'vue/html-closing-bracket-newline': ['error', { 'selfClosingTag': {'multiline': 'always'} }]}">
114+
115+
```vue
116+
<template>
117+
<!-- ✓ GOOD -->
118+
<MyComponent
119+
:foo="foo"
120+
/>
121+
122+
<!-- ✗ BAD -->
123+
<MyComponent
124+
:foo="foo" />
125+
</template>
126+
```
127+
128+
</eslint-code-block>
129+
98130
## :rocket: Version
99131

100132
This rule was introduced in eslint-plugin-vue v4.1.0

lib/rules/html-closing-bracket-newline.js

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,45 @@ function getPhrase(lineBreaks) {
2424
}
2525
}
2626

27+
/**
28+
* @typedef LineBreakBehavior
29+
* @type {('always'|'never')}
30+
*/
31+
32+
/**
33+
* @typedef LineType
34+
* @type {('singleline'|'multiline')}
35+
*/
36+
37+
/**
38+
* @typedef RuleOptions
39+
* @type {object}
40+
* @property {LineBreakBehavior} singleline - The behavior for single line tags.
41+
* @property {LineBreakBehavior} multiline - The behavior for multiline tags.
42+
* @property {object} selfClosingTag
43+
* @property {LineBreakBehavior} selfClosingTag.singleline - The behavior for single line self closing tags.
44+
* @property {LineBreakBehavior} selfClosingTag.multiline - The behavior for multiline self closing tags.
45+
*/
46+
47+
/**
48+
* @param {VStartTag | VEndTag} node - The node representing a start or end tag.
49+
* @param {RuleOptions} options - The options for line breaks.
50+
* @param {LineType} type - The type of line break.
51+
* @returns {number} - The expected line breaks.
52+
*/
53+
function getExpectedLineBreaks(node, options, type) {
54+
const isSelfClosingTag = node.type === 'VStartTag' && node.selfClosing
55+
if (
56+
isSelfClosingTag &&
57+
options.selfClosingTag &&
58+
options.selfClosingTag[type]
59+
) {
60+
return options.selfClosingTag[type] === 'always' ? 1 : 0
61+
}
62+
63+
return options[type] === 'always' ? 1 : 0
64+
}
65+
2766
module.exports = {
2867
meta: {
2968
type: 'layout',
@@ -39,7 +78,16 @@ module.exports = {
3978
type: 'object',
4079
properties: {
4180
singleline: { enum: ['always', 'never'] },
42-
multiline: { enum: ['always', 'never'] }
81+
multiline: { enum: ['always', 'never'] },
82+
selfClosingTag: {
83+
type: 'object',
84+
properties: {
85+
singleline: { enum: ['always', 'never'] },
86+
multiline: { enum: ['always', 'never'] }
87+
},
88+
additionalProperties: false,
89+
minProperties: 1
90+
}
4391
},
4492
additionalProperties: false
4593
}
@@ -80,7 +128,9 @@ module.exports = {
80128
node.loc.start.line === prevToken.loc.end.line
81129
? 'singleline'
82130
: 'multiline'
83-
const expectedLineBreaks = options[type] === 'always' ? 1 : 0
131+
132+
const expectedLineBreaks = getExpectedLineBreaks(node, options, type)
133+
84134
const actualLineBreaks =
85135
closingBracketToken.loc.start.line - prevToken.loc.end.line
86136

tests/lib/rules/html-closing-bracket-newline.js

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,42 @@ tester.run('html-closing-bracket-newline', rule, {
116116
}
117117
]
118118
},
119+
{
120+
code: `
121+
<template>
122+
<MyComp
123+
:foo="foo"
124+
/>
125+
<MyComp :foo="foo" />
126+
</template>
127+
`,
128+
options: [
129+
{
130+
selfClosingTag: {
131+
singleline: 'never',
132+
multiline: 'always'
133+
}
134+
}
135+
]
136+
},
137+
{
138+
code: `
139+
<template>
140+
<MyComp :foo="foo"
141+
/>
142+
<MyComp
143+
:foo="foo" />
144+
</template>
145+
`,
146+
options: [
147+
{
148+
selfClosingTag: {
149+
singleline: 'always',
150+
multiline: 'never'
151+
}
152+
}
153+
]
154+
},
119155

120156
// Ignore if no closing brackets
121157
`
@@ -479,6 +515,106 @@ tester.run('html-closing-bracket-newline', rule, {
479515
endColumn: 23
480516
}
481517
]
518+
},
519+
{
520+
code: `
521+
<template>
522+
<MyComp
523+
/>
524+
</template>
525+
`,
526+
output: `
527+
<template>
528+
<MyComp/>
529+
</template>
530+
`,
531+
options: [
532+
{
533+
selfClosingTag: {
534+
singleline: 'never',
535+
multiline: 'always'
536+
}
537+
}
538+
],
539+
errors: [
540+
'Expected no line breaks before closing bracket, but 1 line break found.'
541+
]
542+
},
543+
{
544+
code: `
545+
<template>
546+
<MyComp
547+
:foo="foo"/>
548+
</template>
549+
`,
550+
output: `
551+
<template>
552+
<MyComp
553+
:foo="foo"
554+
/>
555+
</template>
556+
`,
557+
options: [
558+
{
559+
selfClosingTag: {
560+
singleline: 'never',
561+
multiline: 'always'
562+
}
563+
}
564+
],
565+
errors: [
566+
'Expected 1 line break before closing bracket, but no line breaks found.'
567+
]
568+
},
569+
{
570+
code: `
571+
<template>
572+
<MyComp :foo="foo"/>
573+
</template>
574+
`,
575+
output: `
576+
<template>
577+
<MyComp :foo="foo"
578+
/>
579+
</template>
580+
`,
581+
options: [
582+
{
583+
selfClosingTag: {
584+
singleline: 'always',
585+
multiline: 'never'
586+
}
587+
}
588+
],
589+
errors: [
590+
'Expected 1 line break before closing bracket, but no line breaks found.'
591+
]
592+
},
593+
{
594+
code: `
595+
<template>
596+
<MyComp
597+
:foo="foo"
598+
/>
599+
</template>
600+
`,
601+
output: `
602+
<template>
603+
<MyComp
604+
:foo="foo"/>
605+
</template>
606+
`,
607+
options: [
608+
{
609+
selfClosingTag: {
610+
singleline: 'always',
611+
multiline: 'never'
612+
}
613+
}
614+
],
615+
errors: [
616+
'Expected no line breaks before closing bracket, but 1 line break found.'
617+
]
482618
}
483619
]
484620
})

0 commit comments

Comments
 (0)