diff --git a/attribute.go b/attribute.go
index 2fc8496..60cba08 100644
--- a/attribute.go
+++ b/attribute.go
@@ -2,6 +2,7 @@ package humle
import (
"fmt"
+ "html/template"
)
type attribute struct {
@@ -14,7 +15,7 @@ type attribute struct {
func Attr(name, value string) attribute {
return attribute{
name: name,
- value: "fisk",
+ value: value,
}
}
@@ -29,7 +30,7 @@ func (a attribute) String() string {
return fmt.Sprintf(`%s="%s"`, a.name, a.value)
}
// TODO: Add escaping for HTML entities if needed
- return fmt.Sprintf(`%s="%s"`, a.name, a.value)
+ return fmt.Sprintf(`%s="%s"`, a.name, template.HTMLEscapeString(a.value))
//return fmt.Sprintf(`%s="%s"`, a.name, template.JSEscapeString(a.value))
}
diff --git a/component.go b/component.go
index 6027828..db270da 100644
--- a/component.go
+++ b/component.go
@@ -2,16 +2,17 @@
package humle
import (
+ "errors"
"io"
+ "strings"
)
-type RenderFunc func(args []Argument, children Node) Node
+type RenderFunc func() Node
type Component struct {
// Name is mostly for debugging and maybe future web component
Name string
args []Argument
- childNode Node
renderFunc RenderFunc
}
@@ -24,10 +25,19 @@ func NewComponent(name string, render RenderFunc) *Component {
}
func (c *Component) WriteTo(w io.Writer) (int64, error) {
- t := c.renderFunc(c.args, c.childNode)
+ if c.renderFunc == nil {
+ return 0, errors.New("Component has no render method")
+ }
+ t := c.renderFunc()
return t.WriteTo(w)
}
+func (n *Component) String() string {
+ var b strings.Builder
+ n.WriteTo(&b)
+ return b.String()
+}
+
func (c *Component) Type() NodeType {
return NodeComponent
}
diff --git a/component_test.go b/component_test.go
new file mode 100644
index 0000000..5669216
--- /dev/null
+++ b/component_test.go
@@ -0,0 +1,24 @@
+package humle_test
+
+import (
+ "testing"
+
+ h "github.com/andrioid/humle"
+)
+
+func basicLayout() *h.Component {
+ return h.NewComponent("basic-layout", func() h.Node {
+ return h.Div(h.Text("Hello"))
+ })
+}
+
+var testMatrixComponents = h.TestCases{
+ "component": h.TestCase{
+ Input: basicLayout(),
+ Expected: `
Hello
`,
+ },
+}
+
+func TestComponents(t *testing.T) {
+ testMatrixComponents.Test(t)
+}
diff --git a/group.go b/group.go
index 6719a4e..682fc84 100644
--- a/group.go
+++ b/group.go
@@ -2,6 +2,7 @@ package humle
import (
"io"
+ "strings"
)
type Group []Node
@@ -30,3 +31,9 @@ func (g Group) WriteTo(w io.Writer) (int64, error) {
return total, nil
}
+
+func (n Group) String() string {
+ var b strings.Builder
+ n.WriteTo(&b)
+ return b.String()
+}
diff --git a/html_tags_gen.go b/html_tags_gen.go
index 4402e3d..2883880 100644
--- a/html_tags_gen.go
+++ b/html_tags_gen.go
@@ -4,291 +4,291 @@ package humle
// Elements
-func HTML(args ...Argument) *Tag {
- tag := NewTag("html", args...)
+func HTML(args ...Argument) *TagNode {
+ tag := Tag("html", args...)
return tag
}
-func Head(args ...Argument) *Tag {
- tag := NewTag("head", args...)
+func Head(args ...Argument) *TagNode {
+ tag := Tag("head", args...)
return tag
}
-func Title(args ...Argument) *Tag {
- tag := NewTag("title", args...)
+func Title(args ...Argument) *TagNode {
+ tag := Tag("title", args...)
return tag
}
-func Link(args ...Argument) *Tag {
- tag := NewTag("link", args...)
+func Link(args ...Argument) *TagNode {
+ tag := Tag("link", args...)
return tag
}
-func Style(args ...Argument) *Tag {
- tag := NewTag("style", args...)
+func Style(args ...Argument) *TagNode {
+ tag := Tag("style", args...)
return tag
}
-func Script(args ...Argument) *Tag {
- tag := NewTag("script", args...)
+func Script(args ...Argument) *TagNode {
+ tag := Tag("script", args...)
return tag
}
-func Noscript(args ...Argument) *Tag {
- tag := NewTag("noscript", args...)
+func Noscript(args ...Argument) *TagNode {
+ tag := Tag("noscript", args...)
return tag
}
-func Template(args ...Argument) *Tag {
- tag := NewTag("template", args...)
+func Template(args ...Argument) *TagNode {
+ tag := Tag("template", args...)
return tag
}
-func Article(args ...Argument) *Tag {
- tag := NewTag("article", args...)
+func Article(args ...Argument) *TagNode {
+ tag := Tag("article", args...)
return tag
}
-func Aside(args ...Argument) *Tag {
- tag := NewTag("aside", args...)
+func Aside(args ...Argument) *TagNode {
+ tag := Tag("aside", args...)
return tag
}
-func Footer(args ...Argument) *Tag {
- tag := NewTag("footer", args...)
+func Footer(args ...Argument) *TagNode {
+ tag := Tag("footer", args...)
return tag
}
-func Header(args ...Argument) *Tag {
- tag := NewTag("header", args...)
+func Header(args ...Argument) *TagNode {
+ tag := Tag("header", args...)
return tag
}
-func Nav(args ...Argument) *Tag {
- tag := NewTag("nav", args...)
+func Nav(args ...Argument) *TagNode {
+ tag := Tag("nav", args...)
return tag
}
-func Figure(args ...Argument) *Tag {
- tag := NewTag("figure", args...)
+func Figure(args ...Argument) *TagNode {
+ tag := Tag("figure", args...)
return tag
}
-func Figcaption(args ...Argument) *Tag {
- tag := NewTag("figcaption", args...)
+func Figcaption(args ...Argument) *TagNode {
+ tag := Tag("figcaption", args...)
return tag
}
-func Address(args ...Argument) *Tag {
- tag := NewTag("address", args...)
+func Address(args ...Argument) *TagNode {
+ tag := Tag("address", args...)
return tag
}
-func Dl(args ...Argument) *Tag {
- tag := NewTag("dl", args...)
+func Dl(args ...Argument) *TagNode {
+ tag := Tag("dl", args...)
return tag
}
-func Dt(args ...Argument) *Tag {
- tag := NewTag("dt", args...)
+func Dt(args ...Argument) *TagNode {
+ tag := Tag("dt", args...)
return tag
}
-func Dd(args ...Argument) *Tag {
- tag := NewTag("dd", args...)
+func Dd(args ...Argument) *TagNode {
+ tag := Tag("dd", args...)
return tag
}
-func Ol(args ...Argument) *Tag {
- tag := NewTag("ol", args...)
+func Ol(args ...Argument) *TagNode {
+ tag := Tag("ol", args...)
return tag
}
-func Ul(args ...Argument) *Tag {
- tag := NewTag("ul", args...)
+func Ul(args ...Argument) *TagNode {
+ tag := Tag("ul", args...)
return tag
}
-func Li(args ...Argument) *Tag {
- tag := NewTag("li", args...)
+func Li(args ...Argument) *TagNode {
+ tag := Tag("li", args...)
return tag
}
-func Table(args ...Argument) *Tag {
- tag := NewTag("table", args...)
+func Table(args ...Argument) *TagNode {
+ tag := Tag("table", args...)
return tag
}
-func Caption(args ...Argument) *Tag {
- tag := NewTag("caption", args...)
+func Caption(args ...Argument) *TagNode {
+ tag := Tag("caption", args...)
return tag
}
-func Thead(args ...Argument) *Tag {
- tag := NewTag("thead", args...)
+func Thead(args ...Argument) *TagNode {
+ tag := Tag("thead", args...)
return tag
}
-func Tbody(args ...Argument) *Tag {
- tag := NewTag("tbody", args...)
+func Tbody(args ...Argument) *TagNode {
+ tag := Tag("tbody", args...)
return tag
}
-func Tfoot(args ...Argument) *Tag {
- tag := NewTag("tfoot", args...)
+func Tfoot(args ...Argument) *TagNode {
+ tag := Tag("tfoot", args...)
return tag
}
-func Tr(args ...Argument) *Tag {
- tag := NewTag("tr", args...)
+func Tr(args ...Argument) *TagNode {
+ tag := Tag("tr", args...)
return tag
}
-func Th(args ...Argument) *Tag {
- tag := NewTag("th", args...)
+func Th(args ...Argument) *TagNode {
+ tag := Tag("th", args...)
return tag
}
-func Td(args ...Argument) *Tag {
- tag := NewTag("td", args...)
+func Td(args ...Argument) *TagNode {
+ tag := Tag("td", args...)
return tag
}
-func Col(args ...Argument) *Tag {
- tag := NewTag("col", args...)
+func Col(args ...Argument) *TagNode {
+ tag := Tag("col", args...)
return tag
}
-func Colgroup(args ...Argument) *Tag {
- tag := NewTag("colgroup", args...)
+func Colgroup(args ...Argument) *TagNode {
+ tag := Tag("colgroup", args...)
return tag
}
-func Form(args ...Argument) *Tag {
- tag := NewTag("form", args...)
+func Form(args ...Argument) *TagNode {
+ tag := Tag("form", args...)
return tag
}
-func Fieldset(args ...Argument) *Tag {
- tag := NewTag("fieldset", args...)
+func Fieldset(args ...Argument) *TagNode {
+ tag := Tag("fieldset", args...)
return tag
}
-func Legend(args ...Argument) *Tag {
- tag := NewTag("legend", args...)
+func Legend(args ...Argument) *TagNode {
+ tag := Tag("legend", args...)
return tag
}
-func Label(args ...Argument) *Tag {
- tag := NewTag("label", args...)
+func Label(args ...Argument) *TagNode {
+ tag := Tag("label", args...)
return tag
}
-func Input(args ...Argument) *Tag {
- tag := NewTag("input", args...)
+func Input(args ...Argument) *TagNode {
+ tag := Tag("input", args...)
return tag
}
-func Select(args ...Argument) *Tag {
- tag := NewTag("select", args...)
+func Select(args ...Argument) *TagNode {
+ tag := Tag("select", args...)
return tag
}
-func Option(args ...Argument) *Tag {
- tag := NewTag("option", args...)
+func Option(args ...Argument) *TagNode {
+ tag := Tag("option", args...)
return tag
}
-func Optgroup(args ...Argument) *Tag {
- tag := NewTag("optgroup", args...)
+func Optgroup(args ...Argument) *TagNode {
+ tag := Tag("optgroup", args...)
return tag
}
-func Div(args ...Argument) *Tag {
- tag := NewTag("div", args...)
+func Div(args ...Argument) *TagNode {
+ tag := Tag("div", args...)
return tag
}
-func Section(args ...Argument) *Tag {
- tag := NewTag("section", args...)
+func Section(args ...Argument) *TagNode {
+ tag := Tag("section", args...)
return tag
}
-func Main(args ...Argument) *Tag {
- tag := NewTag("main", args...)
+func Main(args ...Argument) *TagNode {
+ tag := Tag("main", args...)
return tag
}
-func Button(args ...Argument) *Tag {
- tag := NewTag("button", args...)
+func Button(args ...Argument) *TagNode {
+ tag := Tag("button", args...)
return tag
}
-func A(args ...Argument) *Tag {
- tag := NewTag("a", args...)
+func A(args ...Argument) *TagNode {
+ tag := Tag("a", args...)
return tag
}
-func H1(args ...Argument) *Tag {
- tag := NewTag("h1", args...)
+func H1(args ...Argument) *TagNode {
+ tag := Tag("h1", args...)
return tag
}
-func H2(args ...Argument) *Tag {
- tag := NewTag("h2", args...)
+func H2(args ...Argument) *TagNode {
+ tag := Tag("h2", args...)
return tag
}
-func H3(args ...Argument) *Tag {
- tag := NewTag("h3", args...)
+func H3(args ...Argument) *TagNode {
+ tag := Tag("h3", args...)
return tag
}
-func P(args ...Argument) *Tag {
- tag := NewTag("p", args...)
+func P(args ...Argument) *TagNode {
+ tag := Tag("p", args...)
return tag
}
-func Span(args ...Argument) *Tag {
- tag := NewTag("span", args...)
+func Span(args ...Argument) *TagNode {
+ tag := Tag("span", args...)
return tag
}
-func Field(args ...Argument) *Tag {
- tag := NewTag("field", args...)
+func Field(args ...Argument) *TagNode {
+ tag := Tag("field", args...)
return tag
}
-func Pre(args ...Argument) *Tag {
- tag := NewTag("pre", args...)
+func Pre(args ...Argument) *TagNode {
+ tag := Tag("pre", args...)
return tag
}
-func Body(args ...Argument) *Tag {
- tag := NewTag("body", args...)
+func Body(args ...Argument) *TagNode {
+ tag := Tag("body", args...)
return tag
}
-func Svg(args ...Argument) *Tag {
- tag := NewTag("svg", args...)
+func Svg(args ...Argument) *TagNode {
+ tag := Tag("svg", args...)
return tag
}
// Void Elements
-func Br(args ...Argument) *Tag {
- tag := NewTag("br", args...)
+func Br(args ...Argument) *TagNode {
+ tag := Tag("br", args...)
tag = WithVoidElement(tag)
return tag
}
-func Hr(args ...Argument) *Tag {
- tag := NewTag("hr", args...)
+func Hr(args ...Argument) *TagNode {
+ tag := Tag("hr", args...)
tag = WithVoidElement(tag)
return tag
}
-func Meta(args ...Argument) *Tag {
- tag := NewTag("meta", args...)
+func Meta(args ...Argument) *TagNode {
+ tag := Tag("meta", args...)
tag = WithVoidElement(tag)
return tag
}
diff --git a/humle.go b/humle.go
index 582d0ba..9f10c08 100644
--- a/humle.go
+++ b/humle.go
@@ -1,7 +1,23 @@
package humle
-import "io"
+import (
+ "io"
+ "strings"
+)
func WriteHTML(w io.Writer, n Node) (int64, error) {
return n.WriteTo(w)
}
+
+func WriteString(n Node) (string, error) {
+ if n == nil {
+ return "", nil
+ }
+ var b strings.Builder
+ _, err := n.WriteTo(&b)
+ if err != nil {
+ return "", err
+ }
+
+ return b.String(), nil
+}
diff --git a/node_test.go b/node_test.go
index cff3f82..21c8dd3 100644
--- a/node_test.go
+++ b/node_test.go
@@ -1,6 +1,8 @@
package humle_test
import (
+ "fmt"
+ "html/template"
"testing"
. "github.com/andrioid/humle"
@@ -29,7 +31,7 @@ var testMatrix2 = TestCases{
},
"with id and data": TestCase{
Input: Div(ID("divid"), Data("show", `$tab === 'logs'`)),
- Expected: ``,
+ Expected: fmt.Sprintf(``, template.HTMLEscapeString("$tab === 'logs'")),
},
"raw": TestCase{
Input: RawHTML(""),
diff --git a/nodes.go b/nodes.go
index faa5752..0330250 100644
--- a/nodes.go
+++ b/nodes.go
@@ -1,6 +1,8 @@
package humle
-import "io"
+import (
+ "io"
+)
type NodeType int
@@ -15,4 +17,5 @@ const (
type Node interface {
Type() NodeType
io.WriterTo
+ String() string
}
diff --git a/raw_tag.go b/raw_tag.go
index 0295bef..d3fa9ab 100644
--- a/raw_tag.go
+++ b/raw_tag.go
@@ -2,6 +2,7 @@ package humle
import (
"io"
+ "strings"
)
// Satisfies Node interface
@@ -17,3 +18,9 @@ func (n RawHTML) WriteTo(w io.Writer) (int64, error) {
len, err := w.Write([]byte(n))
return int64(len), err
}
+
+func (n RawHTML) String() string {
+ var b strings.Builder
+ n.WriteTo(&b)
+ return b.String()
+}
diff --git a/tag.go b/tag.go
index 91e35e3..5a272f1 100644
--- a/tag.go
+++ b/tag.go
@@ -3,22 +3,23 @@ package humle
import (
"io"
"log"
+ "strings"
)
-type Tag struct {
+type TagNode struct {
name string
children []Node
arguments Arguments
isVoidElement bool
}
-func (e *Tag) Type() NodeType {
+func (e *TagNode) Type() NodeType {
return NodeTag
}
// Identifies nodes and assigns them properly for later rendering
-func NewTag(name string, args ...Argument) *Tag {
- el := Tag{
+func Tag(name string, args ...Argument) *TagNode {
+ el := TagNode{
name: name,
children: []Node{},
arguments: Arguments{},
@@ -28,10 +29,10 @@ func NewTag(name string, args ...Argument) *Tag {
return &el
}
-func (el *Tag) parseChildren(nodes []Node) {
+func (el *TagNode) parseChildren(nodes []Node) {
for _, node := range nodes {
switch n := node.(type) {
- case *Tag:
+ case *TagNode:
// Children for recursive rendering
el.children = append(el.children, n)
case Group:
@@ -45,12 +46,12 @@ func (el *Tag) parseChildren(nodes []Node) {
}
}
-func (el *Tag) Children(children ...Node) *Tag {
+func (el *TagNode) Children(children ...Node) *TagNode {
el.parseChildren(children)
return el
}
-func (el *Tag) WriteTo(w io.Writer) (int64, error) {
+func (el *TagNode) WriteTo(w io.Writer) (int64, error) {
attrs := el.arguments.GetAttributes().String()
w.Write([]byte("<" + el.name))
if attrs != "" {
@@ -80,7 +81,13 @@ func (el *Tag) WriteTo(w io.Writer) (int64, error) {
return 0, nil
}
-func WithVoidElement(el *Tag) *Tag {
+func (n *TagNode) String() string {
+ var b strings.Builder
+ n.WriteTo(&b)
+ return b.String()
+}
+
+func WithVoidElement(el *TagNode) *TagNode {
el.isVoidElement = true
return el
}
diff --git a/text_value.go b/text_value.go
index b29b357..c91a3ee 100644
--- a/text_value.go
+++ b/text_value.go
@@ -3,6 +3,7 @@ package humle
import (
"html/template"
"io"
+ "strings"
)
type Text string
@@ -16,6 +17,12 @@ func (n Text) WriteTo(w io.Writer) (int64, error) {
return 0, nil
}
+func (n Text) String() string {
+ var b strings.Builder
+ n.WriteTo(&b)
+ return b.String()
+}
+
// TODO: I'd really like for Text to be work as an attribute too
func (n Text) ArgumentType() ArgumentType {
return ArgumentText