From 7aa55bb89a221b2c2ebb68ab6999449afb9e4dc7 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Sun, 1 Oct 2023 12:13:51 -0700 Subject: [PATCH] Create initial elements --- Makefile | 9 +++++++ elem.go | 49 +++++++++++++++++++++++++++++++++++ elements.go | 45 +++++++++++++++++++++++++++++++++ elements_test.go | 66 ++++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 11 ++++++++ go.sum | 10 ++++++++ 6 files changed, 190 insertions(+) create mode 100644 Makefile create mode 100644 elem.go create mode 100644 elements.go create mode 100644 elements_test.go create mode 100644 go.mod create mode 100644 go.sum diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..37bd484 --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +.PHONY: test tidy + +tidy: + @echo "Tidying up module..." + go mod tidy + +test: + @echo "Running tests..." + go test ./... \ No newline at end of file diff --git a/elem.go b/elem.go new file mode 100644 index 0000000..a4adbdf --- /dev/null +++ b/elem.go @@ -0,0 +1,49 @@ +package elem + +import ( + "sort" +) + +type Element struct { + Tag string + Props map[string]string + Children []interface{} // Can be either string (for text) or another Element +} + +func NewElement(tag string, props Props, children ...interface{}) *Element { + return &Element{ + Tag: tag, + Props: props, + Children: children, + } +} + +func (e *Element) Render() string { + // Sort the keys for consistent order + keys := make([]string, 0, len(e.Props)) + for k := range e.Props { + keys = append(keys, k) + } + sort.Strings(keys) + + props := "" + for _, k := range keys { + props += ` ` + k + `="` + e.Props[k] + `"` + } + + content := "" + for _, child := range e.Children { + switch c := child.(type) { + case string: + content += c + case *Element: + content += c.Render() + } + } + + if content == "" { + return `<` + e.Tag + props + ` />` // Self-closing tag + } + + return `<` + e.Tag + props + `>` + content + `` +} diff --git a/elements.go b/elements.go new file mode 100644 index 0000000..6b4e9e0 --- /dev/null +++ b/elements.go @@ -0,0 +1,45 @@ +package elem + +func Div(props Props, children ...interface{}) *Element { + return NewElement("div", props, children...) +} + +func H1(props Props, children ...interface{}) *Element { + return NewElement("h1", props, children...) +} + +func H2(props Props, children ...interface{}) *Element { + return NewElement("h2", props, children...) +} + +func H3(props Props, children ...interface{}) *Element { + return NewElement("h3", props, children...) +} + +func P(props Props, children ...interface{}) *Element { + return NewElement("p", props, children...) +} + +func A(props Props, children ...interface{}) *Element { + return NewElement("a", props, children...) +} + +func Span(props Props, children ...interface{}) *Element { + return NewElement("span", props, children...) +} + +func Ul(props Props, children ...interface{}) *Element { + return NewElement("ul", props, children...) +} + +func Li(props Props, children ...interface{}) *Element { + return NewElement("li", props, children...) +} + +func Img(props Props) *Element { + return NewElement("img", props) +} + +func Text(content string) string { + return content +} diff --git a/elements_test.go b/elements_test.go new file mode 100644 index 0000000..70798e7 --- /dev/null +++ b/elements_test.go @@ -0,0 +1,66 @@ +package elem + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestA(t *testing.T) { + expected := `Visit Example` + el := A(Props{Href: "https://example.com"}, Text("Visit Example")) + assert.Equal(t, expected, el.Render()) +} + +func TestDiv(t *testing.T) { + expected := `
Hello, Elem!
` + el := Div(Props{Class: "container"}, Text("Hello, Elem!")) + assert.Equal(t, expected, el.Render()) +} + +func TestH1(t *testing.T) { + expected := `

Hello, Elem!

` + el := H1(Props{Class: "title"}, Text("Hello, Elem!")) + assert.Equal(t, expected, el.Render()) +} + +func TestH2(t *testing.T) { + expected := `

Hello, Elem!

` + el := H2(Props{Class: "subtitle"}, Text("Hello, Elem!")) + assert.Equal(t, expected, el.Render()) +} + +func TestH3(t *testing.T) { + expected := `

Hello, Elem!

` + el := H3(nil, Text("Hello, Elem!")) + assert.Equal(t, expected, el.Render()) +} + +func TestImg(t *testing.T) { + expected := `An image` + el := Img(Props{Src: "image.jpg", Alt: "An image"}) + assert.Equal(t, expected, el.Render()) +} + +func TestLi(t *testing.T) { + expected := `
  • Item 1
  • ` + el := Li(nil, Text("Item 1")) + assert.Equal(t, expected, el.Render()) +} + +func TestP(t *testing.T) { + expected := `

    Hello, Elem!

    ` + el := P(nil, Text("Hello, Elem!")) + assert.Equal(t, expected, el.Render()) +} + +func TestSpan(t *testing.T) { + expected := `Hello, Elem!` + el := Span(Props{Class: "highlight"}, Text("Hello, Elem!")) + assert.Equal(t, expected, el.Render()) +} + +func TestUl(t *testing.T) { + expected := `` + el := Ul(nil, Li(nil, Text("Item 1")), Li(nil, Text("Item 2"))) + assert.Equal(t, expected, el.Render()) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..9aa8340 --- /dev/null +++ b/go.mod @@ -0,0 +1,11 @@ +module github.com/chasefleming/elem-go + +go 1.21.1 + +require github.com/stretchr/testify v1.8.4 + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..fa4b6e6 --- /dev/null +++ b/go.sum @@ -0,0 +1,10 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=