Find a comment's root through reader(Comment).root() instead of three hand-rolled K/A/E parsers

This commit is contained in:
Jon Staab 2026-09-25 16:00:58 -07:00
parent e7c7fac112
commit f130af4edd
3 changed files with 42 additions and 20 deletions

View file

@ -1,6 +1,18 @@
import {derived, get, readable, writable} from "svelte/store" import {derived, get, readable, writable} from "svelte/store"
import type {Readable} from "svelte/store" import type {Readable} from "svelte/store"
import {batch, call, int, ms, now, on, sleep, uniqBy, MONTH, YEAR} from "@welshman/lib" import {
batch,
call,
int,
ms,
now,
on,
removeUndefined,
sleep,
uniqBy,
MONTH,
YEAR,
} from "@welshman/lib"
import { import {
COMMENT, COMMENT,
DELETE, DELETE,
@ -17,7 +29,7 @@ import {
matchFilters, matchFilters,
tagValues, tagValues,
} from "@welshman/util" } from "@welshman/util"
import {TimeEvent} from "@welshman/domain" import {Comment, TimeEvent} from "@welshman/domain"
import type {Maybe} from "@welshman/lib" import type {Maybe} from "@welshman/lib"
import type {Filter, TrustedEvent} from "@welshman/util" import type {Filter, TrustedEvent} from "@welshman/util"
import {mergeRepositoryUpdates} from "@welshman/net" import {mergeRepositoryUpdates} from "@welshman/net"
@ -51,10 +63,15 @@ const mergeSorted = <T>(left: T[], right: T[], compare: (a: T, b: T) => number)
} }
// A NIP-22 comment points at its thread root with `E`/`A`, which is the scope a reply count wants. // A NIP-22 comment points at its thread root with `E`/`A`, which is the scope a reply count wants.
const getTargets = ({kind, tags}: TrustedEvent) => const getTargets = (event: TrustedEvent) => {
kind === COMMENT if (event.kind === COMMENT) {
? [...tagValues(hexTags("E"), tags), ...tagValues(addressTags("A"), tags)] const {id, address} = reader(Comment)(event).root()
: [...tagValues(hexTags("e"), tags), ...tagValues(addressTags("a"), tags)]
return removeUndefined([id, address])
}
return [...tagValues(hexTags("e"), event.tags), ...tagValues(addressTags("a"), event.tags)]
}
// A related event may point at a replaceable one by either id or address, so both are keys // A related event may point at a replaceable one by either id or address, so both are keys
const getKeys = (event: TrustedEvent) => const getKeys = (event: TrustedEvent) =>

View file

@ -13,10 +13,11 @@ import {
makeHttpAuth, makeHttpAuth,
makeHttpAuthHeader, makeHttpAuthHeader,
} from "@welshman/util" } from "@welshman/util"
import {Comment} from "@welshman/domain"
import {synced, throttled, withGetter} from "@welshman/store" import {synced, throttled, withGetter} from "@welshman/store"
import {Relays, RoomLists} from "@welshman/app" import {Relays, RoomLists} from "@welshman/app"
import {deriveEventsByIdByUrl} from "@app/repository" import {deriveEventsByIdByUrl} from "@app/repository"
import {app, fromApp} from "@app/core" import {app, fromApp, reader} from "@app/core"
import {makeRoomPath, makeSpaceChatPath, makeChatPath, makeContentPath} from "@app/routes" import {makeRoomPath, makeSpaceChatPath, makeChatPath, makeContentPath} from "@app/routes"
import {CONTENT_KINDS, makeCommentFilter} from "@app/content" import {CONTENT_KINDS, makeCommentFilter} from "@app/content"
import {getIsMuted, notificationSettings, userSettingsValues} from "@app/settings" import {getIsMuted, notificationSettings, userSettingsValues} from "@app/settings"
@ -185,8 +186,9 @@ const getContentTarget = (event: TrustedEvent) => {
} }
if (event.kind === COMMENT) { if (event.kind === COMMENT) {
const kind = parseInt(tagValue(tagSpec("K"), event.tags) || "") const root = reader(Comment)(event).root()
const idOrAddress = tagValue(tagSpec("A"), event.tags) || tagValue(tagSpec("E"), event.tags) const kind = parseInt(root.kind || "")
const idOrAddress = root.address || root.id
if (CONTENT_KINDS.includes(kind) && idOrAddress) { if (CONTENT_KINDS.includes(kind) && idOrAddress) {
return {kind, idOrAddress} return {kind, idOrAddress}

View file

@ -5,6 +5,7 @@ import {identity, tryCatch} from "@welshman/lib"
import type {TrustedEvent} from "@welshman/util" import type {TrustedEvent} from "@welshman/util"
import { import {
CLASSIFIED, CLASSIFIED,
COMMENT,
EVENT_TIME, EVENT_TIME,
LONG_FORM, LONG_FORM,
MESSAGE, MESSAGE,
@ -19,7 +20,8 @@ import {
tagValue, tagValue,
tagValues, tagValues,
} from "@welshman/util" } from "@welshman/util"
import {app, messagingRelayLists, user} from "@app/core" import {Comment} from "@welshman/domain"
import {app, messagingRelayLists, reader, user} from "@app/core"
import {makeChatId} from "@app/chats" import {makeChatId} from "@app/chats"
import {entityLink, PLATFORM_URL, PLATFORM_RELAYS} from "@app/env" import {entityLink, PLATFORM_URL, PLATFORM_RELAYS} from "@app/env"
import {decodeRelay, encodeRelay} from "@app/relays" import {decodeRelay, encodeRelay} from "@app/relays"
@ -219,19 +221,20 @@ export const makeEventPath = (event: TrustedEvent, urls: string[]) => {
return path return path
} }
const parentKind = tagValue(tagSpec("K"), event.tags) if (event.kind === COMMENT) {
const parentIdOrAddress = const root = reader(Comment)(event).root()
tagValue(tagSpec("A"), event.tags) ?? tagValue(tagSpec("E"), event.tags) const rootIdOrAddress = root.address ?? root.id
if (parentKind && parentIdOrAddress) { if (root.kind && rootIdOrAddress) {
if (parseInt(parentKind) === MESSAGE) { if (parseInt(root.kind) === MESSAGE) {
return makeMessagePath(url, event) return makeMessagePath(url, event)
} }
const parentPath = makeContentPath(url, parseInt(parentKind), parentIdOrAddress) const rootPath = makeContentPath(url, parseInt(root.kind), rootIdOrAddress)
if (parentPath) { if (rootPath) {
return parentPath return rootPath
}
} }
} }
} }