7 Commits

7 changed files with 171 additions and 277 deletions

View File

@ -2,7 +2,7 @@
An extensible Atom feed generator library that aims to be very close to RFC4287. An extensible Atom feed generator library that aims to be very close to RFC4287.
It diligently checks for compliance with the standard and provides functions for It diligently checks for compliance with the standard and provides functions for
easy creation and extension of elements. easy creation, extension and deletion of elements.
## Installation ## Installation
@ -14,9 +14,9 @@ go get git.streifling.com/jason/atom@latest
## Usage ## Usage
This library provides convenient functions to safely create and extend elements This library provides convenient functions to safely create, extend and delete
and attributes of Atom feeds. It also provides checks for all constructs' elements and attributes of Atom feeds. It also provides checks for all
adherence to RFC4287. constructs' adherence to RFC4287.
```go ```go
package main package main
@ -30,8 +30,6 @@ import (
func main() { func main() {
feed := atom.NewFeed("Example Feed") feed := atom.NewFeed("Example Feed")
feed.Title = atom.NewText("text", "Example Feed")
feed.ID = atom.NewID(atom.NewURN())
if err := feed.Check(); err != nil { if err := feed.Check(); err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
@ -44,7 +42,6 @@ func main() {
feed.AddAuthor(author) feed.AddAuthor(author)
entry := atom.NewEntry("First Entry") entry := atom.NewEntry("First Entry")
entry.ID = atom.NewID(atom.NewURN())
entry.Content = atom.NewContent(atom.InlineText, "text", "This is the content of the first entry.") entry.Content = atom.NewContent(atom.InlineText, "text", "This is the content of the first entry.")
if err := entry.Check(); err != nil { if err := entry.Check(); err != nil {
log.Fatalln(err) log.Fatalln(err)

27
atom.go
View File

@ -1,6 +1,7 @@
package atom package atom
import ( import (
"encoding/xml"
"fmt" "fmt"
"html" "html"
"mime" "mime"
@ -11,6 +12,32 @@ import (
"golang.org/x/text/language" "golang.org/x/text/language"
) )
type Countable interface {
*xml.Attr | *Person | *Category | *Link | *ExtensionElement | *Entry
}
// addToSlice adds a Countable to to a *[]Countable. It returns an int.
func addToSlice[C Countable](slice *[]C, countable C) int {
if *slice == nil {
*slice = make([]C, 0)
}
*slice = append(*slice, countable)
return len(*slice) - 1
}
// deleteFromSlice deletes the Countable with the index from the *[]Countable.
// It return an error.
func deleteFromSlice[C Countable](slice *[]C, index int) error {
length := len(*slice)
if index > length {
return fmt.Errorf("id %v out of range %v", index, length)
}
*slice = append((*slice)[:index], (*slice)[index+1:]...)
return nil
}
// isValidIRI checks whether an IRI is valid or not. It returns a bool. // isValidIRI checks whether an IRI is valid or not. It returns a bool.
// https://www.w3.org/2011/04/XMLSchema/TypeLibrary-IRI-RFC3987.xsd // https://www.w3.org/2011/04/XMLSchema/TypeLibrary-IRI-RFC3987.xsd
func isValidIRI(iri string) bool { func isValidIRI(iri string) bool {

View File

@ -17,25 +17,17 @@ func newCommonAttributes() *CommonAttributes {
return new(CommonAttributes) return new(CommonAttributes)
} }
// AddAttribute adds the attribute to the CommonAttributes. // AddAttribute adds the attribute to the CommonAttributes. It returns an int.
func (c *CommonAttributes) AddAttribute(name, value string) { func (c *CommonAttributes) AddAttribute(name, value string) int {
if c.UndefinedAttributes == nil { return addToSlice(&c.UndefinedAttributes, &xml.Attr{Name: xml.Name{Local: name}, Value: value})
c.UndefinedAttributes = make([]*xml.Attr, 1)
c.UndefinedAttributes[0] = &xml.Attr{Name: xml.Name{Local: name}, Value: value}
} else {
c.UndefinedAttributes = append(c.UndefinedAttributes, &xml.Attr{Name: xml.Name{Local: name}, Value: value})
}
} }
// DeleteAttribute deletes the attribute from the CommonAttributes. It return an // DeleteAttribute deletes the attribute at index from the CommonAttributes. It
// error. // return an error.
func (c *CommonAttributes) DeleteAttribute(id int) error { func (c *CommonAttributes) DeleteAttribute(index int) error {
length := len(c.UndefinedAttributes) if err := deleteFromSlice(&c.UndefinedAttributes, index); err != nil {
if id > length { return fmt.Errorf("error deleting undefined attribute %v from common attributes %v: %v", index, c, err)
return fmt.Errorf("error deleting undefined attribute from common attributes %v: id %v out of range %v", c, id, length)
} }
c.UndefinedAttributes = append(c.UndefinedAttributes[:id], c.UndefinedAttributes[id+1:]...)
return nil return nil
} }

114
entry.go
View File

@ -66,122 +66,86 @@ func NewEntry(title string) *Entry {
} }
} }
// AddAuthor adds the Person as an author to the Entry. // AddAuthor adds the Person as an author to the Entry. It returns an int.
func (e *Entry) AddAuthor(p *Person) { func (e *Entry) AddAuthor(p *Person) int {
if e.Authors == nil {
e.Authors = make([]*Person, 1)
e.Authors[0] = p
} else {
e.Authors = append(e.Authors, p)
}
e.Updated = NewDate(time.Now()) e.Updated = NewDate(time.Now())
return addToSlice(&e.Authors, p)
} }
// DeleteAuthor deletes the Person from the Entry. It return an error. // DeleteAuthor deletes the Person at index from the Entry. It return an error.
func (e *Entry) DeleteAuthor(id int) error { func (e *Entry) DeleteAuthor(index int) error {
length := len(e.Authors) if err := deleteFromSlice(&e.Authors, index); err != nil {
if id > length { return fmt.Errorf("error deleting author %v from entry %v: %v", index, e.ID.URI, err)
return fmt.Errorf("error deleting author from entry %v: id %v out of range %v", e.ID.URI, id, length)
} }
e.Authors = append(e.Authors[:id], e.Authors[id+1:]...)
e.Updated = NewDate(time.Now()) e.Updated = NewDate(time.Now())
return nil return nil
} }
// AddCategory adds the Category to the Entry. // AddCategory adds the Category to the Entry. It returns an int.
func (e *Entry) AddCategory(c *Category) { func (e *Entry) AddCategory(c *Category) int {
if e.Categories == nil {
e.Categories = make([]*Category, 1)
e.Categories[0] = c
} else {
e.Categories = append(e.Categories, c)
}
e.Updated = NewDate(time.Now()) e.Updated = NewDate(time.Now())
return addToSlice(&e.Categories, c)
} }
// DeleteCategory deletes the Category from the Entry. It return an error. // DeleteCategory deletes the Category at index from the Entry. It return an
func (e *Entry) DeleteCategory(id int) error { // error.
length := len(e.Categories) func (e *Entry) DeleteCategory(index int) error {
if id > length { if err := deleteFromSlice(&e.Categories, index); err != nil {
return fmt.Errorf("error deleting category from entry %v: id %v out of range %v", e.ID.URI, id, length) return fmt.Errorf("error deleting category %v from entry %v: %v", index, e.ID.URI, err)
} }
e.Categories = append(e.Categories[:id], e.Categories[id+1:]...)
e.Updated = NewDate(time.Now()) e.Updated = NewDate(time.Now())
return nil return nil
} }
// AddContributor adds the Person as a contributor to the Entry. // AddContributor adds the Person as a contributor to the Entry. It returns an
func (e *Entry) AddContributor(c *Person) { // int.
if e.Contributors == nil { func (e *Entry) AddContributor(c *Person) int {
e.Contributors = make([]*Person, 1)
e.Contributors[0] = c
} else {
e.Contributors = append(e.Contributors, c)
}
e.Updated = NewDate(time.Now()) e.Updated = NewDate(time.Now())
return addToSlice(&e.Contributors, c)
} }
// DeleteContributor deletes the Person from the Entry. It return an error. // DeleteContributor deletes the Person at index from the Entry. It return an
func (e *Entry) DeleteContributor(id int) error { // error.
length := len(e.Contributors) func (e *Entry) DeleteContributor(index int) error {
if id > length { if err := deleteFromSlice(&e.Contributors, index); err != nil {
return fmt.Errorf("error deleting contributor from entry %v: id %v out of range %v", e.ID.URI, id, length) return fmt.Errorf("error deleting contributor %v from entry %v: %v", index, e.ID.URI, err)
} }
e.Contributors = append(e.Contributors[:id], e.Contributors[id+1:]...)
e.Updated = NewDate(time.Now()) e.Updated = NewDate(time.Now())
return nil return nil
} }
// AddLink adds the Link to the Entry. // AddLink adds the Link to the Entry. It returns an int.
func (e *Entry) AddLink(l *Link) { func (e *Entry) AddLink(l *Link) int {
if e.Links == nil {
e.Links = make([]*Link, 1)
e.Links[0] = l
} else {
e.Links = append(e.Links, l)
}
e.Updated = NewDate(time.Now()) e.Updated = NewDate(time.Now())
return addToSlice(&e.Links, l)
} }
// DeleteLink deletes the Link from the Entry. It return an error. // DeleteLink deletes the Link at index from the Entry. It return an error.
func (e *Entry) DeleteLink(id int) error { func (e *Entry) DeleteLink(index int) error {
length := len(e.Links) if err := deleteFromSlice(&e.Links, index); err != nil {
if id > length { return fmt.Errorf("error deleting link %v from entry %v: %v", index, e.ID.URI, err)
return fmt.Errorf("error deleting link from entry %v: id %v out of range %v", e.ID.URI, id, length)
} }
e.Links = append(e.Links[:id], e.Links[id+1:]...)
e.Updated = NewDate(time.Now()) e.Updated = NewDate(time.Now())
return nil return nil
} }
// AddExtension adds the ExtensionElement to the Entry. // AddExtension adds the ExtensionElement to the Entry. It returns an int.
func (e *Entry) AddExtension(x *ExtensionElement) { func (e *Entry) AddExtension(x *ExtensionElement) int {
if e.Extensions == nil {
e.Extensions = make([]*ExtensionElement, 1)
e.Extensions[0] = x
} else {
e.Extensions = append(e.Extensions, x)
}
e.Updated = NewDate(time.Now()) e.Updated = NewDate(time.Now())
return addToSlice(&e.Extensions, x)
} }
// DeleteExtension deletes the Extension from the Entry. It return an error. // DeleteExtension deletes the Extension at index from the Entry. It return an
func (e *Entry) DeleteExtension(id int) error { // error.
length := len(e.Extensions) func (e *Entry) DeleteExtension(index int) error {
if id > length { if err := deleteFromSlice(&e.Extensions, index); err != nil {
return fmt.Errorf("error deleting extension from entry %v: id %v out of range %v", e.ID.URI, id, length) return fmt.Errorf("error deleting extension %v from entry %v: %v", index, e.ID.URI, err)
} }
e.Extensions = append(e.Extensions[:id], e.Extensions[id+1:]...)
e.Updated = NewDate(time.Now()) e.Updated = NewDate(time.Now())
return nil return nil
} }

135
feed.go
View File

@ -35,146 +35,103 @@ func NewFeed(title string) *Feed {
} }
} }
// AddAuthor adds the Person as an author to the Feed. // AddAuthor adds the Person as an author to the Feed. It returns an int.
func (f *Feed) AddAuthor(p *Person) { func (f *Feed) AddAuthor(p *Person) int {
if f.Authors == nil {
f.Authors = make([]*Person, 1)
f.Authors[0] = p
} else {
f.Authors = append(f.Authors, p)
}
f.Updated = NewDate(time.Now()) f.Updated = NewDate(time.Now())
return addToSlice(&f.Authors, p)
} }
// DeleteAuthor deletes the Person from the Feed. It return an error. // DeleteAuthor deletes the Person at index from the Feed. It return an error.
func (f *Feed) DeleteAuthor(id int) error { func (f *Feed) DeleteAuthor(index int) error {
length := len(f.Authors) if err := deleteFromSlice(&f.Authors, index); err != nil {
if id > length { return fmt.Errorf("error deleting author %v from entry %v: %v", index, f.ID.URI, err)
return fmt.Errorf("error deleting author from feed %v: id %v out of range %v", f.ID.URI, id, length)
} }
f.Authors = append(f.Authors[:id], f.Authors[id+1:]...)
f.Updated = NewDate(time.Now()) f.Updated = NewDate(time.Now())
return nil return nil
} }
// AddCategory adds the Category to the Feed. // AddCategory adds the Category to the Feed. It returns an int.
func (f *Feed) AddCategory(c *Category) { func (f *Feed) AddCategory(c *Category) int {
if f.Categories == nil {
f.Categories = make([]*Category, 1)
f.Categories[0] = c
} else {
f.Categories = append(f.Categories, c)
}
f.Updated = NewDate(time.Now()) f.Updated = NewDate(time.Now())
return addToSlice(&f.Categories, c)
} }
// DeleteCategory deletes the Category from the Feed. It return an error. // DeleteCategory deletes the Category at index from the Feed. It return an
func (f *Feed) DeleteCategory(id int) error { // error.
length := len(f.Categories) func (f *Feed) DeleteCategory(index int) error {
if id > length { if err := deleteFromSlice(&f.Categories, index); err != nil {
return fmt.Errorf("error deleting category from feed %v: id %v out of range %v", f.ID.URI, id, length) return fmt.Errorf("error deleting category %v from entry %v: %v", index, f.ID.URI, err)
} }
f.Categories = append(f.Categories[:id], f.Categories[id+1:]...)
f.Updated = NewDate(time.Now()) f.Updated = NewDate(time.Now())
return nil return nil
} }
// AddContributor adds the Person as a contributor to the Feed. // AddContributor adds the Person as a contributor to the Feed. It returns an
func (f *Feed) AddContributor(c *Person) { // int.
if f.Contributors == nil { func (f *Feed) AddContributor(c *Person) int {
f.Contributors = make([]*Person, 1)
f.Contributors[0] = c
} else {
f.Contributors = append(f.Contributors, c)
}
f.Updated = NewDate(time.Now()) f.Updated = NewDate(time.Now())
return addToSlice(&f.Contributors, c)
} }
// DeleteContributor deletes the Person from the Feed. It return an error. // DeleteContributor deletes the Person at index from the Feed. It return an
func (f *Feed) DeleteContributor(id int) error { // error.
length := len(f.Contributors) func (f *Feed) DeleteContributor(index int) error {
if id > length { if err := deleteFromSlice(&f.Contributors, index); err != nil {
return fmt.Errorf("error deleting contributor from feed %v: id %v out of range %v", f.ID.URI, id, length) return fmt.Errorf("error deleting contributor %v from entry %v: %v", index, f.ID.URI, err)
} }
f.Contributors = append(f.Contributors[:id], f.Contributors[id+1:]...)
f.Updated = NewDate(time.Now()) f.Updated = NewDate(time.Now())
return nil return nil
} }
// AddLink adds the Link to the Feed. There should be one Link with Rel "self". // AddLink adds the Link to the Feed. There should be one Link with Rel "self".
func (f *Feed) AddLink(l *Link) { // It returns an int.
if f.Links == nil { func (f *Feed) AddLink(l *Link) int {
f.Links = make([]*Link, 1)
f.Links[0] = l
} else {
f.Links = append(f.Links, l)
}
f.Updated = NewDate(time.Now()) f.Updated = NewDate(time.Now())
return addToSlice(&f.Links, l)
} }
// DeleteLink deletes the Link from the Feed. It return an error. // DeleteLink deletes the Link at index from the Feed. It return an error.
func (f *Feed) DeleteLink(id int) error { func (f *Feed) DeleteLink(index int) error {
length := len(f.Links) if err := deleteFromSlice(&f.Links, index); err != nil {
if id > length { return fmt.Errorf("error deleting link %v from entry %v: %v", index, f.ID.URI, err)
return fmt.Errorf("error deleting link from feed %v: id %v out of range %v", f.ID.URI, id, length)
} }
f.Links = append(f.Links[:id], f.Links[id+1:]...)
f.Updated = NewDate(time.Now()) f.Updated = NewDate(time.Now())
return nil return nil
} }
// AddExtension adds the Extension to the Feed. // AddExtension adds the Extension to the Feed. It returns an int.
func (f *Feed) AddExtension(e *ExtensionElement) { func (f *Feed) AddExtension(e *ExtensionElement) int {
if f.Extensions == nil {
f.Extensions = make([]*ExtensionElement, 1)
f.Extensions[0] = e
} else {
f.Extensions = append(f.Extensions, e)
}
f.Updated = NewDate(time.Now()) f.Updated = NewDate(time.Now())
return addToSlice(&f.Extensions, e)
} }
// DeleteExtension deletes the Extension from the Feed. It return an error. // DeleteExtension deletes the Extension at index from the Feed. It return an
func (f *Feed) DeleteExtension(id int) error { // error.
length := len(f.Extensions) func (f *Feed) DeleteExtension(index int) error {
if id > length { if err := deleteFromSlice(&f.Extensions, index); err != nil {
return fmt.Errorf("error deleting extension from feed %v: id %v out of range %v", f.ID.URI, id, length) return fmt.Errorf("error deleting extension %v from entry %v: %v", index, f.ID.URI, err)
} }
f.Extensions = append(f.Extensions[:id], f.Extensions[id+1:]...)
f.Updated = NewDate(time.Now()) f.Updated = NewDate(time.Now())
return nil return nil
} }
// AddEntry adds the Entry to the Feed. // AddEntry adds the Entry to the Feed. It returns an int.
func (f *Feed) AddEntry(e *Entry) { func (f *Feed) AddEntry(e *Entry) int {
if f.Entries == nil {
f.Entries = make([]*Entry, 1)
f.Entries[0] = e
} else {
f.Entries = append(f.Entries, e)
}
f.Updated = NewDate(time.Now()) f.Updated = NewDate(time.Now())
return addToSlice(&f.Entries, e)
} }
// DeleteEntry deletes the Entry from the Feed. It return an error. // DeleteEntry deletes the Entry at index from the Feed. It return an error.
func (f *Feed) DeleteEntry(id int) error { func (f *Feed) DeleteEntry(index int) error {
length := len(f.Entries) if err := deleteFromSlice(&f.Entries, index); err != nil {
if id > length { return fmt.Errorf("error deleting entry %v from entry %v: %v", index, f.ID.URI, err)
return fmt.Errorf("error deleting entry from feed %v: id %v out of range %v", f.ID.URI, id, length)
} }
f.Entries = append(f.Entries[:id], f.Entries[id+1:]...)
f.Updated = NewDate(time.Now()) f.Updated = NewDate(time.Now())
return nil return nil
} }

View File

@ -21,24 +21,17 @@ func NewPerson(name string) *Person {
} }
} }
// AddExtension adds the Extension to the Person. // AddExtension adds the Extension to the Person. It returns an int.
func (p *Person) AddExtension(e *ExtensionElement) { func (p *Person) AddExtension(e *ExtensionElement) int {
if p.Extensions == nil { return addToSlice(&p.Extensions, e)
p.Extensions = make([]*ExtensionElement, 1)
p.Extensions[0] = e
} else {
p.Extensions = append(p.Extensions, e)
}
} }
// DeleteExtension deletes the Extension from the Person. It return an error. // DeleteExtension deletes the Extension at index from the Person. It return an
func (p *Person) DeleteExtension(id int) error { // error.
length := len(p.Extensions) func (p *Person) DeleteExtension(index int) error {
if id > length { if err := deleteFromSlice(&p.Extensions, index); err != nil {
return fmt.Errorf("error deleting extension from person %v: id %v out of range %v", p, id, length) return fmt.Errorf("error deleting extension %v from person %v: %v", index, p, err)
} }
p.Extensions = append(p.Extensions[:id], p.Extensions[id+1:]...)
return nil return nil
} }

114
source.go
View File

@ -28,108 +28,72 @@ func NewSource() *Source {
return &Source{CommonAttributes: newCommonAttributes()} return &Source{CommonAttributes: newCommonAttributes()}
} }
// AddAuthor adds the Person as an author to the Source. // AddAuthor adds the Person as an author to the Source. It returns an int.
func (s *Source) AddAuthor(p *Person) { func (s *Source) AddAuthor(p *Person) int {
if s.Authors == nil { return addToSlice(&s.Authors, p)
s.Authors = make([]*Person, 1)
s.Authors[0] = p
} else {
s.Authors = append(s.Authors, p)
}
} }
// DeleteAuthor deletes the Person from the Source. It return an error. // DeleteAuthor deletes the Person at index from the Source. It return an error.
func (s *Source) DeleteAuthor(id int) error { func (s *Source) DeleteAuthor(index int) error {
length := len(s.Authors) if err := deleteFromSlice(&s.Authors, index); err != nil {
if id > length { return fmt.Errorf("error deleting author %v from source %v: %v", index, s, err)
return fmt.Errorf("error deleting author from source %v: id %v out of range %v", s, id, length)
} }
s.Authors = append(s.Authors[:id], s.Authors[id+1:]...)
return nil return nil
} }
// AddCategory adds the Category to the Source. // AddCategory adds the Category to the Source. It returns an int.
func (s *Source) AddCategory(c *Category) { func (s *Source) AddCategory(c *Category) int {
if s.Categories == nil { return addToSlice(&s.Categories, c)
s.Categories = make([]*Category, 1)
s.Categories[0] = c
} else {
s.Categories = append(s.Categories, c)
}
} }
// DeleteCategory deletes the Category from the Source. It return an error. // DeleteCategory deletes the Category at index from the Source. It return an
func (s *Source) DeleteCategory(id int) error { // error.
length := len(s.Categories) func (s *Source) DeleteCategory(index int) error {
if id > length { if err := deleteFromSlice(&s.Categories, index); err != nil {
return fmt.Errorf("error deleting category from source %v: id %v out of range %v", s, id, length) return fmt.Errorf("error deleting category %v from source %v: %v", index, s, err)
} }
s.Categories = append(s.Categories[:id], s.Categories[id+1:]...)
return nil return nil
} }
// AddContributor adds the Person as a contributor to the Source. // AddContributor adds the Person as a contributor to the Source. It returns an
func (s *Source) AddContributor(c *Person) { // int.
if s.Contributors == nil { func (s *Source) AddContributor(c *Person) int {
s.Contributors = make([]*Person, 1) return addToSlice(&s.Contributors, c)
s.Contributors[0] = c
} else {
s.Contributors = append(s.Contributors, c)
}
} }
// DeleteContributor deletes the Person from the Source. It return an error. // DeleteContributor deletes the Person at index from the Source. It return an
func (s *Source) DeleteContributor(id int) error { // error.
length := len(s.Contributors) func (s *Source) DeleteContributor(index int) error {
if id > length { if err := deleteFromSlice(&s.Contributors, index); err != nil {
return fmt.Errorf("error deleting contributor from source %v: id %v out of range %v", s, id, length) return fmt.Errorf("error deleting contributor %v from source %v: %v", index, s, err)
} }
s.Contributors = append(s.Contributors[:id], s.Contributors[id+1:]...)
return nil return nil
} }
// AddLink adds the Link to the Source. // AddLink adds the Link to the Source. It returns an int.
func (s *Source) AddLink(l *Link) { func (s *Source) AddLink(l *Link) int {
if s.Links == nil { return addToSlice(&s.Links, l)
s.Links = make([]*Link, 1)
s.Links[0] = l
} else {
s.Links = append(s.Links, l)
}
} }
// DeleteLink deletes the Link from the Source. It return an error. // DeleteLink deletes the Link at index from the Source. It return an error.
func (s *Source) DeleteLink(id int) error { func (s *Source) DeleteLink(index int) error {
length := len(s.Links) if err := deleteFromSlice(&s.Links, index); err != nil {
if id > length { return fmt.Errorf("error deleting link %v from source %v: %v", index, s, err)
return fmt.Errorf("error deleting link from source %v: id %v out of range %v", s, id, length)
} }
s.Links = append(s.Links[:id], s.Links[id+1:]...)
return nil return nil
} }
// AddExtension adds the ExtensionElement to the Source. // AddExtension adds the ExtensionElement to the Source. It returns an int.
func (s *Source) AddExtension(e *ExtensionElement) { func (s *Source) AddExtension(e *ExtensionElement) int {
if s.Extensions == nil { return addToSlice(&s.Extensions, e)
s.Extensions = make([]*ExtensionElement, 1)
s.Extensions[0] = e
} else {
s.Extensions = append(s.Extensions, e)
}
} }
// DeleteExtension deletes the Extension from the Source. It return an error. // DeleteExtension deletes the Extension at index from the Source. It return an
func (s *Source) DeleteExtension(id int) error { // error.
length := len(s.Extensions) func (s *Source) DeleteExtension(index int) error {
if id > length { if err := deleteFromSlice(&s.Extensions, index); err != nil {
return fmt.Errorf("error deleting extension from source %v: id %v out of range %v", s, id, length) return fmt.Errorf("error deleting extension %v from source %v: %v", index, s, err)
} }
s.Extensions = append(s.Extensions[:id], s.Extensions[id+1:]...)
return nil return nil
} }