Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions src/text/discordMarkdown.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { describe, expect, it } from 'vitest'
import { parseDiscordMarkdown, stripDiscordMarkdown } from './discordMarkdown'
import { segmentStyledText } from './segment'

describe('stripDiscordMarkdown', () => {
it('leaves plain text alone', () => {
Expand Down Expand Up @@ -202,4 +203,44 @@ describe('parseDiscordMarkdown', () => {
it('reveals a spoiler as plain, unstyled text', () => {
expect(parseDiscordMarkdown('||spoiler||')).toEqual([{ value: 'spoiler' }])
})

it('keeps a custom emoji bracketed, not stripped to its bare shortcode:id', () => {
expect(parseDiscordMarkdown('<:blob_x:1245750752115167293>')).toEqual([
{ value: '<:blob_x:1245750752115167293>' },
])
expect(parseDiscordMarkdown('<a:spin:123456789012345678>')).toEqual([
{ value: '<a:spin:123456789012345678>' },
])
})

it('keeps a mention bracketed, not stripped to its bare id', () => {
expect(parseDiscordMarkdown('<@123456789012345678>')).toEqual([
{ value: '<@123456789012345678>' },
])
expect(parseDiscordMarkdown('<@!123456789012345678>')).toEqual([
{ value: '<@!123456789012345678>' },
])
expect(parseDiscordMarkdown('<@&123456789012345678>')).toEqual([
{ value: '<@&123456789012345678>' },
])
expect(parseDiscordMarkdown('<#123456789012345678>')).toEqual([
{ value: '<#123456789012345678>' },
])
})

it('keeps a custom emoji bracketed within stripDiscordMarkdown too', () => {
expect(stripDiscordMarkdown('<:blob_x:1245750752115167293> hi')).toBe(
'<:blob_x:1245750752115167293> hi',
)
})

it('resolves to an actual emoji segment once fed through segmentStyledText, matching the raw path', () => {
const raw = segmentStyledText([{ value: '<:blob_x:1245750752115167293> hi' }])
const viaDiscordMode = segmentStyledText(
parseDiscordMarkdown('<:blob_x:1245750752115167293> hi'),
)

expect(viaDiscordMode).toEqual(raw)
expect(viaDiscordMode[0]).toMatchObject({ kind: 'emoji', source: 'discord' })
})
})
15 changes: 14 additions & 1 deletion src/text/discordMarkdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,25 @@ const WRAPPER_ELEMENTS = new Set<ParsedElement>([
'list',
])

/**
* Element kinds whose delimiters are the whole point — `.content` strips exactly the `<`/`>` that later stages (`segment.ts`'s `splitDiscord()`, for `emoji`) need to recognize the construct, so `.raw` has to survive instead. `code`/`codeBlock` are the opposite: their fence is not meant to display, so `.content` (the body without it) is correct for those.
*/
const RAW_ELEMENTS = new Set<ParsedElement>([
'emoji',
'mention',
'globalMention',
'roleMention',
'gameMention',
'channelMention',
'slashCommand',
])

function parseInto(text: string, style: TextStyle | undefined): StyledRun[] {
const out: StyledRun[] = []

for (const token of parse(text)) {
if (!WRAPPER_ELEMENTS.has(token.element)) {
pushStyledRun(out, token.content, style)
pushStyledRun(out, RAW_ELEMENTS.has(token.element) ? token.raw : token.content, style)
continue
}
const addedStyle = styleFor(token.element)
Expand Down
Loading