Skip to content

Commit

Permalink
generate void elements, instead of <br></br>, fixes #12
Browse files Browse the repository at this point in the history
  • Loading branch information
a-h committed Jun 6, 2021
1 parent 76a6d6b commit 82c33cf
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 61 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
cmd/example/*.go
dist
cmd/templ/templ
cmd/lspcmd/*log.txt
cmd/templ/lspcmd/*log.txt
.DS_Store
162 changes: 104 additions & 58 deletions generator/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -393,9 +393,47 @@ func (g *generator) writeErrorHandler(indentLevel int) (err error) {
}

func (g *generator) writeElement(indentLevel int, n templ.Element) error {
var r templ.Range
var err error
// Attributes.
if n.IsVoidElement() {
return g.writeVoidElement(indentLevel, n)
}
return g.writeStandardElement(indentLevel, n)
}

func (g *generator) writeVoidElement(indentLevel int, n templ.Element) (err error) {
if len(n.Children) > 0 {
return fmt.Errorf("writeVoidElement: void element %q must not have child elements", n.Name)
}
if len(n.Attributes) == 0 {
// <div/>
if _, err = g.w.WriteIndent(indentLevel, fmt.Sprintf(`_, err = io.WriteString(w, "<%s/>")`+"\n", html.EscapeString(n.Name))); err != nil {
return err
}
if err = g.writeErrorHandler(indentLevel); err != nil {
return err
}
} else {
// <div
if _, err = g.w.WriteIndent(indentLevel, fmt.Sprintf(`_, err = io.WriteString(w, "<%s")`+"\n", html.EscapeString(n.Name))); err != nil {
return err
}
if err = g.writeErrorHandler(indentLevel); err != nil {
return err
}
if err = g.writeElementAttributes(indentLevel, n); err != nil {
return err
}
// />
if _, err = g.w.WriteIndent(indentLevel, `_, err = io.WriteString(w, "/>")`+"\n"); err != nil {
return err
}
if err = g.writeErrorHandler(indentLevel); err != nil {
return err
}
}
return err
}

func (g *generator) writeStandardElement(indentLevel int, n templ.Element) (err error) {
if len(n.Attributes) == 0 {
// <div>
if _, err = g.w.WriteIndent(indentLevel, fmt.Sprintf(`_, err = io.WriteString(w, "<%s>")`+"\n", html.EscapeString(n.Name))); err != nil {
Expand All @@ -412,60 +450,8 @@ func (g *generator) writeElement(indentLevel int, n templ.Element) error {
if err = g.writeErrorHandler(indentLevel); err != nil {
return err
}
for i := 0; i < len(n.Attributes); i++ {
switch attr := n.Attributes[i].(type) {
case templ.ConstantAttribute:
name := html.EscapeString(attr.Name)
value := html.EscapeString(attr.Value)
if _, err = g.w.WriteIndent(indentLevel, fmt.Sprintf(`_, err = io.WriteString(w, " %s=\"%s\"")`+"\n", name, value)); err != nil {
return err
}
if err = g.writeErrorHandler(indentLevel); err != nil {
return err
}
case templ.ExpressionAttribute:
name := html.EscapeString(attr.Name)
// Name
if _, err = g.w.WriteIndent(indentLevel, fmt.Sprintf(`_, err = io.WriteString(w, " %s=")`+"\n", name)); err != nil {
return err
}
if err = g.writeErrorHandler(indentLevel); err != nil {
return err
}
// Value.
// Open quote.
if _, err = g.w.WriteIndent(indentLevel, `_, err = io.WriteString(w, "\"")`+"\n"); err != nil {
return err
}
if err = g.writeErrorHandler(indentLevel); err != nil {
return err
}
// io.WriteString(w, templ.EscapeString(
if _, err = g.w.WriteIndent(indentLevel, "_, err = io.WriteString(w, templ.EscapeString("); err != nil {
return err
}
// p.Name()
if r, err = g.w.Write(attr.Expression.Value); err != nil {
return err
}
g.sourceMap.Add(attr.Expression, r)
// ))
if _, err = g.w.Write("))\n"); err != nil {
return err
}
if err = g.writeErrorHandler(indentLevel); err != nil {
return err
}
// Close quote.
if _, err = g.w.WriteIndent(indentLevel, `_, err = io.WriteString(w, "\"")`+"\n"); err != nil {
return err
}
if err = g.writeErrorHandler(indentLevel); err != nil {
return err
}
default:
return fmt.Errorf("unknown attribute type %s", reflect.TypeOf(n.Attributes[i]))
}
if err = g.writeElementAttributes(indentLevel, n); err != nil {
return err
}
// >
if _, err = g.w.WriteIndent(indentLevel, `_, err = io.WriteString(w, ">")`+"\n"); err != nil {
Expand All @@ -484,7 +470,67 @@ func (g *generator) writeElement(indentLevel int, n templ.Element) error {
if err = g.writeErrorHandler(indentLevel); err != nil {
return err
}
return nil
return err
}

func (g *generator) writeElementAttributes(indentLevel int, n templ.Element) (err error) {
var r templ.Range
for i := 0; i < len(n.Attributes); i++ {
switch attr := n.Attributes[i].(type) {
case templ.ConstantAttribute:
name := html.EscapeString(attr.Name)
value := html.EscapeString(attr.Value)
if _, err = g.w.WriteIndent(indentLevel, fmt.Sprintf(`_, err = io.WriteString(w, " %s=\"%s\"")`+"\n", name, value)); err != nil {
return err
}
if err = g.writeErrorHandler(indentLevel); err != nil {
return err
}
case templ.ExpressionAttribute:
name := html.EscapeString(attr.Name)
// Name
if _, err = g.w.WriteIndent(indentLevel, fmt.Sprintf(`_, err = io.WriteString(w, " %s=")`+"\n", name)); err != nil {
return err
}
if err = g.writeErrorHandler(indentLevel); err != nil {
return err
}
// Value.
// Open quote.
if _, err = g.w.WriteIndent(indentLevel, `_, err = io.WriteString(w, "\"")`+"\n"); err != nil {
return err
}
if err = g.writeErrorHandler(indentLevel); err != nil {
return err
}
// io.WriteString(w, templ.EscapeString(
if _, err = g.w.WriteIndent(indentLevel, "_, err = io.WriteString(w, templ.EscapeString("); err != nil {
return err
}
// p.Name()
if r, err = g.w.Write(attr.Expression.Value); err != nil {
return err
}
g.sourceMap.Add(attr.Expression, r)
// ))
if _, err = g.w.Write("))\n"); err != nil {
return err
}
if err = g.writeErrorHandler(indentLevel); err != nil {
return err
}
// Close quote.
if _, err = g.w.WriteIndent(indentLevel, `_, err = io.WriteString(w, "\"")`+"\n"); err != nil {
return err
}
if err = g.writeErrorHandler(indentLevel); err != nil {
return err
}
default:
return fmt.Errorf("unknown attribute type %s", reflect.TypeOf(n.Attributes[i]))
}
}
return err
}

func (g *generator) writeStringExpression(indentLevel int, e templ.Expression) error {
Expand Down
22 changes: 22 additions & 0 deletions generator/test-void/render_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package testvoid

import (
"context"
"strings"
"testing"

"github.com/google/go-cmp/cmp"
)

const expected = `<br/><img src="https://example.com/image.png"/><br/><br/>`

func TestRender(t *testing.T) {
w := new(strings.Builder)
err := render().Render(context.Background(), w)
if err != nil {
t.Errorf("failed to render: %v", err)
}
if diff := cmp.Diff(expected, w.String()); diff != "" {
t.Error(diff)
}
}
8 changes: 8 additions & 0 deletions generator/test-void/template.templ
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{% package testvoid %}

{% templ render() %}
<br/>
<img src="https://example.com/image.png"/>
<br/><br/>
{% endtempl %}

38 changes: 38 additions & 0 deletions generator/test-void/template_templ.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ var voidElements = map[string]struct{}{
"area": {}, "base": {}, "br": {}, "col": {}, "command": {}, "embed": {}, "hr": {}, "img": {}, "input": {}, "keygen": {}, "link": {}, "meta": {}, "param": {}, "source": {}, "track": {}, "wbr": {}}

// https://www.w3.org/TR/2011/WD-html-markup-20110113/syntax.html#void-element
func (e Element) isVoidElement() bool {
func (e Element) IsVoidElement() bool {
_, ok := voidElements[e.Name]
return ok
}
Expand Down Expand Up @@ -328,7 +328,7 @@ func (e Element) Write(w io.Writer, indent int) error {
}
return nil
}
if e.isVoidElement() {
if e.IsVoidElement() {
if _, err := w.Write([]byte("/>")); err != nil {
return err
}
Expand Down

0 comments on commit 82c33cf

Please sign in to comment.