Skip to content

Commit 6164f00

Browse files
coliffclaude
andcommitted
fix(title-require): allow comments inside non-empty <title>
- Check all text nodes inside <title> instead of only the last event, so titles mixing text with comments (e.g. Apache SSI directives) are not reported as empty - Remove the @ts-expect-error workaround for event.lastEvent - Add tests for comment-only and text-with-comment titles - Update rule docs with comment examples Fixes #1916 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent dc6e3cd commit 6164f00

4 files changed

Lines changed: 59 additions & 12 deletions

File tree

‎dist/core/rules/title-require.js‎

Lines changed: 14 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎src/core/rules/title-require.ts‎

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Block, Listener } from '../htmlparser'
1+
import { Listener } from '../htmlparser'
22
import { Rule } from '../types'
33

44
export default {
@@ -7,26 +7,33 @@ export default {
77
init(parser, reporter) {
88
let headBegin = false
99
let hasTitle = false
10+
let inTitle = false
11+
let titleHasText = false
1012

1113
const onTagStart: Listener = (event) => {
1214
const tagName = event.tagName.toLowerCase()
1315
if (tagName === 'head') {
1416
headBegin = true
1517
} else if (tagName === 'title' && headBegin) {
1618
hasTitle = true
19+
inTitle = true
20+
titleHasText = false
21+
}
22+
}
23+
24+
// Any non-whitespace text inside <title> counts, so content mixed with
25+
// comments (e.g. Apache SSI directives) is not reported as empty.
26+
const onText: Listener = (event) => {
27+
if (inTitle && /\S/.test(event.raw)) {
28+
titleHasText = true
1729
}
1830
}
1931

2032
const onTagEnd: Listener = (event) => {
2133
const tagName = event.tagName.toLowerCase()
2234
if (hasTitle && tagName === 'title') {
23-
// TODO: fix this error
24-
// @ts-expect-error
25-
const lastEvent: Block = event.lastEvent
26-
if (
27-
lastEvent.type !== 'text' ||
28-
(lastEvent.type === 'text' && /^\s*$/.test(lastEvent.raw) === true)
29-
) {
35+
inTitle = false
36+
if (!titleHasText) {
3037
reporter.error(
3138
'<title></title> must not be empty.',
3239
event.line,
@@ -48,10 +55,12 @@ export default {
4855

4956
parser.removeListener('tagstart', onTagStart)
5057
parser.removeListener('tagend', onTagEnd)
58+
parser.removeListener('text', onText)
5159
}
5260
}
5361

5462
parser.addListener('tagstart', onTagStart)
5563
parser.addListener('tagend', onTagEnd)
64+
parser.addListener('text', onText)
5665
},
5766
} as Rule

‎test/rules/title-require.spec.js‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,30 @@ describe(`Rules: ${ruleId}`, () => {
4141
messages = HTMLHint.verify(code, ruleOptions)
4242
expect(messages.length).toBe(1)
4343
})
44+
45+
it('<title> containing only a comment should result in an error', () => {
46+
const code =
47+
'<html><head><title><!-- comment --></title></head><body></body></html>'
48+
const messages = HTMLHint.verify(code, ruleOptions)
49+
expect(messages.length).toBe(1)
50+
})
51+
52+
it('<title> with text and comments should not result in an error', () => {
53+
let code =
54+
'<html><head><title>test<!-- comment --></title></head><body></body></html>'
55+
let messages = HTMLHint.verify(code, ruleOptions)
56+
expect(messages.length).toBe(0)
57+
58+
code = `<html><head><title>
59+
<!--#if expr="\${REDIRECT_STATUS} = 400"-->
60+
Page Name: Bad Request
61+
<!--#elif expr="\${REDIRECT_STATUS} = 404"-->
62+
Page Name: Resource Not Found
63+
<!--#else-->
64+
Page Name: Error <!--#echo var="REDIRECT_STATUS"-->
65+
<!--#endif-->
66+
</title></head><body></body></html>`
67+
messages = HTMLHint.verify(code, ruleOptions)
68+
expect(messages.length).toBe(0)
69+
})
4470
})

‎website/src/content/docs/rules/title-require.mdx‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,15 @@ Level: <Badge text="Error" variant="danger" />
2222

2323
```html
2424
<html><head><title>test</title></head></html>
25+
<html><head><title>test <!-- comment --></title></head></html>
2526
```
2627

2728
### The following pattern is considered a rule violation:
2829

2930
```html
3031
<html><head></head></html>
3132
<html><head><title></title></head></html>
33+
<html><head><title><!-- comment --></title></head></html>
3234
<html><title></title><head></head></html>
3335
```
3436

0 commit comments

Comments
 (0)