Skip to content

Commit b91d2b8

Browse files
authored
Allow html void tags (#73)
* Add instruction for installing husky * Add failing test for void elements * Allow parsing and formatting for unclosed void elements
1 parent f0e51e5 commit b91d2b8

File tree

6 files changed

+50
-3
lines changed

6 files changed

+50
-3
lines changed

Gemfile.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ GEM
2323

2424
PLATFORMS
2525
arm64-darwin-21
26+
arm64-darwin-23
2627
x86_64-darwin-21
2728
x86_64-darwin-22
2829
x86_64-linux

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ puts failures
7979

8080
## Development
8181

82+
Install `husky`:
83+
84+
```sh
85+
npm i -g husky
86+
```
87+
8288
Setup linting:
8389

8490
```sh

lib/syntax_tree/erb/format.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,10 @@ def visit_opening_tag(node)
203203
q.text(" ")
204204
end
205205

206+
# If element is a valid void element, but not currently self-closing
207+
# format to be self-closing
208+
q.text(" /") if node.is_void_element? and node.closing.value == ">"
209+
206210
visit(node.closing)
207211
end
208212
end

lib/syntax_tree/erb/nodes.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,25 @@ def deconstruct_keys(keys)
185185
# potentially contain an opening tag that self-closes, in which case the
186186
# content and closing tag will be nil.
187187
class HtmlNode < Block
188+
# These elements do not require a closing tag
189+
# https://developer.mozilla.org/en-US/docs/Glossary/Void_element
190+
HTML_VOID_ELEMENTS = %w[
191+
area
192+
base
193+
br
194+
col
195+
embed
196+
hr
197+
img
198+
input
199+
link
200+
meta
201+
param
202+
source
203+
track
204+
wbr
205+
]
206+
188207
# The opening tag of an element. It contains the opening character (<),
189208
# the name of the element, any optional attributes, and the closing
190209
# token (either > or />).
@@ -214,6 +233,10 @@ def child_nodes
214233
[opening, name, *attributes, closing]
215234
end
216235

236+
def is_void_element?
237+
HTML_VOID_ELEMENTS.include?(name.value)
238+
end
239+
217240
alias deconstruct child_nodes
218241

219242
def deconstruct_keys(keys)
@@ -253,6 +276,10 @@ def deconstruct_keys(keys)
253276
end
254277
end
255278

279+
def is_void_element?
280+
false
281+
end
282+
256283
def without_new_line
257284
self.class.new(
258285
**deconstruct_keys([]).merge(

lib/syntax_tree/erb/parser.rb

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,11 @@ def parse_html_closing
419419
def parse_html_element
420420
opening = parse_html_opening_tag
421421

422-
if opening.closing.value == ">"
422+
if opening.closing.value == "/>"
423+
HtmlNode.new(opening: opening, location: opening.location)
424+
elsif opening.is_void_element?
425+
HtmlNode.new(opening: opening, location: opening.location)
426+
else
423427
elements = many { parse_any_tag }
424428
closing = maybe { parse_html_closing }
425429

@@ -443,8 +447,6 @@ def parse_html_element
443447
closing: closing,
444448
location: opening.location.to(closing.location)
445449
)
446-
else
447-
HtmlNode.new(opening: opening, location: opening.location)
448450
end
449451
end
450452

test/html_test.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,5 +205,12 @@ def test_self_closing_group
205205

206206
assert_formatting(source, expected)
207207
end
208+
209+
def test_self_closing_for_void_elements
210+
source = "<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\" >"
211+
expected = "<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\" />\n"
212+
213+
assert_formatting(source, expected)
214+
end
208215
end
209216
end

0 commit comments

Comments
 (0)