From 73250375c94cf4764387ba60b5c57719a28fa3fb Mon Sep 17 00:00:00 2001
From: Arpad Ryszka
Date: Mon, 6 Oct 2025 00:37:10 +0200
Subject: [PATCH] test rendering
---
Makefile | 42 +-
eq.go | 12 +-
escape_test.go | 2 +-
indent.go | 16 +
lib.go | 68 +-
lib_test.go | 4 +-
notes.txt | 5 -
query.go | 11 +-
query_test.go | 12 +-
render.go | 34 +-
render_test.go | 906 +++++++++++++++++-
script/generate-tags.go | 2 +-
script/promote-to-tags.go | 2 +-
tags.block.txt => tag.block.txt | 0
tags.inline.txt => tag.inline.txt | 0
...linechildren.txt => tag.inlinechildren.txt | 0
tags.script.txt => tag.script.txt | 0
tags.void.block.txt => tag.void.block.txt | 0
tags.void.inline.txt => tag.void.inline.txt | 0
{tags => tag}/block.gen.go | 2 +-
{tags => tag}/inline.gen.go | 2 +-
{tags => tag}/inlinechildren.gen.go | 2 +-
{tags => tag}/promote.gen.go | 2 +-
{tags => tag}/script.gen.go | 2 +-
{tags => tag}/void.block.gen.go | 2 +-
{tags => tag}/void.inline.gen.go | 2 +-
validate.go | 6 +-
validate_test.go | 2 +-
wrap.go | 11 +-
wrap_test.go | 10 +-
30 files changed, 1028 insertions(+), 131 deletions(-)
rename tags.block.txt => tag.block.txt (100%)
rename tags.inline.txt => tag.inline.txt (100%)
rename tags.inlinechildren.txt => tag.inlinechildren.txt (100%)
rename tags.script.txt => tag.script.txt (100%)
rename tags.void.block.txt => tag.void.block.txt (100%)
rename tags.void.inline.txt => tag.void.inline.txt (100%)
rename {tags => tag}/block.gen.go (99%)
rename {tags => tag}/inline.gen.go (99%)
rename {tags => tag}/inlinechildren.gen.go (97%)
rename {tags => tag}/promote.gen.go (93%)
rename {tags => tag}/script.gen.go (93%)
rename {tags => tag}/void.block.gen.go (96%)
rename {tags => tag}/void.inline.gen.go (96%)
diff --git a/Makefile b/Makefile
index 87c189e..06698ea 100644
--- a/Makefile
+++ b/Makefile
@@ -7,30 +7,38 @@ all: clean fmt build cover
build: $(SOURCES) tags promote-to-tags
go build
-tags: tags/block.gen.go tags/inline.gen.go tags/void.block.gen.go tags/void.inline.gen.go tags/inlinechildren.gen.go tags/script.gen.go
+tags: \
+ tag/block.gen.go \
+ tag/inline.gen.go \
+ tag/void.block.gen.go \
+ tag/void.inline.gen.go \
+ tag/inlinechildren.gen.go \
+ tag/script.gen.go
+ go fmt tag/*
-promote-to-tags: tags/promote.gen.go
+promote-to-tags: tag/promote.gen.go
+ go fmt tag/*
-tags/block.gen.go: $(SOURCES) tags.block.txt
- go run script/generate-tags.go < tags.block.txt > tags/block.gen.go
+tag/block.gen.go: $(SOURCES) tag.block.txt
+ go run script/generate-tags.go < tag.block.txt > tag/block.gen.go
-tags/inline.gen.go: $(SOURCES) tags.inline.txt
- go run script/generate-tags.go Inline < tags.inline.txt > tags/inline.gen.go
+tag/inline.gen.go: $(SOURCES) tag.inline.txt
+ go run script/generate-tags.go Inline < tag.inline.txt > tag/inline.gen.go
-tags/inlinechildren.gen.go: $(SOURCES) tags.inlinechildren.txt
- go run script/generate-tags.go InlineChildren < tags.inlinechildren.txt > tags/inlinechildren.gen.go
+tag/inlinechildren.gen.go: $(SOURCES) tag.inlinechildren.txt
+ go run script/generate-tags.go InlineChildren < tag.inlinechildren.txt > tag/inlinechildren.gen.go
-tags/void.block.gen.go: $(SOURCES) tags.void.block.txt
- go run script/generate-tags.go Void < tags.void.block.txt > tags/void.block.gen.go
+tag/void.block.gen.go: $(SOURCES) tag.void.block.txt
+ go run script/generate-tags.go Void < tag.void.block.txt > tag/void.block.gen.go
-tags/void.inline.gen.go: $(SOURCES) tags.void.inline.txt
- go run script/generate-tags.go Void Inline < tags.void.inline.txt > tags/void.inline.gen.go
+tag/void.inline.gen.go: $(SOURCES) tag.void.inline.txt
+ go run script/generate-tags.go Void Inline < tag.void.inline.txt > tag/void.inline.gen.go
-tags/script.gen.go: $(SOURCES) tags.script.txt
- go run script/generate-tags.go ScriptContent < tags.script.txt > tags/script.gen.go
+tag/script.gen.go: $(SOURCES) tag.script.txt
+ go run script/generate-tags.go ScriptContent < tag.script.txt > tag/script.gen.go
-tags/promote.gen.go: $(SOURCES) promote-to-tags.txt
- go run script/promote-to-tags.go < promote-to-tags.txt > tags/promote.gen.go
+tag/promote.gen.go: $(SOURCES) promote-to-tags.txt
+ go run script/promote-to-tags.go < promote-to-tags.txt > tag/promote.gen.go
fmt: $(SOURCES) tags
go fmt ./...
@@ -49,4 +57,4 @@ showcover: .cover
clean:
go clean
- rm -f tags/*.gen.go
+ rm -f tag/*.gen.go
diff --git a/eq.go b/eq.go
index 336cb6b..260f81f 100644
--- a/eq.go
+++ b/eq.go
@@ -6,13 +6,17 @@ func eq2(t1, t2 Tag) bool {
}
a1, a2 := AllAttributes(t1), AllAttributes(t2)
- if len(a1) != len(a2) {
+ if len(a1.names) != len(a2.names) {
return false
}
- for name := range a1 {
- v1 := a1[name]
- v2, ok := a2[name]
+ for i, name := range a1.names {
+ if a2.names[i] != name {
+ return false
+ }
+
+ v1 := a1.values[name]
+ v2, ok := a2.values[name]
if !ok || v1 != v2 {
return false
}
diff --git a/escape_test.go b/escape_test.go
index c704fd7..93d9b19 100644
--- a/escape_test.go
+++ b/escape_test.go
@@ -3,7 +3,7 @@ package html_test
import (
"bytes"
"code.squareroundforest.org/arpio/html"
- . "code.squareroundforest.org/arpio/html/tags"
+ . "code.squareroundforest.org/arpio/html/tag"
"testing"
)
diff --git a/indent.go b/indent.go
index ea4244a..7878271 100644
--- a/indent.go
+++ b/indent.go
@@ -15,6 +15,21 @@ type indentWriter struct {
err error
}
+func indentLen(indent string) int {
+ var l int
+ r := []rune(indent)
+ for _, ri := range r {
+ if ri == '\t' {
+ l += 8
+ continue
+ }
+
+ l++
+ }
+
+ return l
+}
+
func newIndentWriter(out io.Writer, indent string) *indentWriter {
return &indentWriter{
out: bufio.NewWriter(out),
@@ -66,6 +81,7 @@ func (w *indentWriter) Write(p []byte) (int, error) {
if r == '\n' {
w.write('\n')
+ w.started = true
w.lineStarted = false
continue
}
diff --git a/lib.go b/lib.go
index 076bfcc..bbde2a0 100644
--- a/lib.go
+++ b/lib.go
@@ -9,7 +9,10 @@ import (
)
// when composing html, the Attr convenience function is recommended to construct input attributes
-type Attributes map[string]any
+type Attributes struct {
+ names []string
+ values map[string]any
+}
// immutable
// calling creates a new copy with the passed in attributes and child nodes applied only to the copy
@@ -31,13 +34,6 @@ type Indentation struct {
Indent string
}
-func (t Tag) String() string {
- buf := bytes.NewBuffer(nil)
- r := renderer{out: buf}
- t()(r)
- return buf.String()
-}
-
// convenience function primarily aimed to help with construction of html with tags
// the names and values are applied using fmt.Sprint, tolerating fmt.Stringer implementations
func Attr(a ...any) Attributes {
@@ -45,14 +41,43 @@ func Attr(a ...any) Attributes {
a = append(a, "")
}
- am := make(Attributes)
+ var am Attributes
+ am.values = make(map[string]any)
for i := 0; i < len(a); i += 2 {
- am[fmt.Sprint(a[i])] = a[i+1]
+ name := fmt.Sprint(a[i])
+ am.names = append(am.names, name)
+ am.values[name] = a[i+1]
}
return am
}
+func (a Attributes) Names() []string {
+ if len(a.names) == 0 {
+ return nil
+ }
+
+ n := make([]string, len(a.names))
+ copy(n, a.names)
+ return n
+}
+
+func (a Attributes) Has(name string) bool {
+ _, ok := a.values[name]
+ return ok
+}
+
+func (a Attributes) Value(name string) any {
+ return a.values[name]
+}
+
+func (t Tag) String() string {
+ buf := bytes.NewBuffer(nil)
+ r := renderer{out: buf}
+ t()(r)
+ return buf.String()
+}
+
// defines a new tag with name and initial attributes and child nodes
func Define(name string, children ...any) Tag {
if handleQuery(name, children) {
@@ -86,7 +111,7 @@ func Doctype(children ...any) Tag {
}
func Comment(children ...any) Tag {
- return Inline(Declaration(append(append([]any{"--"}, children...), "--")))
+ return Inline(Declaration(append(append([]any{"--"}, children...), "--")...))
}
// returns the name of a tag
@@ -100,9 +125,11 @@ func Name(t Tag) string {
func AllAttributes(t Tag) Attributes {
q := attributesQuery{}
t()(&q)
- a := make(Attributes)
- for name, value := range q.value {
- a[name] = value
+ a := Attributes{values: make(map[string]any)}
+ for _, name := range q.value.names {
+ value := q.value.values[name]
+ a.names = append(a.names, name)
+ a.values[name] = value
}
return a
@@ -126,7 +153,14 @@ func DeleteAttribute(t Tag, name string) Tag {
n := Name(t)
a := AllAttributes(t)
c := Children(t)
- delete(a, name)
+ delete(a.values, name)
+ for i := range a.names {
+ if a.names[i] == name {
+ a.names = append(a.names[:i], a.names[i+1:]...)
+ break
+ }
+ }
+
return Define(n, append(c, a)...)
}
@@ -174,6 +208,10 @@ func Children(t Tag) []any {
return c
}
+func Indent() Indentation {
+ return Indentation{Indent: "\t"}
+}
+
// renders html with t as the root node with indentation
// child nodes are rendered via fmt.Sprint, tolerating fmt.Stringer implementations
// consecutive spaces are considered to be so on purpose, and are converted into
diff --git a/lib_test.go b/lib_test.go
index 4c4a98f..e6d4aa0 100644
--- a/lib_test.go
+++ b/lib_test.go
@@ -3,7 +3,7 @@ package html_test
import (
"bytes"
"code.squareroundforest.org/arpio/html"
- . "code.squareroundforest.org/arpio/html/tags"
+ . "code.squareroundforest.org/arpio/html/tag"
"code.squareroundforest.org/arpio/notation"
"testing"
)
@@ -58,7 +58,7 @@ func TestLib(t *testing.T) {
}
var b bytes.Buffer
- if err := html.RenderIndent(&b, html.Indentation{Indent: "\t"}, teamHTML(myTeam)); err != nil {
+ if err := html.RenderIndent(&b, html.Indent(), teamHTML(myTeam)); err != nil {
t.Fatal(err)
}
diff --git a/notes.txt b/notes.txt
index 60ba713..6e021bb 100644
--- a/notes.txt
+++ b/notes.txt
@@ -3,9 +3,4 @@ recommendation is not to mutate children. Ofc, creatively breaking the rules is
right audience
test wrapped templates
test empty block
-escape extra space between tag boundaries
-declarations:
-comments:
-render nil as empty
-support readers
review which tags should be of type inline-children
diff --git a/query.go b/query.go
index bfd1988..8e48cb5 100644
--- a/query.go
+++ b/query.go
@@ -53,13 +53,14 @@ func groupChildren(c []any) ([]Attributes, []any, []renderGuide) {
func mergeAttributes(c []any) Attributes {
a, _, _ := groupChildren(c)
if len(a) == 0 {
- return nil
+ return Attributes{}
}
- to := make(Attributes)
+ to := Attributes{values: make(map[string]any)}
for _, ai := range a {
- for name, value := range ai {
- to[name] = value
+ for _, name := range ai.names {
+ to.names = append(to.names, name)
+ to.values[name] = ai.values[name]
}
}
@@ -69,7 +70,7 @@ func mergeAttributes(c []any) Attributes {
func findAttribute(c []any, name string) (any, bool) {
a, _, _ := groupChildren(c)
for i := len(a) - 1; i >= 0; i-- {
- value, ok := a[i][name]
+ value, ok := a[i].values[name]
if ok {
return value, true
}
diff --git a/query_test.go b/query_test.go
index 047e029..3bccc47 100644
--- a/query_test.go
+++ b/query_test.go
@@ -3,7 +3,7 @@ package html_test
import (
"bytes"
"code.squareroundforest.org/arpio/html"
- . "code.squareroundforest.org/arpio/html/tags"
+ . "code.squareroundforest.org/arpio/html/tag"
"testing"
)
@@ -11,7 +11,7 @@ func TestQuery(t *testing.T) {
t.Run("group children", func(t *testing.T) {
inlineDiv := html.Inline(Div(Attr("foo", "bar"), "baz"))
attr := html.AllAttributes(inlineDiv)
- if len(attr) != 1 || attr["foo"] != "bar" {
+ if len(attr.Names()) != 1 || attr.Value("foo") != "bar" {
t.Fatal()
}
@@ -35,7 +35,7 @@ func TestQuery(t *testing.T) {
t.Run("has attributes", func(t *testing.T) {
div := Div(Attr("foo", "bar"))
attr := html.AllAttributes(div)
- if len(attr) != 1 || attr["foo"] != "bar" {
+ if len(attr.Names()) != 1 || attr.Value("foo") != "bar" {
t.Fatal()
}
})
@@ -43,7 +43,7 @@ func TestQuery(t *testing.T) {
t.Run("no attributes", func(t *testing.T) {
div := Div()
attr := html.AllAttributes(div)
- if len(attr) != 0 {
+ if len(attr.Names()) != 0 {
t.Fatal()
}
})
@@ -84,7 +84,7 @@ func TestQuery(t *testing.T) {
t.Run("all attributes", func(t *testing.T) {
div := Div(Attr("foo", "bar", "baz", "qux"))
attr := html.AllAttributes(div)
- if len(attr) != 2 || attr["foo"] != "bar" || attr["baz"] != "qux" {
+ if len(attr.Names()) != 2 || attr.Value("foo") != "bar" || attr.Value("baz") != "qux" {
t.Fatal()
}
})
@@ -109,7 +109,7 @@ func TestQuery(t *testing.T) {
div := Div(Span("foo"))
var b bytes.Buffer
- if err := html.RenderIndent(&b, html.Indentation{Indent: "\t"}, div); err != nil {
+ if err := html.RenderIndent(&b, html.Indent(), div); err != nil {
t.Fatal(err)
}
diff --git a/render.go b/render.go
index 3720640..9aa206c 100644
--- a/render.go
+++ b/render.go
@@ -3,6 +3,7 @@ package html
import (
"fmt"
"io"
+ "strings"
)
const defaultPWidth = 112
@@ -52,10 +53,24 @@ func (r *renderer) getPrintf(tagName string) func(f string, a ...any) {
func (r *renderer) renderAttributes(tagName string, a []Attributes) {
printf := r.getPrintf(tagName)
+ isDeclaration := strings.HasPrefix(tagName, "!")
for _, ai := range a {
- for name, value := range ai {
- if isTrue, _ := value.(bool); isTrue {
- printf(" &s", name)
+ for _, name := range ai.names {
+ value := ai.values[name]
+ isTrue, _ := value.(bool)
+ if isTrue && isDeclaration {
+ escaped := attributeEscape(name)
+ if escaped == name {
+ printf(" %s", name)
+ continue
+ }
+
+ printf(" \"%s\"", escaped)
+ continue
+ }
+
+ if isTrue {
+ printf(" %s", name)
continue
}
@@ -91,7 +106,7 @@ func (r *renderer) renderUnindented(name string, rg renderGuide, a []Attributes,
ew := newEscapeWriter(r.out)
_, r.err = io.Copy(ew, rd)
- if r.err != nil {
+ if r.err == nil {
ew.Flush()
r.err = ew.err
}
@@ -165,7 +180,6 @@ func (r *renderer) renderInline(name string, rg renderGuide, a []Attributes, chi
if r.err == nil {
iw := newIndentWriter(r.out, r.currentIndent+r.indent.Indent)
iw.Write([]byte{'\n'})
- iw.Write([]byte(r.currentIndent + r.indent.Indent))
_, r.err = io.Copy(iw, rd)
if r.err == nil {
iw.Flush()
@@ -222,7 +236,6 @@ func (r *renderer) renderInline(name string, rg renderGuide, a []Attributes, chi
if r.err == nil {
iw := newIndentWriter(r.out, r.currentIndent+r.indent.Indent)
iw.Write([]byte{'\n'})
- iw.Write([]byte(r.currentIndent + r.indent.Indent))
iw.Write([]byte(s))
iw.Flush()
r.err = iw.err
@@ -298,7 +311,7 @@ func (r *renderer) renderInline(name string, rg renderGuide, a []Attributes, chi
cr := new(renderer)
*cr = *r
cr.currentIndent += cr.indent.Indent
- cr.pwidth -= len([]rune(cr.indent.Indent))
+ cr.pwidth -= indentLen(cr.indent.Indent)
if cr.pwidth < cr.indent.MinPWidth {
cr.pwidth = cr.indent.MinPWidth
}
@@ -339,7 +352,7 @@ func (r *renderer) renderBlock(name string, rg renderGuide, a []Attributes, chil
lastBlock := true
originalIndent, originalWidth := r.currentIndent, r.pwidth
r.currentIndent += r.indent.Indent
- r.pwidth -= len([]rune(r.indent.Indent))
+ r.pwidth -= indentLen(r.indent.Indent)
if r.pwidth < r.indent.MinPWidth {
r.pwidth = r.indent.MinPWidth
}
@@ -348,11 +361,9 @@ func (r *renderer) renderBlock(name string, rg renderGuide, a []Attributes, chil
rd, isReader := c.(io.Reader)
if isReader && rg.verbatim {
r.clearWrapper()
- printf("\n")
if r.err == nil {
- iw := newIndentWriter(r.out, r.currentIndent+r.indent.Indent)
+ iw := newIndentWriter(r.out, r.currentIndent)
iw.Write([]byte{'\n'})
- iw.Write([]byte(r.currentIndent + r.indent.Indent))
_, r.err = io.Copy(iw, rd)
if r.err == nil {
iw.Flush()
@@ -406,7 +417,6 @@ func (r *renderer) renderBlock(name string, rg renderGuide, a []Attributes, chil
if r.err == nil {
iw := newIndentWriter(r.out, r.currentIndent)
iw.Write([]byte{'\n'})
- iw.Write([]byte(r.currentIndent + r.indent.Indent))
iw.Write([]byte(s))
iw.Flush()
r.err = iw.err
diff --git a/render_test.go b/render_test.go
index 478384e..0d5b849 100644
--- a/render_test.go
+++ b/render_test.go
@@ -3,36 +3,18 @@ package html_test
import (
"bytes"
"code.squareroundforest.org/arpio/html"
- . "code.squareroundforest.org/arpio/html/tags"
- "errors"
+ . "code.squareroundforest.org/arpio/html/tag"
"strings"
"testing"
)
-type failingWriter struct {
- after int
-}
-
-func failWriteAfter(n int) *failingWriter {
- return &failingWriter{n}
-}
-
-func (w *failingWriter) Write(p []byte) (int, error) {
- w.after -= len(p)
- if w.after < 0 {
- return len(p) + w.after, errors.New("test error")
- }
-
- return len(p), nil
-}
-
func TestRender(t *testing.T) {
t.Run("merge render guides", func(t *testing.T) {
foo := html.Inline(html.Verbatim(Define("foo")))
foo = foo("")
var b bytes.Buffer
- if err := html.RenderIndent(&b, html.Indentation{Indent: "\t"}, foo); err != nil {
+ if err := html.RenderIndent(&b, html.Indent(), foo); err != nil {
t.Fatal(err)
}
@@ -41,17 +23,45 @@ func TestRender(t *testing.T) {
}
})
- t.Run("attribute escaping", func(t *testing.T) {
- span := Span(Attr("foo", "bar=\"&\""))
+ t.Run("attributes", func(t *testing.T) {
+ t.Run("escaping", func(t *testing.T) {
+ span := Span(Attr("foo", "bar=\"&\""))
- var b bytes.Buffer
- if err := html.Render(&b, span); err != nil {
- t.Fatal(err)
- }
+ var b bytes.Buffer
+ if err := html.Render(&b, span); err != nil {
+ t.Fatal(err)
+ }
- if b.String() != "" {
- t.Fatal(b.String())
- }
+ if b.String() != "" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("true form", func(t *testing.T) {
+ span := Span(Attr("foo", true))
+
+ var b bytes.Buffer
+ if err := html.Render(&b, span); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("declaration", func(t *testing.T) {
+ comment := Comment("foo & bar & baz", "qux")
+
+ var b bytes.Buffer
+ if err := html.Render(&b, comment); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "" {
+ t.Fatal(b.String())
+ }
+ })
})
t.Run("html escape", func(t *testing.T) {
@@ -85,32 +95,32 @@ func TestRender(t *testing.T) {
t.Run("write error", func(t *testing.T) {
t.Run("fail immediately", func(t *testing.T) {
div := Div(Span("foo"))
- w := failWriteAfter(0)
- if err := html.Render(w, div); err == nil || !strings.Contains(err.Error(), "test error") {
+ w := &errorWriter{}
+ if err := html.Render(w, div); err == nil || !strings.Contains(err.Error(), "test write error") {
t.Fatal()
}
})
t.Run("fail in tag", func(t *testing.T) {
div := Div(Span("foo"))
- w := failWriteAfter(6)
- if err := html.Render(w, div); err == nil || !strings.Contains(err.Error(), "test error") {
+ w := &errorWriter{failAfter: 6}
+ if err := html.Render(w, div); err == nil || !strings.Contains(err.Error(), "test write error") {
t.Fatal()
}
})
t.Run("partial text children", func(t *testing.T) {
div := Div("foo", Div("bar"), "baz")
- w := failWriteAfter(5)
- if err := html.RenderIndent(w, html.Indentation{Indent: "\t"}, div); err == nil || !strings.Contains(err.Error(), "test error") {
+ w := &errorWriter{failAfter: 5}
+ if err := html.RenderIndent(w, html.Indent(), div); err == nil || !strings.Contains(err.Error(), "test write error") {
t.Fatal()
}
})
t.Run("text children", func(t *testing.T) {
div := Div("foo", "bar", "baz")
- w := failWriteAfter(5)
- if err := html.RenderIndent(w, html.Indentation{Indent: "\t"}, div); err == nil || !strings.Contains(err.Error(), "test error") {
+ w := &errorWriter{failAfter: 5}
+ if err := html.RenderIndent(w, html.Indent(), div); err == nil || !strings.Contains(err.Error(), "test write error") {
t.Fatal()
}
})
@@ -121,7 +131,7 @@ func TestRender(t *testing.T) {
div := Div(Span("foo"))
var b bytes.Buffer
- if err := html.RenderIndent(&b, html.Indentation{Indent: "\t"}, div); err != nil {
+ if err := html.RenderIndent(&b, html.Indent(), div); err != nil {
t.Fatal(err)
}
@@ -131,10 +141,10 @@ func TestRender(t *testing.T) {
})
t.Run("empty tag", func(t *testing.T) {
- div := Div(Br())
+ div := Div(Br)
var b bytes.Buffer
- if err := html.RenderIndent(&b, html.Indentation{Indent: "\t"}, div); err != nil {
+ if err := html.RenderIndent(&b, html.Indent(), div); err != nil {
t.Fatal(err)
}
@@ -147,7 +157,7 @@ func TestRender(t *testing.T) {
div := Div("foo bar baz", Div("qux quux"), "corge")
var b bytes.Buffer
- if err := html.RenderIndent(&b, html.Indentation{Indent: "\t"}, div); err != nil {
+ if err := html.RenderIndent(&b, html.Indent(), div); err != nil {
t.Fatal(err)
}
@@ -160,13 +170,823 @@ func TestRender(t *testing.T) {
div := Div(Span("foo bar baz", Div("qux quux"), "corge"))
var b bytes.Buffer
- if err := html.RenderIndent(&b, html.Indentation{Indent: "XYZ"}, div); err != nil {
+ if err := html.RenderIndent(&b, html.Indent(), div); err != nil {
t.Fatal(err)
}
- if b.String() != "\nXYZ
foo bar baz\nXYZXYZ\nXYZXYZXYZqux quux\nXYZXYZ
\nXYZcorge\n
" {
+ if b.String() != "\n\t
foo bar baz\n\t\t\n\t\t\tqux quux\n\t\t
\n\tcorge\n
" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("verbatim", func(t *testing.T) {
+ foo := html.Verbatim(Define("foo"))
+ foo = foo("bar\nbaz\nqux")
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), foo); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "\n\tbar\n\tbaz\n\tqux\n" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("script not indented", func(t *testing.T) {
+ script := Div(Script("foo()\nbar()\nbaz()"))
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), script); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "\n\t\n
" {
t.Fatal(b.String())
}
})
})
+
+ t.Run("simple", func(t *testing.T) {
+ t.Run("unindented", func(t *testing.T) {
+ div := Div("foo")
+
+ var b bytes.Buffer
+ if err := html.Render(&b, div); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "foo
" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("unindented number", func(t *testing.T) {
+ div := Div(42)
+
+ var b bytes.Buffer
+ if err := html.Render(&b, div); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "42
" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("unindented after block", func(t *testing.T) {
+ div := Div(Div, "foo")
+
+ var b bytes.Buffer
+ if err := html.Render(&b, div); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("unindented after inline", func(t *testing.T) {
+ div := Div(Span, "foo")
+
+ var b bytes.Buffer
+ if err := html.Render(&b, div); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "foo
" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("inline", func(t *testing.T) {
+ span := Span("foo")
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), span); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "foo" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("inline number", func(t *testing.T) {
+ span := Span(42)
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), span); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "42" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("inline after block", func(t *testing.T) {
+ span := Span(Div, "foo")
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), span); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "\n\t\nfoo" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("inline after inline", func(t *testing.T) {
+ span := Span(Span, "foo")
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), span); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "foo" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("inline tag after block", func(t *testing.T) {
+ span := Span(Div, Span("foo"))
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), span); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "\n\t\nfoo" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("inline children", func(t *testing.T) {
+ p := P("foo")
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), p); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "foo
" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("inline children number", func(t *testing.T) {
+ p := P(42)
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), p); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "42
" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("inline children after inline children", func(t *testing.T) {
+ p := P(P, "foo")
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), p); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "\n\t
\nfoo
" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("block", func(t *testing.T) {
+ div := Div("foo")
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), div); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "\n\tfoo\n
" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("block number", func(t *testing.T) {
+ div := Div(42)
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), div); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "\n\t42\n
" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("block after block", func(t *testing.T) {
+ div := Div(Div, 42)
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), div); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("block after inline", func(t *testing.T) {
+ div := Div(Span, 42)
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), div); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "\n\t42\n
" {
+ t.Fatal(b.String())
+ }
+ })
+ })
+
+ t.Run("nil child", func(t *testing.T) {
+ t.Run("unindented", func(t *testing.T) {
+ div := Div("foo", nil, "bar")
+
+ var b bytes.Buffer
+ if err := html.Render(&b, div); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "foobar
" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("unindented verbatim", func(t *testing.T) {
+ div := html.Verbatim(Div("foo &", nil, " bar"))
+
+ var b bytes.Buffer
+ if err := html.Render(&b, div); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "foo & bar
" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("unindented script", func(t *testing.T) {
+ script := Script("let foo =", nil, " bar && baz")
+
+ var b bytes.Buffer
+ if err := html.Render(&b, script); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("inline", func(t *testing.T) {
+ span := Span("foo", nil, "bar")
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), span); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "foobar" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("inline verbatim", func(t *testing.T) {
+ span := html.Verbatim(Span("foo &", nil, " bar"))
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), span); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "\n\tfoo &\n\t bar\n" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("inline script", func(t *testing.T) {
+ script := html.Inline(Script("let foo =", nil, " bar && baz"))
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), script); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("block", func(t *testing.T) {
+ div := Div("foo", nil, "bar")
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), div); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "\n\tfoobar\n
" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("block verbatim", func(t *testing.T) {
+ div := html.Verbatim(Div("foo &", nil, " bar"))
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), div); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "\n\tfoo &\n\t bar\n
" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("block script", func(t *testing.T) {
+ script := Script("let foo =", nil, " bar && baz")
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), script); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "" {
+ t.Fatal(b.String())
+ }
+ })
+ })
+
+ t.Run("empty child", func(t *testing.T) {
+ t.Run("unindented", func(t *testing.T) {
+ div := Div("foo", "", "bar")
+
+ var b bytes.Buffer
+ if err := html.Render(&b, div); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "foobar
" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("unindented verbatim", func(t *testing.T) {
+ div := html.Verbatim(Div("foo &", "", " bar"))
+
+ var b bytes.Buffer
+ if err := html.Render(&b, div); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "foo & bar
" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("unindented script", func(t *testing.T) {
+ script := Script("let foo =", "", " bar && baz")
+
+ var b bytes.Buffer
+ if err := html.Render(&b, script); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("inline", func(t *testing.T) {
+ span := Span("foo", "", "bar")
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), span); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "foobar" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("inline verbatim", func(t *testing.T) {
+ span := html.Verbatim(Span("foo &", "", " bar"))
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), span); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "\n\tfoo &\n\t bar\n" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("inline script", func(t *testing.T) {
+ script := html.Inline(Script("let foo =", "", " bar && baz"))
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), script); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("block", func(t *testing.T) {
+ div := Div("foo", "", "bar")
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), div); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "\n\tfoobar\n
" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("block verbatim", func(t *testing.T) {
+ div := html.Verbatim(Div("foo &", "", " bar"))
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), div); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "\n\tfoo &\n\t bar\n
" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("block script", func(t *testing.T) {
+ script := Script("let foo =", "", " bar && baz")
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), script); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "" {
+ t.Fatal(b.String())
+ }
+ })
+ })
+
+ t.Run("reader child", func(t *testing.T) {
+ t.Run("unindented", func(t *testing.T) {
+ rd := bytes.NewBufferString("foo & bar & baz")
+ div := Div(rd)
+
+ var b bytes.Buffer
+ if err := html.Render(&b, div); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "foo & bar & baz
" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("unindented verbatim", func(t *testing.T) {
+ rd := bytes.NewBufferString("foo & bar & baz")
+ div := html.Verbatim(Div(rd))
+
+ var b bytes.Buffer
+ if err := html.Render(&b, div); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "foo & bar & baz
" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("unindented script", func(t *testing.T) {
+ rd := bytes.NewBufferString("let foo = bar() && baz()")
+ script := Script(rd)
+
+ var b bytes.Buffer
+ if err := html.Render(&b, script); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("inline", func(t *testing.T) {
+ rd := bytes.NewBufferString("foo & bar & baz")
+ span := Span(rd)
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), span); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "foo & bar & baz" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("inline verbatim", func(t *testing.T) {
+ rd := bytes.NewBufferString("foo & bar & baz")
+ span := html.Verbatim(Span(rd))
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), span); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "\n\tfoo & bar & baz\n" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("inline script", func(t *testing.T) {
+ rd := bytes.NewBufferString("let foo = bar() && baz()")
+ script := html.Inline(Script(rd))
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), script); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("inline after block", func(t *testing.T) {
+ rd := bytes.NewBufferString("foo & bar & baz")
+ span := Span(Div, rd)
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), span); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "\n\t\nfoo & bar & baz" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("block", func(t *testing.T) {
+ rd := bytes.NewBufferString("foo & bar & baz")
+ div := Div(rd)
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), div); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "\n\tfoo & bar & baz\n
" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("block verbatim", func(t *testing.T) {
+ rd := bytes.NewBufferString("foo & bar & baz")
+ div := html.Verbatim(Div(rd))
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), div); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "\n\tfoo & bar & baz\n
" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("block script", func(t *testing.T) {
+ rd := bytes.NewBufferString("let foo = bar() && baz()")
+ script := Script(rd)
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), script); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "" {
+ t.Fatal(b.String())
+ }
+ })
+ })
+
+ t.Run("void", func(t *testing.T) {
+ t.Run("unindented", func(t *testing.T) {
+ var b bytes.Buffer
+ if err := html.Render(&b, Br); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "
" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("inline", func(t *testing.T) {
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), Br); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "
" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("block", func(t *testing.T) {
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), Hr); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "
" {
+ t.Fatal(b.String())
+ }
+ })
+ })
+
+ t.Run("no children", func(t *testing.T) {
+ t.Run("unindented", func(t *testing.T) {
+ var b bytes.Buffer
+ if err := html.Render(&b, Div); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("inline", func(t *testing.T) {
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), Span); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("block", func(t *testing.T) {
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), Div); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "" {
+ t.Fatal(b.String())
+ }
+ })
+ })
+
+ t.Run("verbatim", func(t *testing.T) {
+ t.Run("unindented", func(t *testing.T) {
+ div := html.Verbatim(Div("foo & bar"))
+
+ var b bytes.Buffer
+ if err := html.Render(&b, div); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "foo & bar
" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("inline", func(t *testing.T) {
+ span := html.Verbatim(Span("foo & bar"))
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), span); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "\n\tfoo & bar\n" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("block", func(t *testing.T) {
+ div := html.Verbatim(Div("foo & bar"))
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), div); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "\n\tfoo & bar\n
" {
+ t.Fatal(b.String())
+ }
+ })
+ })
+
+ t.Run("script", func(t *testing.T) {
+ t.Run("unindented", func(t *testing.T) {
+ script := Script("let foo = bar && baz")
+
+ var b bytes.Buffer
+ if err := html.Render(&b, script); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("inline", func(t *testing.T) {
+ script := html.Inline(Script("let foo = bar && baz"))
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), script); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "" {
+ t.Fatal(b.String())
+ }
+ })
+
+ t.Run("block", func(t *testing.T) {
+ script := Script("let foo = bar && baz")
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indent(), script); err != nil {
+ t.Fatal(err)
+ }
+
+ if b.String() != "" {
+ t.Fatal(b.String())
+ }
+ })
+ })
+
+ t.Run("wrap", func(t *testing.T) {
+ t.Run("simple", func(t *testing.T) {
+ p := P("foo bar baz qux quux corge")
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indentation{Indent: "\t", PWidth: 15}, p); err != nil {
+ t.Error(err)
+ }
+
+ if b.String() != "foo bar baz\nqux quux corge\n
" {
+ t.Error(b.String())
+ }
+ })
+
+ t.Run("min width", func(t *testing.T) {
+ div := Div(P("foo bar baz qux quux corge"))
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indentation{Indent: "\t", PWidth: 21, MinPWidth: 18}, div); err != nil {
+ t.Error(err)
+ }
+
+ if b.String() != "\n\t
foo bar baz qux\n\tquux corge
\n
" {
+ t.Error(b.String())
+ }
+ })
+
+ t.Run("min width inline", func(t *testing.T) {
+ span := Span(P("foo bar baz qux quux corge"))
+
+ var b bytes.Buffer
+ if err := html.RenderIndent(&b, html.Indentation{Indent: "\t", PWidth: 21, MinPWidth: 18}, span); err != nil {
+ t.Error(err)
+ }
+
+ if b.String() != "\n\tfoo bar baz qux\n\tquux corge
\n" {
+ t.Error(b.String())
+ }
+ })
+ })
}
diff --git a/script/generate-tags.go b/script/generate-tags.go
index 78a2621..24eae8c 100644
--- a/script/generate-tags.go
+++ b/script/generate-tags.go
@@ -47,7 +47,7 @@ func main() {
printf("// generated by ../script/generate-tags.go\n")
printf("\n")
- printf("package tags\n")
+ printf("package tag\n")
printf("import \"code.squareroundforest.org/arpio/html\"\n")
for _, si := range ss {
exp := fmt.Sprintf("html.Define(\"%s\")", si)
diff --git a/script/promote-to-tags.go b/script/promote-to-tags.go
index ec733de..c3dd1a6 100644
--- a/script/promote-to-tags.go
+++ b/script/promote-to-tags.go
@@ -46,7 +46,7 @@ func main() {
printf("// generated by ../script/promote-to-tags.go\n")
printf("\n")
- printf("package tags\n")
+ printf("package tag\n")
printf("import \"code.squareroundforest.org/arpio/html\"\n")
for _, si := range ss {
printf("var %s = html.%s\n", si, si)
diff --git a/tags.block.txt b/tag.block.txt
similarity index 100%
rename from tags.block.txt
rename to tag.block.txt
diff --git a/tags.inline.txt b/tag.inline.txt
similarity index 100%
rename from tags.inline.txt
rename to tag.inline.txt
diff --git a/tags.inlinechildren.txt b/tag.inlinechildren.txt
similarity index 100%
rename from tags.inlinechildren.txt
rename to tag.inlinechildren.txt
diff --git a/tags.script.txt b/tag.script.txt
similarity index 100%
rename from tags.script.txt
rename to tag.script.txt
diff --git a/tags.void.block.txt b/tag.void.block.txt
similarity index 100%
rename from tags.void.block.txt
rename to tag.void.block.txt
diff --git a/tags.void.inline.txt b/tag.void.inline.txt
similarity index 100%
rename from tags.void.inline.txt
rename to tag.void.inline.txt
diff --git a/tags/block.gen.go b/tag/block.gen.go
similarity index 99%
rename from tags/block.gen.go
rename to tag/block.gen.go
index b94b0aa..9fcb837 100644
--- a/tags/block.gen.go
+++ b/tag/block.gen.go
@@ -1,6 +1,6 @@
// generated by ../script/generate-tags.go
-package tags
+package tag
import "code.squareroundforest.org/arpio/html"
diff --git a/tags/inline.gen.go b/tag/inline.gen.go
similarity index 99%
rename from tags/inline.gen.go
rename to tag/inline.gen.go
index 6d84356..a2d538a 100644
--- a/tags/inline.gen.go
+++ b/tag/inline.gen.go
@@ -1,6 +1,6 @@
// generated by ../script/generate-tags.go
-package tags
+package tag
import "code.squareroundforest.org/arpio/html"
diff --git a/tags/inlinechildren.gen.go b/tag/inlinechildren.gen.go
similarity index 97%
rename from tags/inlinechildren.gen.go
rename to tag/inlinechildren.gen.go
index 0b0a993..911c1a3 100644
--- a/tags/inlinechildren.gen.go
+++ b/tag/inlinechildren.gen.go
@@ -1,6 +1,6 @@
// generated by ../script/generate-tags.go
-package tags
+package tag
import "code.squareroundforest.org/arpio/html"
diff --git a/tags/promote.gen.go b/tag/promote.gen.go
similarity index 93%
rename from tags/promote.gen.go
rename to tag/promote.gen.go
index 3893eb2..ee4d67f 100644
--- a/tags/promote.gen.go
+++ b/tag/promote.gen.go
@@ -1,6 +1,6 @@
// generated by ../script/promote-to-tags.go
-package tags
+package tag
import "code.squareroundforest.org/arpio/html"
diff --git a/tags/script.gen.go b/tag/script.gen.go
similarity index 93%
rename from tags/script.gen.go
rename to tag/script.gen.go
index cec0a0d..3a520c6 100644
--- a/tags/script.gen.go
+++ b/tag/script.gen.go
@@ -1,6 +1,6 @@
// generated by ../script/generate-tags.go
-package tags
+package tag
import "code.squareroundforest.org/arpio/html"
diff --git a/tags/void.block.gen.go b/tag/void.block.gen.go
similarity index 96%
rename from tags/void.block.gen.go
rename to tag/void.block.gen.go
index 9ced5c0..3a874e4 100644
--- a/tags/void.block.gen.go
+++ b/tag/void.block.gen.go
@@ -1,6 +1,6 @@
// generated by ../script/generate-tags.go
-package tags
+package tag
import "code.squareroundforest.org/arpio/html"
diff --git a/tags/void.inline.gen.go b/tag/void.inline.gen.go
similarity index 96%
rename from tags/void.inline.gen.go
rename to tag/void.inline.gen.go
index 816cc45..ac2b751 100644
--- a/tags/void.inline.gen.go
+++ b/tag/void.inline.gen.go
@@ -1,6 +1,6 @@
// generated by ../script/generate-tags.go
-package tags
+package tag
import "code.squareroundforest.org/arpio/html"
diff --git a/validate.go b/validate.go
index 46906b0..208d130 100644
--- a/validate.go
+++ b/validate.go
@@ -21,6 +21,10 @@ func validateSymbol(s string) error {
}
func validateTagName(name string) error {
+ if strings.HasPrefix(name, "!") {
+ return nil
+ }
+
return validateSymbol(name)
}
@@ -41,7 +45,7 @@ func validate(name string, children []any) error {
isDeclaration := strings.HasPrefix(name, "!")
for _, ai := range a {
- for name := range ai {
+ for _, name := range ai.names {
if isDeclaration {
continue
}
diff --git a/validate_test.go b/validate_test.go
index ddc3949..b5981c5 100644
--- a/validate_test.go
+++ b/validate_test.go
@@ -3,7 +3,7 @@ package html_test
import (
"bytes"
"code.squareroundforest.org/arpio/html"
- . "code.squareroundforest.org/arpio/html/tags"
+ . "code.squareroundforest.org/arpio/html/tag"
"testing"
)
diff --git a/wrap.go b/wrap.go
index 6052b4e..523f4d8 100644
--- a/wrap.go
+++ b/wrap.go
@@ -8,11 +8,12 @@ import (
)
type wrapper struct {
- out *indentWriter
- width int
- line, word *bytes.Buffer
- inWord, inTag, inSingleQuote, inQuote, lastSpace, started bool
- err error
+ out *indentWriter
+ width int
+ line, word *bytes.Buffer
+ inWord, inTag, inSingleQuote, inQuote bool
+ lastSpace, started bool
+ err error
}
func newWrapper(out io.Writer, width int, indent string) *wrapper {
diff --git a/wrap_test.go b/wrap_test.go
index 3c7d7c5..d97f6d9 100644
--- a/wrap_test.go
+++ b/wrap_test.go
@@ -3,7 +3,7 @@ package html_test
import (
"bytes"
"code.squareroundforest.org/arpio/html"
- . "code.squareroundforest.org/arpio/html/tags"
+ . "code.squareroundforest.org/arpio/html/tag"
"testing"
)
@@ -56,7 +56,7 @@ func TestWrap(t *testing.T) {
ew := &errorWriter{}
if err := html.RenderIndent(
ew,
- html.Indentation{Indent: "\t"},
+ html.Indent(),
Span(Span("foo"), Span("bar"), Span("baz")),
); err == nil {
t.Fatal()
@@ -117,7 +117,7 @@ func TestWrap(t *testing.T) {
div := Div(Span("foo bar baz qux quux corge"))
var buf bytes.Buffer
- if err := html.RenderIndent(&buf, html.Indentation{Indent: "\t", PWidth: 9}, div); err != nil {
+ if err := html.RenderIndent(&buf, html.Indentation{Indent: "\t", PWidth: 15}, div); err != nil {
t.Fatal(err)
}
@@ -130,7 +130,7 @@ func TestWrap(t *testing.T) {
div := Div(Span("foo"), " ", Span("bar"))
var buf bytes.Buffer
- if err := html.RenderIndent(&buf, html.Indentation{Indent: "\t"}, div); err != nil {
+ if err := html.RenderIndent(&buf, html.Indent(), div); err != nil {
t.Fatal(err)
}
@@ -143,7 +143,7 @@ func TestWrap(t *testing.T) {
div := Div("foo\nbar\tbaz")
var buf bytes.Buffer
- if err := html.RenderIndent(&buf, html.Indentation{Indent: "\t"}, div); err != nil {
+ if err := html.RenderIndent(&buf, html.Indent(), div); err != nil {
t.Fatal(err)
}