references returns an iterator because why not?

This commit is contained in:
fiatjaf 2024-12-31 23:09:56 -03:00
parent dcd5030fcd
commit 08d6943dd1

View File

@ -1,6 +1,7 @@
package sdk package sdk
import ( import (
"iter"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
@ -21,88 +22,87 @@ type Reference struct {
var mentionRegex = regexp.MustCompile(`\bnostr:((note|npub|naddr|nevent|nprofile)1\w+)\b|#\[(\d+)\]`) var mentionRegex = regexp.MustCompile(`\bnostr:((note|npub|naddr|nevent|nprofile)1\w+)\b|#\[(\d+)\]`)
// ParseReferences parses both NIP-08 and NIP-27 references in a single unifying interface. // ParseReferences parses both NIP-08 and NIP-27 references in a single unifying interface.
func ParseReferences(evt *nostr.Event) []*Reference { func ParseReferences(evt nostr.Event) iter.Seq[Reference] {
var references []*Reference return func(yield func(Reference) bool) {
content := evt.Content for _, ref := range mentionRegex.FindAllStringSubmatchIndex(evt.Content, -1) {
reference := Reference{
Text: evt.Content[ref[0]:ref[1]],
Start: ref[0],
End: ref[1],
}
for _, ref := range mentionRegex.FindAllStringSubmatchIndex(evt.Content, -1) { if ref[6] == -1 {
reference := &Reference{ // didn't find a NIP-10 #[0] reference, so it's a NIP-27 mention
Text: content[ref[0]:ref[1]], nip19code := evt.Content[ref[2]:ref[3]]
Start: ref[0],
End: ref[1],
}
if ref[6] == -1 { if prefix, data, err := nip19.Decode(nip19code); err == nil {
// didn't find a NIP-10 #[0] reference, so it's a NIP-27 mention switch prefix {
nip19code := content[ref[2]:ref[3]] case "npub":
reference.Profile = &nostr.ProfilePointer{
if prefix, data, err := nip19.Decode(nip19code); err == nil { PublicKey: data.(string), Relays: []string{},
switch prefix { }
case "npub": case "nprofile":
reference.Profile = &nostr.ProfilePointer{ pp := data.(nostr.ProfilePointer)
PublicKey: data.(string), Relays: []string{}, reference.Profile = &pp
case "note":
reference.Event = &nostr.EventPointer{ID: data.(string), Relays: []string{}}
case "nevent":
evp := data.(nostr.EventPointer)
reference.Event = &evp
case "naddr":
addr := data.(nostr.EntityPointer)
reference.Entity = &addr
} }
case "nprofile":
pp := data.(nostr.ProfilePointer)
reference.Profile = &pp
case "note":
reference.Event = &nostr.EventPointer{ID: data.(string), Relays: []string{}}
case "nevent":
evp := data.(nostr.EventPointer)
reference.Event = &evp
case "naddr":
addr := data.(nostr.EntityPointer)
reference.Entity = &addr
} }
} } else {
} else { // it's a NIP-10 mention.
// it's a NIP-10 mention. // parse the number, get data from event tags.
// parse the number, get data from event tags. n := evt.Content[ref[6]:ref[7]]
n := content[ref[6]:ref[7]] idx, err := strconv.Atoi(n)
idx, err := strconv.Atoi(n) if err != nil || len(evt.Tags) <= idx {
if err != nil || len(evt.Tags) <= idx { continue
continue }
} if tag := evt.Tags[idx]; tag != nil && len(tag) >= 2 {
if tag := evt.Tags[idx]; tag != nil && len(tag) >= 2 { switch tag[0] {
switch tag[0] { case "p":
case "p":
relays := make([]string, 0, 1)
if len(tag) > 2 && tag[2] != "" {
relays = append(relays, tag[2])
}
reference.Profile = &nostr.ProfilePointer{
PublicKey: tag[1],
Relays: relays,
}
case "e":
relays := make([]string, 0, 1)
if len(tag) > 2 && tag[2] != "" {
relays = append(relays, tag[2])
}
reference.Event = &nostr.EventPointer{
ID: tag[1],
Relays: relays,
}
case "a":
if parts := strings.Split(tag[1], ":"); len(parts) == 3 {
kind, _ := strconv.Atoi(parts[0])
relays := make([]string, 0, 1) relays := make([]string, 0, 1)
if len(tag) > 2 && tag[2] != "" { if len(tag) > 2 && tag[2] != "" {
relays = append(relays, tag[2]) relays = append(relays, tag[2])
} }
reference.Entity = &nostr.EntityPointer{ reference.Profile = &nostr.ProfilePointer{
Identifier: parts[2], PublicKey: tag[1],
PublicKey: parts[1], Relays: relays,
Kind: kind, }
Relays: relays, case "e":
relays := make([]string, 0, 1)
if len(tag) > 2 && tag[2] != "" {
relays = append(relays, tag[2])
}
reference.Event = &nostr.EventPointer{
ID: tag[1],
Relays: relays,
}
case "a":
if parts := strings.Split(tag[1], ":"); len(parts) == 3 {
kind, _ := strconv.Atoi(parts[0])
relays := make([]string, 0, 1)
if len(tag) > 2 && tag[2] != "" {
relays = append(relays, tag[2])
}
reference.Entity = &nostr.EntityPointer{
Identifier: parts[2],
PublicKey: parts[1],
Kind: kind,
Relays: relays,
}
} }
} }
} }
} }
if !yield(reference) {
return
}
} }
references = append(references, reference)
} }
return references
} }