Skip to content

Commit

Permalink
Stabalized the output of splitRangesOnEmojis
Browse files Browse the repository at this point in the history
  • Loading branch information
shubham1206agra committed Jan 11, 2025
1 parent 14eed4b commit 1bfd6e2
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 17 deletions.
36 changes: 26 additions & 10 deletions src/__tests__/splitRangesOnEmojis.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import type {MarkdownRange} from '../commonTypes';
import {splitRangesOnEmojis} from '../rangeUtils';

const sortRanges = (ranges: MarkdownRange[]) => {
return ranges.sort((a, b) => a.start - b.start);
};

test('no overlap', () => {
const markdownRanges: MarkdownRange[] = [
{type: 'strikethrough', start: 0, length: 10},
Expand All @@ -28,6 +24,32 @@ test('overlap different type', () => {
expect(splittedRanges).toEqual(markdownRanges);
});

test('overlap with bold and emoji type', () => {
const markdownRanges: MarkdownRange[] = [
{type: 'syntax', start: 0, length: 1},
{type: 'italic', start: 1, length: 4},
{type: 'syntax', start: 1, length: 1},
{type: 'bold', start: 2, length: 2},
{type: 'emoji', start: 2, length: 2},
{type: 'syntax', start: 4, length: 1},
{type: 'syntax', start: 5, length: 1},
];

const expectedResult = [
{type: 'syntax', start: 0, length: 1},
{type: 'italic', start: 1, length: 1},
{type: 'syntax', start: 1, length: 1},
{type: 'bold', start: 2, length: 2},
{type: 'emoji', start: 2, length: 2},
{type: 'italic', start: 4, length: 1},
{type: 'syntax', start: 4, length: 1},
{type: 'syntax', start: 5, length: 1},
];

const splittedRanges = splitRangesOnEmojis(markdownRanges, 'italic');
expect(splittedRanges).toEqual(expectedResult);
});

describe('single overlap', () => {
test('emoji at the beginning', () => {
let markdownRanges: MarkdownRange[] = [
Expand All @@ -36,7 +58,6 @@ describe('single overlap', () => {
];

markdownRanges = splitRangesOnEmojis(markdownRanges, 'strikethrough');
sortRanges(markdownRanges);

expect(markdownRanges).toEqual([
{type: 'emoji', start: 0, length: 2},
Expand All @@ -51,7 +72,6 @@ describe('single overlap', () => {
];

markdownRanges = splitRangesOnEmojis(markdownRanges, 'strikethrough');
sortRanges(markdownRanges);

expect(markdownRanges).toEqual([
{type: 'strikethrough', start: 0, length: 3},
Expand All @@ -67,7 +87,6 @@ describe('single overlap', () => {
];

markdownRanges = splitRangesOnEmojis(markdownRanges, 'strikethrough');
sortRanges(markdownRanges);

expect(markdownRanges).toEqual([
{type: 'strikethrough', start: 0, length: 8},
Expand All @@ -83,7 +102,6 @@ describe('single overlap', () => {
];

markdownRanges = splitRangesOnEmojis(markdownRanges, 'strikethrough');
sortRanges(markdownRanges);

expect(markdownRanges).toEqual([
{type: 'strikethrough', start: 0, length: 3},
Expand Down Expand Up @@ -122,7 +140,6 @@ describe('multiple overlaps', () => {
];

markdownRanges = splitRangesOnEmojis(markdownRanges, 'strikethrough');
sortRanges(markdownRanges);

expect(markdownRanges).toEqual([
{type: 'italic', start: 0, length: 20},
Expand All @@ -146,7 +163,6 @@ describe('multiple overlaps', () => {

markdownRanges = splitRangesOnEmojis(markdownRanges, 'strikethrough');
markdownRanges = splitRangesOnEmojis(markdownRanges, 'italic');
sortRanges(markdownRanges);

expect(markdownRanges).toEqual([
{type: 'italic', start: 0, length: 3},
Expand Down
6 changes: 3 additions & 3 deletions src/parseExpensiMark.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,11 +253,11 @@ function parseExpensiMark(markdown: string): MarkdownRange[] {
return [];
}

let splittedRanges = splitRangesOnEmojis(ranges, 'italic');
let splittedRanges = sortRanges(ranges);
splittedRanges = splitRangesOnEmojis(ranges, 'italic');
splittedRanges = splitRangesOnEmojis(splittedRanges, 'strikethrough');

const sortedRanges = sortRanges(splittedRanges);
const groupedRanges = groupRanges(sortedRanges);
const groupedRanges = groupRanges(splittedRanges);

return groupedRanges;
}
Expand Down
86 changes: 82 additions & 4 deletions src/rangeUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,44 @@

import type {MarkdownRange, MarkdownType} from './commonTypes';

class MarkdownRangeQueue {
items: Record<number, MarkdownRange>;

frontIndex: number;

backIndex: number;

constructor() {
this.items = {};
this.frontIndex = 0;
this.backIndex = 0;
}

enqueue(item: MarkdownRange) {
this.items[this.backIndex] = item;
this.backIndex += 1;
}

dequeue() {
const item = this.items[this.frontIndex];
delete this.items[this.frontIndex];
this.frontIndex += 1;
return item;
}

peek() {
return this.items[this.frontIndex];
}

isEmpty() {
return this.frontIndex === this.backIndex;
}

get printQueue() {
return this.items;
}
}

// getTagPriority returns a priority for a tag, higher priority means the tag should be processed first
function getTagPriority(tag: string) {
switch (tag) {
Expand Down Expand Up @@ -55,9 +93,20 @@ function ungroupRanges(ranges: MarkdownRange[]): MarkdownRange[] {
return ungroupedRanges;
}

function compareRanges(a: MarkdownRange | undefined, b: MarkdownRange | undefined) {
if (!a) {
return -1;
}
if (!b) {
return 1;
}
return a.start - b.start || b.length - a.length || getTagPriority(b.type) - getTagPriority(a.type) || 0;
}

function splitRangesOnEmojis(ranges: MarkdownRange[], type: MarkdownType): MarkdownRange[] {
const emojiRanges: MarkdownRange[] = ranges.filter((range) => range.type === 'emoji');
const newRanges: MarkdownRange[] = [];
const queue = new MarkdownRangeQueue();

let i = 0;
let j = 0;
Expand All @@ -68,9 +117,17 @@ function splitRangesOnEmojis(ranges: MarkdownRange[], type: MarkdownType): Markd
}

if (currentRange.type !== type) {
newRanges.push(currentRange);
i++;
if (queue.isEmpty() || compareRanges(currentRange, queue.peek()) < 0) {
newRanges.push(currentRange);
i++;
} else {
const newRange = queue.dequeue();
if (newRange) {
newRanges.push(newRange);
}
}
} else {
let firstTimeEntry = true;
// Iterate through all emoji ranges before the end of the current range, splitting the current range at each intersection.
while (j < emojiRanges.length) {
const emojiRange = emojiRanges[j];
Expand All @@ -96,18 +153,39 @@ function splitRangesOnEmojis(ranges: MarkdownRange[], type: MarkdownType): Markd
currentRange.length = currentEnd - emojiEnd;

if (newRange.length > 0) {
newRanges.push(newRange);
if (firstTimeEntry) {
newRanges.push(newRange);
} else {
queue.enqueue(newRange);
}
}
firstTimeEntry = false;
}
j++;
}

if (currentRange.length > 0) {
newRanges.push(currentRange);
if (firstTimeEntry) {
while (!queue.isEmpty() && compareRanges(currentRange, queue.peek()) >= 0) {
const newRange = queue.dequeue();
if (newRange) {
newRanges.push(newRange);
}
}
newRanges.push(currentRange);
} else {
queue.enqueue(currentRange);
}
}
i++;
}
}
while (!queue.isEmpty()) {
const newRange = queue.dequeue();
if (newRange) {
newRanges.push(newRange);
}
}
return newRanges;
}

Expand Down

0 comments on commit 1bfd6e2

Please sign in to comment.