check-templates: Be stricter about singleton tags.

We now forbid tags of the form `<foo ... />` in most
places, and we also forbid it even for several void
tags.

We make exceptions for tags that are already formatted
in two different ways in our codebase.  This is mostly
svg tags, plus these common cases:

    - br
    - hr
    - img
    - input

It would be nice to lock down a convention for these,
even though the HTML specification is unopinionated
on these.  We'll probably want to stay flexible for
svg tags, since they are sometimes copy/pasted from
other sources (although it's probably rare enough for
them that we can tolerate just doing minor edits as
needed).
This commit is contained in:
Steve Howell 2020-04-18 09:38:31 +00:00
parent 28f2a6950e
commit 951514dd7d
4 changed files with 24 additions and 9 deletions

View File

@ -301,7 +301,21 @@ def validate(fn: Optional[str] = None, text: Optional[str] = None, check_indent:
def is_special_html_tag(s: str, tag: str) -> bool: def is_special_html_tag(s: str, tag: str) -> bool:
return tag in ['link', 'meta', '!DOCTYPE'] return tag in ['link', 'meta', '!DOCTYPE']
OPTIONAL_CLOSING_TAGS = [
'br',
'circle',
'hr',
'img',
'input',
'path',
'polygon',
]
def is_self_closing_html_tag(s: Text, tag: Text) -> bool: def is_self_closing_html_tag(s: Text, tag: Text) -> bool:
if s.endswith('/>'):
if tag in OPTIONAL_CLOSING_TAGS:
return True
raise TokenizationException('Singleton tag not allowed', tag)
self_closing_tag = tag in [ self_closing_tag = tag in [
'area', 'area',
'base', 'base',
@ -316,8 +330,9 @@ def is_self_closing_html_tag(s: Text, tag: Text) -> bool:
'track', 'track',
'wbr', 'wbr',
] ]
singleton_tag = s.endswith('/>') if self_closing_tag:
return self_closing_tag or singleton_tag return True
return False
def is_django_block_tag(tag: str) -> bool: def is_django_block_tag(tag: str) -> bool:
return tag in [ return tag in [

View File

@ -41,7 +41,7 @@ class TestHtmlBranches(unittest.TestCase):
<link rel="stylesheet" href="style.css" /> <link rel="stylesheet" href="style.css" />
</head> </head>
<body> <body>
<p>Hello<br />world!</p> <p>Hello<br>world!</p>
<p>Goodbye<!-- test -->world!</p> <p>Goodbye<!-- test -->world!</p>
</body> </body>
</html> </html>
@ -83,7 +83,7 @@ class TestHtmlBranches(unittest.TestCase):
<link rel="stylesheet" href="style.css" /> <link rel="stylesheet" href="style.css" />
</head> </head>
<body> <body>
<p>Hello<br />world!</p> <p>Hello<br>world!</p>
<p>Goodbye<!-- test -->world!</p> <p>Goodbye<!-- test -->world!</p>
</body> </body>
</html> </html>

View File

@ -20,7 +20,7 @@ BAD_HTML = """
<link rel="stylesheet" href="style.css" /> <link rel="stylesheet" href="style.css" />
</head> </head>
<body> <body>
<div><p>Hello<br />world!</p></div> <div><p>Hello<br>world!</p></div>
<p>Goodbye<!-- test -->world!</p> <p>Goodbye<!-- test -->world!</p>
<table> <table>
<tr> <tr>
@ -52,7 +52,7 @@ GOOD_HTML = """
<link rel="stylesheet" href="style.css" /> <link rel="stylesheet" href="style.css" />
</head> </head>
<body> <body>
<div><p>Hello<br />world!</p></div> <div><p>Hello<br>world!</p></div>
<p>Goodbye<!-- test -->world!</p> <p>Goodbye<!-- test -->world!</p>
<table> <table>
<tr> <tr>
@ -338,7 +338,7 @@ BAD_HTML13 = """
{{#if this.is_realm_emoji}} {{#if this.is_realm_emoji}}
<img src="{{this.url}}" class="emoji" /> <img src="{{this.url}}" class="emoji" />
{{else}} {{else}}
<div/> <br>
{{/if}} {{/if}}
{{/if}} {{/if}}
<div>{{this.count}}</div> <div>{{this.count}}</div>
@ -353,7 +353,7 @@ GOOD_HTML13 = """
{{#if this.is_realm_emoji}} {{#if this.is_realm_emoji}}
<img src="{{this.url}}" class="emoji" /> <img src="{{this.url}}" class="emoji" />
{{else}} {{else}}
<div/> <br>
{{/if}} {{/if}}
{{/if}} {{/if}}
<div>{{this.count}}</div> <div>{{this.count}}</div>

View File

@ -249,7 +249,7 @@ class ParserTest(unittest.TestCase):
self.assertEqual(token.kind, 'html_start') self.assertEqual(token.kind, 'html_start')
self.assertEqual(token.tag, 'a') self.assertEqual(token.tag, 'a')
tag = '<br />bla' tag = '<br>bla'
token = tokenize(tag)[0] token = tokenize(tag)[0]
self.assertEqual(token.kind, 'html_singleton') self.assertEqual(token.kind, 'html_singleton')
self.assertEqual(token.tag, 'br') self.assertEqual(token.tag, 'br')