Skip to content

Commit c660368

Browse files
committed
Enable vue/html-closing-bracket-* for top-level tags
1 parent 9344af8 commit c660368

5 files changed

+406
-85
lines changed

lib/rules/block-tag-newline.js

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -347,13 +347,6 @@ module.exports = {
347347

348348
const verify = normalizeOptionValue(context.options[0])
349349

350-
/**
351-
* @returns {VElement[]}
352-
*/
353-
function getTopLevelHTMLElements() {
354-
return documentFragment.children.filter(utils.isVElement)
355-
}
356-
357350
return utils.defineTemplateBodyVisitor(
358351
context,
359352
{},
@@ -364,8 +357,10 @@ module.exports = {
364357
return
365358
}
366359

367-
for (const element of getTopLevelHTMLElements()) {
368-
verify(element)
360+
for (const element of documentFragment.children) {
361+
if (utils.isVElement(element)) {
362+
verify(element)
363+
}
369364
}
370365
}
371366
}

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

Lines changed: 73 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ module.exports = {
5656
},
5757
/** @param {RuleContext} context */
5858
create(context) {
59+
const df =
60+
context.parserServices.getDocumentFragment &&
61+
context.parserServices.getDocumentFragment()
62+
if (!df) {
63+
return {}
64+
}
65+
5966
const options = Object.assign(
6067
{},
6168
{
@@ -68,48 +75,76 @@ module.exports = {
6875
context.parserServices.getTemplateBodyTokenStore &&
6976
context.parserServices.getTemplateBodyTokenStore()
7077

71-
return utils.defineTemplateBodyVisitor(context, {
72-
/** @param {VStartTag | VEndTag} node */
73-
'VStartTag, VEndTag'(node) {
74-
const closingBracketToken = template.getLastToken(node)
75-
if (
76-
closingBracketToken.type !== 'HTMLSelfClosingTagClose' &&
77-
closingBracketToken.type !== 'HTMLTagClose'
78-
) {
79-
return
80-
}
78+
/** @param {VStartTag | VEndTag} node */
79+
function verify(node) {
80+
const closingBracketToken = template.getLastToken(node)
81+
if (
82+
closingBracketToken.type !== 'HTMLSelfClosingTagClose' &&
83+
closingBracketToken.type !== 'HTMLTagClose'
84+
) {
85+
return
86+
}
87+
88+
const prevToken = template.getTokenBefore(closingBracketToken)
89+
const type =
90+
node.loc.start.line === prevToken.loc.end.line
91+
? 'singleline'
92+
: 'multiline'
93+
const expectedLineBreaks = options[type] === 'always' ? 1 : 0
94+
const actualLineBreaks =
95+
closingBracketToken.loc.start.line - prevToken.loc.end.line
96+
97+
if (actualLineBreaks !== expectedLineBreaks) {
98+
context.report({
99+
node,
100+
loc: {
101+
start: prevToken.loc.end,
102+
end: closingBracketToken.loc.start
103+
},
104+
message:
105+
'Expected {{expected}} before closing bracket, but {{actual}} found.',
106+
data: {
107+
expected: getPhrase(expectedLineBreaks),
108+
actual: getPhrase(actualLineBreaks)
109+
},
110+
fix(fixer) {
111+
/** @type {Range} */
112+
const range = [prevToken.range[1], closingBracketToken.range[0]]
113+
const text = '\n'.repeat(expectedLineBreaks)
114+
return fixer.replaceTextRange(range, text)
115+
}
116+
})
117+
}
118+
}
119+
120+
const documentFragment = df
81121

82-
const prevToken = template.getTokenBefore(closingBracketToken)
83-
const type =
84-
node.loc.start.line === prevToken.loc.end.line
85-
? 'singleline'
86-
: 'multiline'
87-
const expectedLineBreaks = options[type] === 'always' ? 1 : 0
88-
const actualLineBreaks =
89-
closingBracketToken.loc.start.line - prevToken.loc.end.line
122+
return utils.defineTemplateBodyVisitor(
123+
context,
124+
{
125+
/** @param {VStartTag | VEndTag} node */
126+
'VStartTag, VEndTag': verify
127+
},
128+
{
129+
/** @param {Program} node */
130+
Program(node) {
131+
if (utils.hasInvalidEOF(node)) {
132+
return
133+
}
90134

91-
if (actualLineBreaks !== expectedLineBreaks) {
92-
context.report({
93-
node,
94-
loc: {
95-
start: prevToken.loc.end,
96-
end: closingBracketToken.loc.start
97-
},
98-
message:
99-
'Expected {{expected}} before closing bracket, but {{actual}} found.',
100-
data: {
101-
expected: getPhrase(expectedLineBreaks),
102-
actual: getPhrase(actualLineBreaks)
103-
},
104-
fix(fixer) {
105-
/** @type {Range} */
106-
const range = [prevToken.range[1], closingBracketToken.range[0]]
107-
const text = '\n'.repeat(expectedLineBreaks)
108-
return fixer.replaceTextRange(range, text)
135+
for (const element of documentFragment.children) {
136+
if (!utils.isVElement(element) || element.name === 'template') {
137+
continue
109138
}
110-
})
139+
140+
verify(element.startTag)
141+
142+
if (element.endTag !== null) {
143+
verify(element.endTag)
144+
}
145+
}
111146
}
112147
}
113-
})
148+
)
114149
}
115150
}

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

Lines changed: 72 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -86,52 +86,86 @@ module.exports = {
8686
},
8787
/** @param {RuleContext} context */
8888
create(context) {
89+
const df =
90+
context.parserServices.getDocumentFragment &&
91+
context.parserServices.getDocumentFragment()
92+
if (!df) {
93+
return {}
94+
}
95+
8996
const sourceCode = context.getSourceCode()
9097
const tokens =
9198
context.parserServices.getTemplateBodyTokenStore &&
9299
context.parserServices.getTemplateBodyTokenStore()
93100
const options = parseOptions(context.options[0], tokens)
94101

95-
return utils.defineTemplateBodyVisitor(context, {
96-
/** @param {VStartTag | VEndTag} node */
97-
'VStartTag, VEndTag'(node) {
98-
const type = options.detectType(node)
99-
const lastToken = tokens.getLastToken(node)
100-
const prevToken = tokens.getLastToken(node, 1)
101-
102-
// Skip if EOF exists in the tag or linebreak exists before `>`.
103-
if (
104-
type == null ||
105-
prevToken == null ||
106-
prevToken.loc.end.line !== lastToken.loc.start.line
107-
) {
108-
return
109-
}
102+
/** @param {VStartTag | VEndTag} node */
103+
function verify(node) {
104+
const type = options.detectType(node)
105+
const lastToken = tokens.getLastToken(node)
106+
const prevToken = tokens.getLastToken(node, 1)
107+
108+
// Skip if EOF exists in the tag or linebreak exists before `>`.
109+
if (
110+
type == null ||
111+
prevToken == null ||
112+
prevToken.loc.end.line !== lastToken.loc.start.line
113+
) {
114+
return
115+
}
116+
117+
// Check and report.
118+
const hasSpace = prevToken.range[1] !== lastToken.range[0]
119+
if (type === 'always' && !hasSpace) {
120+
context.report({
121+
node,
122+
loc: lastToken.loc,
123+
message: "Expected a space before '{{bracket}}', but not found.",
124+
data: { bracket: sourceCode.getText(lastToken) },
125+
fix: (fixer) => fixer.insertTextBefore(lastToken, ' ')
126+
})
127+
} else if (type === 'never' && hasSpace) {
128+
context.report({
129+
node,
130+
loc: {
131+
start: prevToken.loc.end,
132+
end: lastToken.loc.end
133+
},
134+
message: "Expected no space before '{{bracket}}', but found.",
135+
data: { bracket: sourceCode.getText(lastToken) },
136+
fix: (fixer) =>
137+
fixer.removeRange([prevToken.range[1], lastToken.range[0]])
138+
})
139+
}
140+
}
141+
142+
const documentFragment = df
143+
144+
return utils.defineTemplateBodyVisitor(
145+
context,
146+
{
147+
'VStartTag, VEndTag': verify
148+
},
149+
{
150+
/** @param {Program} node */
151+
Program(node) {
152+
if (utils.hasInvalidEOF(node)) {
153+
return
154+
}
155+
156+
for (const element of documentFragment.children) {
157+
if (!utils.isVElement(element) || element.name === 'template') {
158+
continue
159+
}
160+
161+
verify(element.startTag)
110162

111-
// Check and report.
112-
const hasSpace = prevToken.range[1] !== lastToken.range[0]
113-
if (type === 'always' && !hasSpace) {
114-
context.report({
115-
node,
116-
loc: lastToken.loc,
117-
message: "Expected a space before '{{bracket}}', but not found.",
118-
data: { bracket: sourceCode.getText(lastToken) },
119-
fix: (fixer) => fixer.insertTextBefore(lastToken, ' ')
120-
})
121-
} else if (type === 'never' && hasSpace) {
122-
context.report({
123-
node,
124-
loc: {
125-
start: prevToken.loc.end,
126-
end: lastToken.loc.end
127-
},
128-
message: "Expected no space before '{{bracket}}', but found.",
129-
data: { bracket: sourceCode.getText(lastToken) },
130-
fix: (fixer) =>
131-
fixer.removeRange([prevToken.range[1], lastToken.range[0]])
132-
})
163+
if (element.endTag !== null) {
164+
verify(element.endTag)
165+
}
166+
}
133167
}
134168
}
135-
})
169+
)
136170
}
137171
}

0 commit comments

Comments
 (0)