From b269dd9ce90898e7c397f51bb32b7c633a098794 Mon Sep 17 00:00:00 2001 From: fiatjaf Date: Fri, 26 May 2023 18:04:36 -0300 Subject: [PATCH] sdk: return start and end on references for replacement. --- sdk/references.go | 100 +++++++++++++++++++---------------------- sdk/references_test.go | 24 ++++++++-- 2 files changed, 66 insertions(+), 58 deletions(-) diff --git a/sdk/references.go b/sdk/references.go index 80b730f..72f3724 100644 --- a/sdk/references.go +++ b/sdk/references.go @@ -11,6 +11,8 @@ import ( type Reference struct { Text string + Start int + End int Profile *nostr.ProfilePointer Event *nostr.EventPointer Entity *nostr.EntityPointer @@ -21,95 +23,85 @@ var mentionRegex = regexp.MustCompile(`\bnostr:((note|npub|naddr|nevent|nprofile // ParseReferences parses both NIP-08 and NIP-27 references in a single unifying interface. func ParseReferences(evt *nostr.Event) []*Reference { var references []*Reference - for _, ref := range mentionRegex.FindAllStringSubmatch(evt.Content, -1) { - if ref[2] != "" { - // it's a NIP-27 mention - if prefix, data, err := nip19.Decode(ref[1]); err == nil { + content := evt.Content + + for _, ref := range mentionRegex.FindAllStringSubmatchIndex(evt.Content, -1) { + reference := &Reference{ + Text: content[ref[0]:ref[1]], + Start: ref[0], + End: ref[1], + } + + if ref[6] == -1 { + // didn't find a NIP-10 #[0] reference, so it's it's a NIP-27 mention + nip19code := content[ref[2]:ref[3]] + + if prefix, data, err := nip19.Decode(nip19code); err == nil { switch prefix { case "npub": - references = append(references, &Reference{ - Text: ref[0], - Profile: &nostr.ProfilePointer{ - PublicKey: data.(string), Relays: []string{}, - }, - }) + reference.Profile = &nostr.ProfilePointer{ + PublicKey: data.(string), Relays: []string{}, + } case "nprofile": pp := data.(nostr.ProfilePointer) - references = append(references, &Reference{ - Text: ref[0], - Profile: &pp, - }) + reference.Profile = &pp case "note": - references = append(references, &Reference{ - Text: ref[0], - Event: &nostr.EventPointer{ID: data.(string), Relays: []string{}}, - }) + reference.Event = &nostr.EventPointer{ID: data.(string), Relays: []string{}} case "nevent": evp := data.(nostr.EventPointer) - references = append(references, &Reference{ - Text: ref[0], - Event: &evp, - }) + reference.Event = &evp case "naddr": addr := data.(nostr.EntityPointer) - references = append(references, &Reference{ - Text: ref[0], - Entity: &addr, - }) + reference.Entity = &addr } } - } else if ref[3] != "" { - // it's a NIP-10 mention - idx, err := strconv.Atoi(ref[3]) + } else { + // it's a NIP-10 mention. + // parse the number, get data from event tags. + n := content[ref[6]:ref[7]] + idx, err := strconv.Atoi(n) if err != nil || len(evt.Tags) <= idx { continue } - if tag := evt.Tags[idx]; tag != nil { + if tag := evt.Tags[idx]; tag != nil && len(tag) >= 2 { switch tag[0] { case "p": relays := make([]string, 0, 1) if len(tag) > 2 && tag[2] != "" { relays = append(relays, tag[2]) } - references = append(references, &Reference{ - Text: ref[0], - Profile: &nostr.ProfilePointer{ - PublicKey: tag[1], - Relays: relays, - }, - }) + 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]) } - references = append(references, &Reference{ - Text: ref[0], - Event: &nostr.EventPointer{ - ID: tag[1], - Relays: relays, - }, - }) + reference.Event = &nostr.EventPointer{ + ID: tag[1], + Relays: relays, + } case "a": - if parts := strings.Split(ref[1], ":"); len(parts) == 3 { + 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]) } - references = append(references, &Reference{ - Text: ref[0], - Entity: &nostr.EntityPointer{ - Identifier: parts[2], - PublicKey: parts[1], - Kind: kind, - Relays: relays, - }, - }) + reference.Entity = &nostr.EntityPointer{ + Identifier: parts[2], + PublicKey: parts[1], + Kind: kind, + Relays: relays, + } } } } } + + references = append(references, reference) } return references diff --git a/sdk/references_test.go b/sdk/references_test.go index 9f3b0a8..1743520 100644 --- a/sdk/references_test.go +++ b/sdk/references_test.go @@ -19,28 +19,36 @@ func TestParseReferences(t *testing.T) { expected := []Reference{ { - Text: "#[0]", + Text: "#[0]", + Start: 6, + End: 10, Profile: &nostr.ProfilePointer{ PublicKey: "c9d556c6d3978d112d30616d0d20aaa81410e3653911dd67787b5aaf9b36ade8", Relays: []string{"wss://nostr.com"}, }, }, { - Text: "#[2]", + Text: "#[2]", + Start: 26, + End: 30, Event: &nostr.EventPointer{ ID: "31d7c2875b5fc8e6f9c8f9dc1f84de1b6b91d1947ea4c59225e55c325d330fa8", Relays: []string{}, }, }, { - Text: "nostr:nprofile1qqsvc6ulagpn7kwrcwdqgp797xl7usumqa6s3kgcelwq6m75x8fe8yc5usxdg", + Text: "nostr:nprofile1qqsvc6ulagpn7kwrcwdqgp797xl7usumqa6s3kgcelwq6m75x8fe8yc5usxdg", + Start: 47, + End: 123, Profile: &nostr.ProfilePointer{ PublicKey: "cc6b9fea033f59c3c39a0407c5f1bfee439b077508d918cfdc0d6fd431d39393", Relays: []string{}, }, }, { - Text: "nostr:nevent1qqsvc6ulagpn7kwrcwdqgp797xl7usumqa6s3kgcelwq6m75x8fe8ychxp5v4", + Text: "nostr:nevent1qqsvc6ulagpn7kwrcwdqgp797xl7usumqa6s3kgcelwq6m75x8fe8ychxp5v4", + Start: 127, + End: 201, Event: &nostr.EventPointer{ ID: "cc6b9fea033f59c3c39a0407c5f1bfee439b077508d918cfdc0d6fd431d39393", Relays: []string{}, @@ -61,6 +69,14 @@ func TestParseReferences(t *testing.T) { t.Errorf("%d: got text %s, expected %s", i, g.Text, e.Text) } + if g.Start != e.Start { + t.Errorf("%d: got start %d, expected %d", i, g.Start, e.Start) + } + + if g.End != e.End { + t.Errorf("%d: got end %d, expected %d", i, g.End, e.End) + } + if (g.Entity == nil && e.Entity != nil) || (g.Event == nil && e.Event != nil) || (g.Profile == nil && e.Profile != nil) {