Skip to content

Commit

Permalink
Fix custom parsing on the web (#585)
Browse files Browse the repository at this point in the history
  • Loading branch information
Skalakid authored Jan 7, 2025
1 parent 24460a7 commit 9030bc5
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 54 deletions.
40 changes: 1 addition & 39 deletions src/parseExpensiMark.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {unescapeText} from 'expensify-common/dist/utils';
import {decode} from 'html-entities';
import type {WorkletFunction} from 'react-native-reanimated/lib/typescript/commonTypes';
import type {MarkdownType, MarkdownRange} from './commonTypes';
import {groupRanges, sortRanges} from './rangeUtils';

function isWeb() {
return Platform.OS === 'web';
Expand Down Expand Up @@ -233,45 +234,6 @@ function parseTreeToTextAndRanges(tree: StackItem): [string, MarkdownRange[]] {
return [text, ranges];
}

// getTagPriority returns a priority for a tag, higher priority means the tag should be processed first
function getTagPriority(tag: string) {
switch (tag) {
case 'blockquote':
return 2;
case 'h1':
return 1;
default:
return 0;
}
}

function sortRanges(ranges: MarkdownRange[]) {
// sort ranges by start position, then by length, then by tag hierarchy
return ranges.sort((a, b) => a.start - b.start || b.length - a.length || getTagPriority(b.type) - getTagPriority(a.type) || 0);
}

function groupRanges(ranges: MarkdownRange[]) {
const lastVisibleRangeIndex: {[key in MarkdownType]?: number} = {};

return ranges.reduce((acc, range) => {
const start = range.start;
const end = range.start + range.length;

const rangeWithSameStyleIndex = lastVisibleRangeIndex[range.type];
const sameStyleRange = rangeWithSameStyleIndex !== undefined ? acc[rangeWithSameStyleIndex] : undefined;

if (sameStyleRange && sameStyleRange.start <= start && sameStyleRange.start + sameStyleRange.length >= end && range.length > 1) {
// increment depth of overlapping range
sameStyleRange.depth = (sameStyleRange.depth || 1) + 1;
} else {
lastVisibleRangeIndex[range.type] = acc.length;
acc.push(range);
}

return acc;
}, [] as MarkdownRange[]);
}

function parseExpensiMark(markdown: string): MarkdownRange[] {
if (markdown.length > MAX_PARSABLE_LENGTH) {
return [];
Expand Down
56 changes: 56 additions & 0 deletions src/rangeUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import type {MarkdownRange, MarkdownType} from './commonTypes';

// getTagPriority returns a priority for a tag, higher priority means the tag should be processed first
function getTagPriority(tag: string) {
switch (tag) {
case 'blockquote':
return 2;
case 'h1':
return 1;
default:
return 0;
}
}

function sortRanges(ranges: MarkdownRange[]) {
// sort ranges by start position, then by length, then by tag hierarchy
return ranges.sort((a, b) => a.start - b.start || b.length - a.length || getTagPriority(b.type) - getTagPriority(a.type) || 0);
}

function groupRanges(ranges: MarkdownRange[]) {
const lastVisibleRangeIndex: {[key in MarkdownType]?: number} = {};

return ranges.reduce((acc, range) => {
const start = range.start;
const end = range.start + range.length;

const rangeWithSameStyleIndex = lastVisibleRangeIndex[range.type];
const sameStyleRange = rangeWithSameStyleIndex !== undefined ? acc[rangeWithSameStyleIndex] : undefined;

if (sameStyleRange && sameStyleRange.start <= start && sameStyleRange.start + sameStyleRange.length >= end && range.length > 1) {
// increment depth of overlapping range
sameStyleRange.depth = (sameStyleRange.depth || 1) + 1;
} else {
lastVisibleRangeIndex[range.type] = acc.length;
acc.push(range);
}

return acc;
}, [] as MarkdownRange[]);
}

function ungroupRanges(ranges: MarkdownRange[]): MarkdownRange[] {
const ungroupedRanges: MarkdownRange[] = [];
ranges.forEach((range) => {
if (!range.depth) {
ungroupedRanges.push(range);
}
const {depth, ...rangeWithoutDepth} = range;
Array.from({length: depth!}).forEach(() => {
ungroupedRanges.push(rangeWithoutDepth);
});
});
return ungroupedRanges;
}

export {sortRanges, groupRanges, ungroupRanges};
19 changes: 4 additions & 15 deletions src/web/utils/parserUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {getCurrentCursorPosition, moveCursorToEnd, setCursorPosition} from './cu
import {addStyleToBlock, extendBlockStructure, getFirstBlockMarkdownRange, isBlockMarkdownType} from './blockUtils';
import type {InlineImagesInputProps, MarkdownRange} from '../../commonTypes';
import {getAnimationCurrentTimes, updateAnimationsTime} from './animationUtils';
import {sortRanges, ungroupRanges} from '../../rangeUtils';

type Paragraph = {
text: string;
Expand All @@ -14,20 +15,6 @@ type Paragraph = {
markdownRanges: MarkdownRange[];
};

function ungroupRanges(ranges: MarkdownRange[]): MarkdownRange[] {
const ungroupedRanges: MarkdownRange[] = [];
ranges.forEach((range) => {
if (!range.depth) {
ungroupedRanges.push(range);
}
const {depth, ...rangeWithoutDepth} = range;
Array.from({length: depth!}).forEach(() => {
ungroupedRanges.push(rangeWithoutDepth);
});
});
return ungroupedRanges;
}

function splitTextIntoLines(text: string): Paragraph[] {
let lineStartIndex = 0;
const lines: Paragraph[] = text.split('\n').map((line) => {
Expand Down Expand Up @@ -167,7 +154,9 @@ function parseRangesToHTMLNodes(
return {dom: rootElement, tree: rootNode};
}

const markdownRanges = ungroupRanges(ranges);
// Sort all ranges by start position, length, and by tag hierarchy so the styles and text are applied in correct order
const sortedRanges = sortRanges(ranges);
const markdownRanges = ungroupRanges(sortedRanges);
lines = mergeLinesWithMultilineTags(lines, markdownRanges);

let lastRangeEndIndex = 0;
Expand Down

0 comments on commit 9030bc5

Please sign in to comment.