Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add conditional attribute, fixes #65 #66

Merged
merged 9 commits into from
Apr 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,12 @@ go tool covdata percent -i=./coverage/generate,./coverage/unit
go tool covdata textfmt -i=./coverage/generate,./coverage/unit -o coverage.out
```

### lint

```sh
docker run --rm -v $(pwd):/app -w /app golangci/golangci-lint:v1.52.2 golangci-lint run -v
```

### release

Create production build with goreleaser.
Expand Down
317 changes: 194 additions & 123 deletions generator/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -510,21 +510,25 @@ func (g *generator) writeIfExpression(indentLevel int, n parser.IfExpression) (e
if _, err = g.w.Write(` {` + "\n"); err != nil {
return err
}
indentLevel++
if err = g.writeNodes(indentLevel, n, stripLeadingAndTrailingWhitespace(n.Then)); err != nil {
return err
{
indentLevel++
if err = g.writeNodes(indentLevel, n, stripLeadingAndTrailingWhitespace(n.Then)); err != nil {
return err
}
indentLevel--
}
indentLevel--
if len(n.Else) > 0 {
// } else {
if _, err = g.w.WriteIndent(indentLevel, `} else {`+"\n"); err != nil {
return err
}
indentLevel++
if err = g.writeNodes(indentLevel, n, stripLeadingAndTrailingWhitespace(n.Else)); err != nil {
return err
{
indentLevel++
if err = g.writeNodes(indentLevel, n, stripLeadingAndTrailingWhitespace(n.Else)); err != nil {
return err
}
indentLevel--
}
indentLevel--
}
// }
if _, err = g.w.WriteIndent(indentLevel, `}`+"\n"); err != nil {
Expand Down Expand Up @@ -891,149 +895,216 @@ func (g *generator) writeElementScript(indentLevel int, n parser.Element) (err e
return err
}

func (g *generator) writeElementAttributes(indentLevel int, name string, attrs []parser.Attribute) (err error) {
if _, err = g.w.WriteIndent(indentLevel, "// Element Attributes\n"); err != nil {
func (g *generator) writeBoolConstantAttribute(indentLevel int, attr parser.BoolConstantAttribute) (err error) {
name := html.EscapeString(attr.Name)
if _, err = g.w.WriteIndent(indentLevel, fmt.Sprintf(`_, err = templBuffer.WriteString(" %s")`+"\n", name)); err != nil {
return err
}
if err = g.writeErrorHandler(indentLevel); err != nil {
return err
}
return nil
}

func (g *generator) writeConstantAttribute(indentLevel int, attr parser.ConstantAttribute) (err error) {
name := html.EscapeString(attr.Name)
value := html.EscapeString(attr.Value)
if _, err = g.w.WriteIndent(indentLevel, fmt.Sprintf(`_, err = templBuffer.WriteString(" %s=\"%s\"")`+"\n", name, value)); err != nil {
return err
}
if err = g.writeErrorHandler(indentLevel); err != nil {
return err
}
return nil
}

func (g *generator) writeBoolExpressionAttribute(indentLevel int, attr parser.BoolExpressionAttribute) (err error) {
name := html.EscapeString(attr.Name)
// if
if _, err = g.w.WriteIndent(indentLevel, `if `); err != nil {
return err
}
// x == y
var r parser.Range
for i := 0; i < len(attrs); i++ {
switch attr := attrs[i].(type) {
case parser.BoolConstantAttribute:
name := html.EscapeString(attr.Name)
if _, err = g.w.WriteIndent(indentLevel, fmt.Sprintf(`_, err = templBuffer.WriteString(" %s")`+"\n", name)); err != nil {
return err
}
if err = g.writeErrorHandler(indentLevel); err != nil {
return err
}
case parser.ConstantAttribute:
name := html.EscapeString(attr.Name)
value := html.EscapeString(attr.Value)
if _, err = g.w.WriteIndent(indentLevel, fmt.Sprintf(`_, err = templBuffer.WriteString(" %s=\"%s\"")`+"\n", name, value)); err != nil {
return err
}
if err = g.writeErrorHandler(indentLevel); err != nil {
return err
}
case parser.BoolExpressionAttribute:
name := html.EscapeString(attr.Name)
// if
if _, err = g.w.WriteIndent(indentLevel, `if `); err != nil {
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
}
{
indentLevel++
if _, err = g.w.WriteIndent(indentLevel, fmt.Sprintf(`_, err = templBuffer.WriteString(" %s")`+"\n", name)); err != nil {
return err
}
if err = g.writeErrorHandler(indentLevel); err != nil {
return err
}
indentLevel--
}
// }
if _, err = g.w.WriteIndent(indentLevel, `}`+"\n"); err != nil {
return err
}
return nil
}

func (g *generator) writeExpressionAttribute(indentLevel int, elementName string, attr parser.ExpressionAttribute) (err error) {
attrName := html.EscapeString(attr.Name)
// Name
if _, err = g.w.WriteIndent(indentLevel, fmt.Sprintf(`_, err = templBuffer.WriteString(" %s=")`+"\n", attrName)); err != nil {
return err
}
if err = g.writeErrorHandler(indentLevel); err != nil {
return err
}
// Value.
// Open quote.
if _, err = g.w.WriteIndent(indentLevel, `_, err = templBuffer.WriteString("\"")`+"\n"); err != nil {
return err
}
if err = g.writeErrorHandler(indentLevel); err != nil {
return err
}
if elementName == "a" && attr.Name == "href" {
vn := g.createVariableName()
// var vn templ.SafeURL =
if _, err = g.w.WriteIndent(indentLevel, "var "+vn+" templ.SafeURL = "); err != nil {
return err
}
// p.Name()
var r parser.Range
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.w.WriteIndent(indentLevel, "_, err = templBuffer.WriteString(templ.EscapeString(string("+vn+")))\n"); err != nil {
return err
}
if err = g.writeErrorHandler(indentLevel); err != nil {
return err
}
} else {
if strings.HasPrefix(attr.Name, "on") {
// It's a JavaScript handler, and requires special handling, because we expect a JavaScript expression.
vn := g.createVariableName()
// var vn templ.ComponentScript =
if _, err = g.w.WriteIndent(indentLevel, "var "+vn+" templ.ComponentScript = "); err != nil {
return err
}
// x == y
// p.Name()
var r parser.Range
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
}
{
indentLevel++
if _, err = g.w.WriteIndent(indentLevel, fmt.Sprintf(`_, err = templBuffer.WriteString(" %s")`+"\n", name)); err != nil {
return err
}
if err = g.writeErrorHandler(indentLevel); err != nil {
return err
}
indentLevel--
}
// }
if _, err = g.w.WriteIndent(indentLevel, `}`+"\n"); err != nil {
if _, err = g.w.Write("\n"); err != nil {
return err
}
case parser.ExpressionAttribute:
attrName := html.EscapeString(attr.Name)
// Name
if _, err = g.w.WriteIndent(indentLevel, fmt.Sprintf(`_, err = templBuffer.WriteString(" %s=")`+"\n", attrName)); err != nil {
if _, err = g.w.WriteIndent(indentLevel, "_, err = templBuffer.WriteString("+vn+".Call)\n"); err != nil {
return err
}
if err = g.writeErrorHandler(indentLevel); err != nil {
return err
}
// Value.
// Open quote.
if _, err = g.w.WriteIndent(indentLevel, `_, err = templBuffer.WriteString("\"")`+"\n"); err != nil {
} else {
// templBuffer.WriteString(templ.EscapeString(
if _, err = g.w.WriteIndent(indentLevel, "_, err = templBuffer.WriteString(templ.EscapeString("); err != nil {
return err
}
if err = g.writeErrorHandler(indentLevel); err != nil {
// p.Name()
var r parser.Range
if r, err = g.w.Write(attr.Expression.Value); err != nil {
return err
}
if name == "a" && attr.Name == "href" {
vn := g.createVariableName()
// var vn templ.SafeURL =
if _, err = g.w.WriteIndent(indentLevel, "var "+vn+" templ.SafeURL = "); 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.w.WriteIndent(indentLevel, "_, err = templBuffer.WriteString(templ.EscapeString(string("+vn+")))\n"); err != nil {
return err
}
if err = g.writeErrorHandler(indentLevel); err != nil {
return err
}
} else {
if strings.HasPrefix(attr.Name, "on") {
// It's a JavaScript handler, and requires special handling, because we expect a JavaScript expression.
vn := g.createVariableName()
// var vn templ.ComponentScript =
if _, err = g.w.WriteIndent(indentLevel, "var "+vn+" templ.ComponentScript = "); 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.w.WriteIndent(indentLevel, "_, err = templBuffer.WriteString("+vn+".Call)\n"); err != nil {
return err
}
if err = g.writeErrorHandler(indentLevel); err != nil {
return err
}
} else {
// templBuffer.WriteString(templ.EscapeString(
if _, err = g.w.WriteIndent(indentLevel, "_, err = templBuffer.WriteString(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 = templBuffer.WriteString("\"")`+"\n"); err != nil {
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 = templBuffer.WriteString("\"")`+"\n"); err != nil {
return err
}
if err = g.writeErrorHandler(indentLevel); err != nil {
return err
}
return nil
}

func (g *generator) writeConditionalAttribute(indentLevel int, elementName string, attr parser.ConditionalAttribute) (err error) {
// if
if _, err = g.w.WriteIndent(indentLevel, `if `); err != nil {
return err
}
// x == y
var r parser.Range
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
}
{
indentLevel++
if err = g.writeElementAttributes(indentLevel, elementName, attr.Then); err != nil {
return err
}
indentLevel--
}
if len(attr.Else) > 0 {
// } else {
if _, err = g.w.WriteIndent(indentLevel, `} else {`+"\n"); err != nil {
return err
}
{
indentLevel++
if err = g.writeElementAttributes(indentLevel, elementName, attr.Else); err != nil {
return err
}
indentLevel--
}
}
// }
if _, err = g.w.WriteIndent(indentLevel, `}`+"\n"); err != nil {
return err
}
return nil
}

func (g *generator) writeElementAttributes(indentLevel int, name string, attrs []parser.Attribute) (err error) {
if _, err = g.w.WriteIndent(indentLevel, "// Element Attributes\n"); err != nil {
return err
}
for i := 0; i < len(attrs); i++ {
switch attr := attrs[i].(type) {
case parser.BoolConstantAttribute:
err = g.writeBoolConstantAttribute(indentLevel, attr)
case parser.ConstantAttribute:
err = g.writeConstantAttribute(indentLevel, attr)
case parser.BoolExpressionAttribute:
err = g.writeBoolExpressionAttribute(indentLevel, attr)
case parser.ExpressionAttribute:
err = g.writeExpressionAttribute(indentLevel, name, attr)
case parser.ConditionalAttribute:
err = g.writeConditionalAttribute(indentLevel, name, attr)
default:
return fmt.Errorf("unknown attribute type %s", reflect.TypeOf(attrs[i]))
err = fmt.Errorf("unknown attribute type %s", reflect.TypeOf(attrs[i]))
}
}
return err
return
}

func (g *generator) writeRawElement(indentLevel int, n parser.RawElement) (err error) {
Expand Down
7 changes: 7 additions & 0 deletions generator/test-element-attributes/data.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package testelementattributes

type person struct {
name string
email string
important bool
}
1 change: 1 addition & 0 deletions generator/test-element-attributes/expected.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div style="width: 100;">Important</div><div style="width: 100;" class="unimportant">Unimportant</div><div style="width: 100;" class="unimportant">Else</div>
Loading