From acda6dbd2472ce9525602fe0036b4db9fc89f3e7 Mon Sep 17 00:00:00 2001 From: "Gustavo \"Guz\" L de Mello" Date: Mon, 26 May 2025 09:28:20 -0300 Subject: [PATCH] feat(ast,ipub): remove marshalling and unmarshalling logic from ast --- ipub/ast/ast.go | 224 +++++++++----------------------------------- ipub/ast/content.go | 53 ++--------- ipub/ast/errors.go | 36 ------- ipub/ast/package.go | 11 +++ ipub/ast/section.go | 18 +--- 5 files changed, 64 insertions(+), 278 deletions(-) delete mode 100644 ipub/ast/errors.go create mode 100644 ipub/ast/package.go diff --git a/ipub/ast/ast.go b/ipub/ast/ast.go index b5813ca..3b49631 100644 --- a/ipub/ast/ast.go +++ b/ipub/ast/ast.go @@ -1,95 +1,87 @@ package ast import ( - "encoding/xml" - "errors" "fmt" - "io" - "slices" ) -type Element interface { - Name() ElementName - Kind() ElementKind +type Node interface { + Kind() NodeKind - NextSibling() Element - SetNextSibling(Element) + NextSibling() Node + SetNextSibling(Node) - PreviousSibling() Element - SetPreviousSibling(Element) + PreviousSibling() Node + SetPreviousSibling(Node) - Parent() Element - SetParent(Element) + Parent() Node + SetParent(Node) HasChildren() bool ChildCount() uint - FirstChild() Element - LastChild() Element + FirstChild() Node + LastChild() Node - AppendChild(self, v Element) - RemoveChild(self, v Element) + AppendChild(self, v Node) + RemoveChild(self, v Node) - RemoveChildren(self Element) - ReplaceChild(self, v1, insertee Element) + RemoveChildren(self Node) + ReplaceChild(self, v1, insertee Node) - InsertBefore(self, v1, insertee Element) - InsertAfter(self, v1, insertee Element) - - xml.Marshaler - xml.Unmarshaler + InsertBefore(self, v1, insertee Node) + InsertAfter(self, v1, insertee Node) } -type BaseElement struct { - next Element - prev Element - parent Element - fisrtChild Element - lastChild Element +type BaseNode struct { + next Node + prev Node + parent Node + fisrtChild Node + lastChild Node childCount uint } -func (e *BaseElement) NextSibling() Element { +func (e *BaseNode) NextSibling() Node { return e.next } -func (e *BaseElement) SetNextSibling(v Element) { +func (e *BaseNode) SetNextSibling(v Node) { e.next = v } -func (e *BaseElement) PreviousSibling() Element { +func (e *BaseNode) PreviousSibling() Node { return e.prev } -func (e *BaseElement) SetPreviousSibling(v Element) { +func (e *BaseNode) SetPreviousSibling(v Node) { e.prev = v } -func (e *BaseElement) Parent() Element { +func (e *BaseNode) Parent() Node { return e.parent } -func (e *BaseElement) SetParent(v Element) { +func (e *BaseNode) SetParent(v Node) { e.parent = v } -func (e *BaseElement) HasChildren() bool { +func (e *BaseNode) HasChildren() bool { return e.fisrtChild != nil } -func (e *BaseElement) ChildCount() uint { +func (e *BaseNode) ChildCount() uint { return e.childCount } -func (e *BaseElement) FirstChild() Element { +func (e *BaseNode) FirstChild() Node { return e.fisrtChild } -func (e *BaseElement) LastChild() Element { +func (e *BaseNode) LastChild() Node { return e.lastChild } -func (e *BaseElement) AppendChild(self, v Element) { +func (e *BaseNode) AppendChild(self, v Node) { ensureIsolated(v) if e.fisrtChild == nil { @@ -107,7 +99,7 @@ func (e *BaseElement) AppendChild(self, v Element) { e.childCount++ } -func (e *BaseElement) RemoveChild(self, v Element) { +func (e *BaseNode) RemoveChild(self, v Node) { if v.Parent() != self { return } @@ -136,7 +128,7 @@ func (e *BaseElement) RemoveChild(self, v Element) { v.SetPreviousSibling(nil) } -func (e *BaseElement) RemoveChildren(_ Element) { +func (e *BaseNode) RemoveChildren(_ Node) { for c := e.fisrtChild; c != nil; { c.SetParent(nil) c.SetPreviousSibling(nil) @@ -149,16 +141,16 @@ func (e *BaseElement) RemoveChildren(_ Element) { e.childCount = 0 } -func (e *BaseElement) ReplaceChild(self, v1, insertee Element) { +func (e *BaseNode) ReplaceChild(self, v1, insertee Node) { e.InsertBefore(self, v1, insertee) e.RemoveChild(self, v1) } -func (e *BaseElement) InsertAfter(self, v1, insertee Element) { +func (e *BaseNode) InsertAfter(self, v1, insertee Node) { e.InsertBefore(self, v1.NextSibling(), insertee) } -func (e *BaseElement) InsertBefore(self, v1, insertee Element) { +func (e *BaseNode) InsertBefore(self, v1, insertee Node) { e.childCount++ if v1 == nil { e.AppendChild(self, insertee) @@ -183,149 +175,21 @@ func (e *BaseElement) InsertBefore(self, v1, insertee Element) { } } -func (e *BaseElement) UnmarshalXMLElement(self Element, d *xml.Decoder, start xml.StartElement) error { - elErr := fmt.Errorf("unable to unmarshal element kind %q", self.Kind()) - - if n := self.Name(); n != (xml.Name{}) { - if n != start.Name { - return errors.Join( - elErr, - fmt.Errorf("element has different name (%q) than expected (%q)", - fmtXMLName(start.Name), fmtXMLName(n)), - ) - } - } - - for { - token, err := d.Token() - if err != nil { - return err - } - if err == io.EOF { - return nil - } - - switch tt := token.(type) { - case xml.StartElement: - elErr = errors.Join(elErr, fmt.Errorf("unable to unmarshal child element %q", fmtXMLName(tt.Name))) - - i := slices.IndexFunc(tt.Attr, func(a xml.Attr) bool { - return a.Name == elementKindAttrName - }) - if i == -1 { - return errors.Join(elErr, fmt.Errorf("element kind not specified")) - } - - var k ElementKind - if err := k.UnmarshalXMLAttr(tt.Attr[i]); err != nil { - return errors.Join(elErr, err) - } - - c := k.Element() - - err := d.DecodeElement(c, &tt) - if err != nil && err != io.EOF { - return err - } - - e.AppendChild(self, c) - } - } -} - -func (e *BaseElement) MarshalXMLElement(self Element, enc *xml.Encoder, start xml.StartElement) error { - elErr := fmt.Errorf("unable to marshal element kind %q", self.Kind()) - - if n := self.Name(); n != (xml.Name{}) { - start.Name = self.Name() - } - - ka, err := self.Kind().MarshalXMLAttr(elementKindAttrName) - if err != nil { - return errors.Join(elErr, err) - } - - start.Attr = append(start.Attr, ka) - - data := struct { - Children []Element `xml:",any"` - }{Children: []Element{}} - - for c := self.FirstChild(); c != nil; { - data.Children = append(data.Children, c) - c = c.NextSibling() - } - - err = enc.EncodeElement(&data, start) - if err != nil && err != io.EOF { - return err - return errors.Join(elErr, err) - } - - return nil -} - -func ensureIsolated(e Element) { +func ensureIsolated(e Node) { if p := e.Parent(); p != nil { p.RemoveChild(p, e) } } -type ( - ElementName = xml.Name - ElementKind string -) +type NodeKind string -func NewElementKind(kind string, e Element) ElementKind { - k := ElementKind(kind) +func NewNodeKind(kind string, e Node) NodeKind { + k := NodeKind(kind) if _, ok := elementKindList[k]; ok { - panic(fmt.Sprintf("Element kind %q is already registered", k)) + panic(fmt.Sprintf("Node kind %q is already registered", k)) } elementKindList[k] = e return k } -var ( - _ xml.MarshalerAttr = ElementKind("") - _ xml.UnmarshalerAttr = (*ElementKind)(nil) - _ fmt.Stringer = ElementKind("") -) - -func (k ElementKind) MarshalXMLAttr(n xml.Name) (xml.Attr, error) { - if n != elementKindAttrName { - return xml.Attr{}, ErrInvalidAttrName{Actual: n, Expected: elementKindAttrName} - } - - return xml.Attr{ - Name: elementKindAttrName, - Value: k.String(), - }, nil -} - -func (k *ElementKind) UnmarshalXMLAttr(attr xml.Attr) error { - if attr.Name != elementKindAttrName { - return ErrInvalidAttrName{Actual: attr.Name, Expected: elementKindAttrName} - } - - ak := ElementKind(attr.Value) - if _, ok := elementKindList[ak]; !ok { - return ErrInvalidAttrValue{Attr: attr, Message: "element kind not registered"} - } - - *k = ak - - return nil -} - -func (k ElementKind) String() string { - return string(k) -} - -func (k ElementKind) Element() Element { - return elementKindList[k] -} - -var ( - elementKindList = make(map[ElementKind]Element) - elementKindAttrName = xml.Name{Local: "data-ipub-element"} -) +var elementKindList = make(map[NodeKind]Node) diff --git a/ipub/ast/content.go b/ipub/ast/content.go index 37d291c..ec8b9c1 100644 --- a/ipub/ast/content.go +++ b/ipub/ast/content.go @@ -1,68 +1,27 @@ package ast -import ( - "encoding/xml" - "slices" -) - type Content struct { - BaseElement + BaseNode } -var KindContent = NewElementKind("content", &Content{}) +var KindContent = NewNodeKind("content", &Content{}) -func (e Content) Name() ElementName { - return ElementName{Local: "section"} -} - -func (e Content) Kind() ElementKind { +func (e Content) Kind() NodeKind { return KindContent } -func (e *Content) MarshalXML(enc *xml.Encoder, start xml.StartElement) error { - return e.MarshalXMLElement(e, enc, start) -} - -func (e *Content) UnmarshalXML(dec *xml.Decoder, start xml.StartElement) error { - return e.UnmarshalXMLElement(e, dec, start) -} - type Image struct { src string - BaseElement + BaseNode } -var KindImage = NewElementKind("image", &Image{}) +var KindImage = NewNodeKind("image", &Image{}) -func (e *Image) Name() ElementName { - return ElementName{Local: "img"} -} - -func (e *Image) Kind() ElementKind { +func (e *Image) Kind() NodeKind { return KindImage } -func (e *Image) MarshalXML(enc *xml.Encoder, start xml.StartElement) error { - if src := e.Source(); src != "" { - start.Attr = append(start.Attr, xml.Attr{ - Name: xml.Name{Local: "src"}, - Value: src, - }) - } - return e.MarshalXMLElement(e, enc, start) -} - -func (e *Image) UnmarshalXML(dec *xml.Decoder, start xml.StartElement) error { - i := slices.IndexFunc(start.Attr, func(a xml.Attr) bool { - return a.Name == xml.Name{Local: "src"} - }) - if i > -1 { - e.SetSource(start.Attr[i].Value) - } - return e.UnmarshalXMLElement(e, dec, start) -} - func (e Image) Source() string { return e.src } diff --git a/ipub/ast/errors.go b/ipub/ast/errors.go deleted file mode 100644 index 06ee830..0000000 --- a/ipub/ast/errors.go +++ /dev/null @@ -1,36 +0,0 @@ -package ast - -import ( - "encoding/xml" - "fmt" -) - -type ErrInvalidAttrName struct { - Actual xml.Name - Expected xml.Name -} - -var _ error = ErrInvalidAttrName{} - -func (err ErrInvalidAttrName) Error() string { - return fmt.Sprintf("attribute %q has invalid name, expected %q", fmtXMLName(err.Expected), fmtXMLName(err.Actual)) -} - -type ErrInvalidAttrValue struct { - Attr xml.Attr - Message string -} - -var _ error = ErrInvalidAttrValue{} - -func (err ErrInvalidAttrValue) Error() string { - return fmt.Sprintf("attribute %q's value %q is invalid: %s", fmtXMLName(err.Attr.Name), err.Attr.Value, err.Message) -} - -func fmtXMLName(n xml.Name) string { - s := n.Local - if n.Space != "" { - s = fmt.Sprintf("%s:%s", n.Space, n.Local) - } - return s -} diff --git a/ipub/ast/package.go b/ipub/ast/package.go new file mode 100644 index 0000000..e6f8743 --- /dev/null +++ b/ipub/ast/package.go @@ -0,0 +1,11 @@ +package ast + +type Package struct { + BaseNode +} + +var KindPackage = NewNodeKind("package", &Package{}) + +func (e Package) Kind() NodeKind { + return KindPackage +} diff --git a/ipub/ast/section.go b/ipub/ast/section.go index 5b74c88..8b96015 100644 --- a/ipub/ast/section.go +++ b/ipub/ast/section.go @@ -10,23 +10,11 @@ type Section struct { } type Body struct { - BaseElement + BaseNode } -var KindBody = NewElementKind("body", &Body{}) +var KindBody = NewNodeKind("body", &Body{}) -func (e Body) Name() ElementName { - return ElementName{Local: "body"} -} - -func (e Body) Kind() ElementKind { +func (e Body) Kind() NodeKind { return KindBody } - -func (e *Body) MarshalXML(enc *xml.Encoder, start xml.StartElement) error { - return e.MarshalXMLElement(e, enc, start) -} - -func (e *Body) UnmarshalXML(dec *xml.Decoder, start xml.StartElement) error { - return e.UnmarshalXMLElement(e, dec, start) -}