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