Skip to content

Commit

Permalink
Add NIP-30 module for custom emojis
Browse files Browse the repository at this point in the history
  • Loading branch information
alexgleason authored and fiatjaf committed Dec 16, 2023
1 parent 9cd4f16 commit 36e0de2
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 1 deletion.
2 changes: 1 addition & 1 deletion nip27.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export interface NostrURIMatch extends NostrURI {
}

/** 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())

for (const match of matches) {
Expand Down
32 changes: 32 additions & 0 deletions nip30.test.ts
Original file line number Diff line number Diff line change
@@ -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 changes: 54 additions & 0 deletions nip30.ts
Original file line number Diff line number Diff line change
@@ -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,
})
})
}

0 comments on commit 36e0de2

Please sign in to comment.