damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

commit a721256e9b49559504c95f6c96398edd0d342bab
parent 007bcc868770bfb500a198fe2f8f2db268fdf1bf
Author: William Casarin <jb55@jb55.com>
Date:   Thu, 25 Apr 2024 14:03:34 -0700

nip10: add marker nip10 support when reading notes

We still need to add these when writing notes.

Changelog-Added: Add marker nip10 support when reading notes
Signed-off-by: William Casarin <jb55@jb55.com>

Diffstat:
Mdamus.xcodeproj/project.pbxproj | 4++++
Mdamus/ContentParsing.swift | 32+++++++++++++++++++-------------
Mdamus/Models/EventRef.swift | 9+++++++++
AdamusTests/NIP10Tests.swift | 171+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 203 insertions(+), 13 deletions(-)

diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj @@ -98,6 +98,7 @@ 4C2B10282A7B0F5C008AA43E /* Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C2B10272A7B0F5C008AA43E /* Log.swift */; }; 4C2B7BF22A71B6540049DEE7 /* Id.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C2B7BF12A71B6540049DEE7 /* Id.swift */; }; 4C2CDDF7299D4A5E00879FD5 /* Debouncer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C2CDDF6299D4A5E00879FD5 /* Debouncer.swift */; }; + 4C2D34412BDAF1B300F9FB44 /* NIP10Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C2D34402BDAF1B300F9FB44 /* NIP10Tests.swift */; }; 4C30AC7229A5677A00E2BD5A /* NotificationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C30AC7129A5677A00E2BD5A /* NotificationsView.swift */; }; 4C30AC7429A5680900E2BD5A /* EventGroupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C30AC7329A5680900E2BD5A /* EventGroupView.swift */; }; 4C30AC7629A5770900E2BD5A /* NotificationItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C30AC7529A5770900E2BD5A /* NotificationItemView.swift */; }; @@ -888,6 +889,7 @@ 4C2B10272A7B0F5C008AA43E /* Log.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Log.swift; sourceTree = "<group>"; }; 4C2B7BF12A71B6540049DEE7 /* Id.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Id.swift; sourceTree = "<group>"; }; 4C2CDDF6299D4A5E00879FD5 /* Debouncer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Debouncer.swift; sourceTree = "<group>"; }; + 4C2D34402BDAF1B300F9FB44 /* NIP10Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NIP10Tests.swift; sourceTree = "<group>"; }; 4C30AC7129A5677A00E2BD5A /* NotificationsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsView.swift; sourceTree = "<group>"; }; 4C30AC7329A5680900E2BD5A /* EventGroupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventGroupView.swift; sourceTree = "<group>"; }; 4C30AC7529A5770900E2BD5A /* NotificationItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationItemView.swift; sourceTree = "<group>"; }; @@ -2557,6 +2559,7 @@ E06336A92B75832100A88E6B /* ImageMetadataTest.swift */, D7CBD1D52B8D509800BFD889 /* DamusPurpleImpendingExpirationTests.swift */, D72927AC2BAB515C00F93E90 /* RelayURLTests.swift */, + 4C2D34402BDAF1B300F9FB44 /* NIP10Tests.swift */, ); path = damusTests; sourceTree = "<group>"; @@ -3522,6 +3525,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 4C2D34412BDAF1B300F9FB44 /* NIP10Tests.swift in Sources */, 4C684A572A7FFAE6005E6031 /* UrlTests.swift in Sources */, 3A90B1832A4EA3C600000D94 /* UserSearchCacheTests.swift in Sources */, 4C9B0DEE2A65A75F00CBDA21 /* AttrStringTestExtensions.swift in Sources */, diff --git a/damus/ContentParsing.swift b/damus/ContentParsing.swift @@ -76,27 +76,33 @@ func interpret_event_refs_ndb(blocks: [Block], tags: TagsSequence) -> [EventRef] } func interp_event_refs_without_mentions_ndb(_ ev_tags: References<NoteRef>) -> [EventRef] { - - var count = 0 var evrefs: [EventRef] = [] var first: Bool = true - var first_ref: NoteRef? = nil + var root_id: NoteRef? = nil for ref in ev_tags { - if first { - first_ref = ref - evrefs.append(.thread_id(ref)) - first = false + if let marker = ref.marker { + switch marker { + case .root: root_id = ref + case .reply: evrefs.append(.reply(ref)) + case .mention: evrefs.append(.mention(.noteref(ref))) + } } else { - - evrefs.append(.reply(ref)) + if first { + root_id = ref + first = false + } else { + evrefs.append(.reply(ref)) + } } - count += 1 } - if let first_ref, count == 1 { - let r = first_ref - return [.reply_to_root(r)] + if let root_id { + if evrefs.count == 0 { + return [.reply_to_root(root_id)] + } else { + evrefs.insert(.thread_id(root_id), at: 0) + } } return evrefs diff --git a/damus/Models/EventRef.swift b/damus/Models/EventRef.swift @@ -13,6 +13,15 @@ enum EventRef: Equatable { case reply(NoteRef) case reply_to_root(NoteRef) + var note_ref: NoteRef { + switch self { + case .mention(let mnref): return mnref.ref + case .thread_id(let ref): return ref + case .reply(let ref): return ref + case .reply_to_root(let ref): return ref + } + } + var is_mention: NoteRef? { if case .mention(let m) = self { return m.ref } return nil diff --git a/damusTests/NIP10Tests.swift b/damusTests/NIP10Tests.swift @@ -0,0 +1,171 @@ +// +// NIP10Tests.swift +// damusTests +// +// Created by William Casarin on 2024-04-25. +// + +import XCTest +@testable import damus + +final class NIP10Tests: XCTestCase { + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testExample() throws { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + // Any test you write for XCTest can be annotated as throws and async. + // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. + // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. + } + + func test_new_nip10() { + let root_note_id_hex = "7c7d37bc8c04d2ec65cbc7d9275253e6b5cc34b5d10439f158194a3feefa8d52" + let direct_reply_hex = "7c7d37bc8c04d2ec65cbc7d9275253e6b5cc34b5d10439f158194a3feefa8d51" + let reply_hex = "7c7d37bc8c04d2ec65cbc7d9275253e6b5cc34b5d10439f158194a3feefa8d53" + + let tags = [ + ["e", direct_reply_hex, "", "reply"], + ["e", root_note_id_hex, "", "root"], + ["e", reply_hex, "", "reply"], + ["e", "7c7d37bc8c04d2ec65cbc7d9275253e6b5cc34b5d10439f158194a3feefa8d54", "", "mention"], + ] + + let root_note_id = NoteId(hex: root_note_id_hex)! + let direct_reply_id = NoteId(hex: direct_reply_hex)! + let reply_id = NoteId(hex: reply_hex)! + + let note = NdbNote(content: "hi", keypair: test_keypair, kind: 1, tags: tags)! + let refs = interp_event_refs_without_mentions_ndb(note.referenced_noterefs) + + XCTAssertEqual(refs.reduce(into: Array<NoteId>(), { xs, r in + if let note_id = r.is_thread_id?.note_id { xs.append(note_id) } + }), [root_note_id]) + + XCTAssertEqual(refs.reduce(into: Array<NoteId>(), { xs, r in + if let note_id = r.is_direct_reply?.note_id { xs.append(note_id) } + }), [direct_reply_id, reply_id]) + + XCTAssertEqual(refs.reduce(into: Array<NoteId>(), { xs, r in + if let note_id = r.is_reply?.note_id { xs.append(note_id) } + }), [direct_reply_id, reply_id]) + } + + func test_repost_root() { + let mention_hex = "7c7d37bc8c04d2ec65cbc7d9275253e6b5cc34b5d10439f158194a3feefa8d52" + let tags = [ + ["e", mention_hex, "", "mention"], + ] + + let mention_id = NoteId(hex: mention_hex)! + let note = NdbNote(content: "hi", keypair: test_keypair, kind: 1, tags: tags)! + let refs = interp_event_refs_without_mentions_ndb(note.referenced_noterefs) + + XCTAssertEqual(refs.reduce(into: Array<NoteId>(), { xs, r in + if let note_id = r.is_thread_id?.note_id { xs.append(note_id) } + }), []) + + XCTAssertEqual(refs.reduce(into: Array<NoteId>(), { xs, r in + if let note_id = r.is_direct_reply?.note_id { xs.append(note_id) } + }), []) + + XCTAssertEqual(refs.reduce(into: Array<NoteId>(), { xs, r in + if let note_id = r.is_reply?.note_id { xs.append(note_id) } + }), []) + } + + func test_direct_reply_old_nip10() { + let root_note_id_hex = "7c7d37bc8c04d2ec65cbc7d9275253e6b5cc34b5d10439f158194a3feefa8d52" + let tags = [ + ["e", root_note_id_hex], + ] + + let root_note_id = NoteId(hex: root_note_id_hex)! + + let note = NdbNote(content: "hi", keypair: test_keypair, kind: 1, tags: tags)! + let refs = interp_event_refs_without_mentions_ndb(note.referenced_noterefs) + + XCTAssertEqual(refs.reduce(into: Array<NoteId>(), { xs, r in + if let note_id = r.is_thread_id?.note_id { xs.append(note_id) } + }), [root_note_id]) + + XCTAssertEqual(refs.reduce(into: Array<NoteId>(), { xs, r in + if let note_id = r.is_direct_reply?.note_id { xs.append(note_id) } + }), [root_note_id]) + + XCTAssertEqual(refs.reduce(into: Array<NoteId>(), { xs, r in + if let note_id = r.is_reply?.note_id { xs.append(note_id) } + }), [root_note_id]) + } + + func test_direct_reply_new_nip10() { + let root_note_id_hex = "7c7d37bc8c04d2ec65cbc7d9275253e6b5cc34b5d10439f158194a3feefa8d52" + let tags = [ + ["e", root_note_id_hex, "", "root"], + ] + + let root_note_id = NoteId(hex: root_note_id_hex)! + + let note = NdbNote(content: "hi", keypair: test_keypair, kind: 1, tags: tags)! + let refs = interp_event_refs_without_mentions_ndb(note.referenced_noterefs) + + XCTAssertEqual(refs.reduce(into: Array<NoteId>(), { xs, r in + if let note_id = r.is_thread_id?.note_id { xs.append(note_id) } + }), [root_note_id]) + + XCTAssertEqual(refs.reduce(into: Array<NoteId>(), { xs, r in + if let note_id = r.is_direct_reply?.note_id { xs.append(note_id) } + }), [root_note_id]) + + XCTAssertEqual(refs.reduce(into: Array<NoteId>(), { xs, r in + if let note_id = r.is_reply?.note_id { xs.append(note_id) } + }), [root_note_id]) + } + + func test_deprecated_nip10() { + let root_note_id_hex = "7c7d37bc8c04d2ec65cbc7d9275253e6b5cc34b5d10439f158194a3feefa8d52" + let direct_reply_hex = "7c7d37bc8c04d2ec65cbc7d9275253e6b5cc34b5d10439f158194a3feefa8d51" + let reply_hex = "7c7d37bc8c04d2ec65cbc7d9275253e6b5cc34b5d10439f158194a3feefa8d53" + let tags = [ + ["e", root_note_id_hex], + ["e", direct_reply_hex], + ["e", reply_hex], + ] + + let root_note_id = NoteId(hex: root_note_id_hex)! + let direct_reply_id = NoteId(hex: direct_reply_hex)! + let reply_id = NoteId(hex: reply_hex)! + + let note = NdbNote(content: "hi", keypair: test_keypair, kind: 1, tags: tags)! + let refs = interp_event_refs_without_mentions_ndb(note.referenced_noterefs) + + XCTAssertEqual(refs.reduce(into: Array<NoteId>(), { xs, r in + if let note_id = r.is_thread_id?.note_id { xs.append(note_id) } + }), [root_note_id]) + + XCTAssertEqual(refs.reduce(into: Array<NoteId>(), { xs, r in + if let note_id = r.is_direct_reply?.note_id { xs.append(note_id) } + }), [direct_reply_id, reply_id]) + + XCTAssertEqual(refs.reduce(into: Array<NoteId>(), { xs, r in + if let note_id = r.is_reply?.note_id { xs.append(note_id) } + }), [direct_reply_id, reply_id]) + } + + + + func testPerformanceExample() throws { + // This is an example of a performance test case. + self.measure { + // Put the code you want to measure the time of here. + } + } + +}