From 423cd67c880f140e95e6749c2cf8a3072e831339 Mon Sep 17 00:00:00 2001 From: TaduJR Date: Sun, 21 Dec 2025 19:51:22 +0300 Subject: [PATCH] fix: Add bold to excludeRangeTypesFromFormatting to fix emoji duplication on web --- src/__tests__/splitRangesOnEmojis.test.ts | 78 +++++++++++++++++++++++ src/parseExpensiMark.ts | 3 +- 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/src/__tests__/splitRangesOnEmojis.test.ts b/src/__tests__/splitRangesOnEmojis.test.ts index 6bd33220..c801479d 100644 --- a/src/__tests__/splitRangesOnEmojis.test.ts +++ b/src/__tests__/splitRangesOnEmojis.test.ts @@ -109,6 +109,41 @@ describe('single overlap', () => { {type: 'emoji', start: 4, length: 2}, ]); }); + + test('bold with emoji in the middle', () => { + let markdownRanges: MarkdownRange[] = [ + {type: 'bold', start: 0, length: 10}, + {type: 'emoji', start: 3, length: 2}, + ]; + + markdownRanges = excludeRangeTypesFromFormatting(markdownRanges, 'bold', getRangesToExcludeFormatting(markdownRanges)); + sortRanges(markdownRanges); + + expect(markdownRanges).toEqual([ + {type: 'bold', start: 0, length: 3}, + {type: 'emoji', start: 3, length: 2}, + {type: 'bold', start: 5, length: 5}, + ]); + }); + + test('bold with multiple emojis', () => { + let markdownRanges: MarkdownRange[] = [ + {type: 'bold', start: 0, length: 10}, + {type: 'emoji', start: 2, length: 2}, + {type: 'emoji', start: 6, length: 2}, + ]; + + markdownRanges = excludeRangeTypesFromFormatting(markdownRanges, 'bold', getRangesToExcludeFormatting(markdownRanges)); + sortRanges(markdownRanges); + + expect(markdownRanges).toEqual([ + {type: 'bold', start: 0, length: 2}, + {type: 'emoji', start: 2, length: 2}, + {type: 'bold', start: 4, length: 2}, + {type: 'emoji', start: 6, length: 2}, + {type: 'bold', start: 8, length: 2}, + ]); + }); }); describe('multiple overlaps', () => { @@ -160,4 +195,47 @@ describe('multiple overlaps', () => { {type: 'strikethrough', start: 22, length: 5}, ]); }); + + test('splitting on three types', () => { + let markdownRanges: MarkdownRange[] = [ + {type: 'italic', start: 0, length: 20}, + {type: 'bold', start: 2, length: 12}, + {type: 'strikethrough', start: 4, length: 8}, + {type: 'emoji', start: 6, length: 2}, + ]; + + markdownRanges = excludeRangeTypesFromFormatting(markdownRanges, 'italic', getRangesToExcludeFormatting(markdownRanges)); + markdownRanges = excludeRangeTypesFromFormatting(markdownRanges, 'bold', getRangesToExcludeFormatting(markdownRanges)); + markdownRanges = excludeRangeTypesFromFormatting(markdownRanges, 'strikethrough', getRangesToExcludeFormatting(markdownRanges)); + sortRanges(markdownRanges); + + expect(markdownRanges).toEqual([ + {type: 'italic', start: 0, length: 6}, + {type: 'bold', start: 2, length: 4}, + {type: 'strikethrough', start: 4, length: 2}, + {type: 'emoji', start: 6, length: 2}, + {type: 'italic', start: 8, length: 12}, + {type: 'bold', start: 8, length: 6}, + {type: 'strikethrough', start: 8, length: 4}, + ]); + }); + + test('nested ranges with emoji', () => { + let markdownRanges: MarkdownRange[] = [ + {type: 'italic', start: 1, length: 15}, + {type: 'bold', start: 5, length: 7}, + {type: 'emoji', start: 10, length: 2}, + ]; + + markdownRanges = excludeRangeTypesFromFormatting(markdownRanges, 'italic', getRangesToExcludeFormatting(markdownRanges)); + markdownRanges = excludeRangeTypesFromFormatting(markdownRanges, 'bold', getRangesToExcludeFormatting(markdownRanges)); + sortRanges(markdownRanges); + + expect(markdownRanges).toEqual([ + {type: 'italic', start: 1, length: 9}, + {type: 'bold', start: 5, length: 5}, + {type: 'emoji', start: 10, length: 2}, + {type: 'italic', start: 12, length: 4}, + ]); + }); }); diff --git a/src/parseExpensiMark.ts b/src/parseExpensiMark.ts index 7a1745eb..6a5d4762 100644 --- a/src/parseExpensiMark.ts +++ b/src/parseExpensiMark.ts @@ -256,9 +256,10 @@ function parseExpensiMark(markdown: string): MarkdownRange[] { } let markdownRanges = sortRanges(ranges); - // Prevent italic and strikethrough formatting inside emojis and inline code blocks + // Prevent italic, bold and strikethrough formatting inside emojis and inline code blocks const rangesToExclude = getRangesToExcludeFormatting(markdownRanges); markdownRanges = excludeRangeTypesFromFormatting(markdownRanges, 'italic', rangesToExclude); + markdownRanges = excludeRangeTypesFromFormatting(markdownRanges, 'bold', rangesToExclude); markdownRanges = excludeRangeTypesFromFormatting(markdownRanges, 'strikethrough', rangesToExclude); const groupedRanges = groupRanges(markdownRanges);