Add NIP-30 module for custom emojis

This commit is contained in:
Alex Gleason 2023-07-06 13:08:38 -05:00 committed by fiatjaf_
parent 9cd4f16e45
commit 36e0de2a68
3 changed files with 87 additions and 1 deletions

View File

@ -13,7 +13,7 @@ export interface NostrURIMatch extends NostrURI {
} }
/** Find and decode all NIP-21 URIs. */ /** Find and decode all NIP-21 URIs. */
export function* matchAll(content: string): Iterable<NostrURIMatch> { export function * matchAll(content: string): Iterable<NostrURIMatch> {
const matches = content.matchAll(regex()) const matches = content.matchAll(regex())
for (const match of matches) { for (const match of matches) {

32
nip30.test.ts Normal file
View File

@ -0,0 +1,32 @@
import {matchAll, replaceAll} from './nip30.ts'
test('matchAll', () => {
const result = matchAll('Hello :blobcat: :disputed: ::joy:joy:')
expect([...result]).toEqual([
{
name: 'blobcat',
shortcode: ':blobcat:',
start: 6,
end: 15
},
{
name: 'disputed',
shortcode: ':disputed:',
start: 16,
end: 26
}
])
})
test('replaceAll', () => {
const content = 'Hello :blobcat: :disputed: ::joy:joy:'
const result = replaceAll(content, ({name}) => {
return `<img src="https://ditto.pub/emoji/${name}.png" />`
})
expect(result).toEqual(
'Hello <img src="https://ditto.pub/emoji/blobcat.png" /> <img src="https://ditto.pub/emoji/disputed.png" /> ::joy:joy:',
)
})

54
nip30.ts Normal file
View File

@ -0,0 +1,54 @@
/** Regex for a single emoji shortcode. */
export const EMOJI_SHORTCODE_REGEX = /:(\w+):/
/** Regex to find emoji shortcodes in content. */
export const regex = () => new RegExp(`\\B${EMOJI_SHORTCODE_REGEX.source}\\B`, 'g')
/** Represents a Nostr custom emoji. */
export interface CustomEmoji {
/** The matched emoji name with colons. */
shortcode: `:${string}:`
/** The matched emoji name without colons. */
name: string
}
/** Match result for a custom emoji in text content. */
export interface CustomEmojiMatch extends CustomEmoji {
/** Index where the emoji begins in the text content. */
start: number
/** Index where the emoji ends in the text content. */
end: number
}
/** Find all custom emoji shortcodes. */
export function * matchAll(content: string): Iterable<CustomEmojiMatch> {
const matches = content.matchAll(regex())
for (const match of matches) {
try {
const [shortcode, name] = match
yield {
shortcode: shortcode as `:${string}:`,
name,
start: match.index!,
end: match.index! + shortcode.length
}
} catch (_e) {
// do nothing
}
}
}
/** Replace all emoji shortcodes in the content. */
export function replaceAll(
content: string,
replacer: (match: CustomEmoji) => string
): string {
return content.replaceAll(regex(), (shortcode, name) => {
return replacer({
shortcode: shortcode as `:${string}:`,
name,
})
})
}