You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

82 lines
2.4 KiB

import { logContentSpacing, reprString } from '@/lib/content-spacing-debug'
import customEmojiService from '@/services/custom-emoji.service'
import { emojis, shortcodeToEmoji } from '@tiptap/extension-emoji'
import { JSONContent } from '@tiptap/react'
import { nip19 } from 'nostr-tools'
export function parseEditorJsonToText(node?: JSONContent) {
const rawJoined = _parseEditorJsonToText(node)
let text = rawJoined.trim()
const trace = rawJoined.includes('nostr:') || /npub1|nprofile1/.test(rawJoined)
if (trace) {
logContentSpacing('parseEditorJsonToText:joined', {
beforeTrimRepr: reprString(rawJoined),
afterTrimRepr: reprString(text)
})
}
const regex = /(?:^|\s)(nevent|naddr|nprofile|npub)1[a-zA-Z0-9]+/g
text = text.replace(regex, (match) => {
const trimmed = match.trim()
const leadingSpace = match.startsWith(' ') ? ' ' : ''
try {
nip19.decode(trimmed)
return `${leadingSpace}nostr:${trimmed}`
} catch {
return match
}
})
// Ensure space before nostr: when not already preceded by space (fixes "Like:nostr:npub" and "Like:\nnostr:npub")
const beforeNostrSpacePass = text
text = text.replace(/(.)(?=nostr:)/g, (_, prev) => (prev === ' ' ? prev : prev + ' '))
if (trace) {
logContentSpacing('parseEditorJsonToText:after-nostr-prefix-pass', {
beforeRepr: reprString(beforeNostrSpacePass),
afterRepr: reprString(text)
})
}
return text
}
function _parseEditorJsonToText(node?: JSONContent): string {
if (!node) return ''
if (typeof node === 'string') return node
if (node.type === 'text') {
return node.text || ''
}
if (node.type === 'hardBreak') {
return '\n'
}
if (Array.isArray(node.content)) {
return (
node.content.map(_parseEditorJsonToText).join('') + (node.type === 'paragraph' ? '\n' : '')
)
}
switch (node.type) {
case 'paragraph':
return '\n'
case 'mention':
return node.attrs ? `nostr:${node.attrs.id}` : ''
case 'emoji':
return parseEmojiNodeName(node.attrs?.name)
default:
return ''
}
}
function parseEmojiNodeName(name?: string): string {
if (!name) return ''
if (customEmojiService.isCustomEmojiId(name)) {
const custom = customEmojiService.getEmojiById(name)
return custom ? `:${custom.shortcode}:` : `:${name}:`
}
const native = shortcodeToEmoji(name, emojis) ?? shortcodeToEmoji(name.replace(/\s+/g, '_'), emojis)
return native?.emoji ?? `:${name}:`
}