From 9e2a833b97e9e1b6b45beafa909e1c7559c35c8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Ska=C5=82ka?= Date: Thu, 12 Dec 2024 12:10:49 +0100 Subject: [PATCH 1/2] Add range sortiing in web parser --- src/__tests__/parseExpensiMark.test.ts | 2 +- src/__tests__/webParser.test.tsx | 2 +- src/index.tsx | 2 +- src/parseExpensiMark.ts | 2 +- src/web/utils/parserUtils.ts | 4 +++- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/__tests__/parseExpensiMark.test.ts b/src/__tests__/parseExpensiMark.test.ts index b49f46fa3..260ae422f 100644 --- a/src/__tests__/parseExpensiMark.test.ts +++ b/src/__tests__/parseExpensiMark.test.ts @@ -1,6 +1,6 @@ import {expect} from '@jest/globals'; import type {MarkdownRange} from '../commonTypes'; -import parseExpensiMark from '../parseExpensiMark'; +import {parseExpensiMark} from '../parseExpensiMark'; declare module 'expect' { interface Matchers { diff --git a/src/__tests__/webParser.test.tsx b/src/__tests__/webParser.test.tsx index 8fcd31400..4a9a94994 100644 --- a/src/__tests__/webParser.test.tsx +++ b/src/__tests__/webParser.test.tsx @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import {expect} from '@jest/globals'; import {parseRangesToHTMLNodes} from '../web/utils/parserUtils'; -import parseExpensiMark from '../parseExpensiMark'; +import {parseExpensiMark} from '../parseExpensiMark'; declare module 'expect' { interface Matchers { diff --git a/src/index.tsx b/src/index.tsx index 4f3b1d607..b57e2b975 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,4 +1,4 @@ export {default as MarkdownTextInput} from './MarkdownTextInput'; export type {MarkdownTextInputProps, MarkdownStyle} from './MarkdownTextInput'; export type {MarkdownType, MarkdownRange} from './commonTypes'; -export {default as parseExpensiMark} from './parseExpensiMark'; +export {parseExpensiMark} from './parseExpensiMark'; diff --git a/src/parseExpensiMark.ts b/src/parseExpensiMark.ts index 673734af7..1d8e64f0e 100644 --- a/src/parseExpensiMark.ts +++ b/src/parseExpensiMark.ts @@ -292,4 +292,4 @@ function parseExpensiMark(markdown: string): MarkdownRange[] { return groupedRanges; } -export default parseExpensiMark; +export {parseExpensiMark, sortRanges}; diff --git a/src/web/utils/parserUtils.ts b/src/web/utils/parserUtils.ts index 419ed780e..36a73f146 100644 --- a/src/web/utils/parserUtils.ts +++ b/src/web/utils/parserUtils.ts @@ -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} from '../../parseExpensiMark'; type Paragraph = { text: string; @@ -167,7 +168,8 @@ function parseRangesToHTMLNodes( return {dom: rootElement, tree: rootNode}; } - const markdownRanges = ungroupRanges(ranges); + const sortedRanges = sortRanges(ranges); + const markdownRanges = ungroupRanges(sortedRanges); lines = mergeLinesWithMultilineTags(lines, markdownRanges); let lastRangeEndIndex = 0; From 5a3ca8906b68b59b72b23b6dba299d4d7b51a86a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Ska=C5=82ka?= Date: Fri, 13 Dec 2024 09:17:27 +0100 Subject: [PATCH 2/2] Move sortRanges and grouPRanges to rangeUtils file --- src/__tests__/parseExpensiMark.test.ts | 2 +- src/__tests__/webParser.test.tsx | 2 +- src/index.tsx | 2 +- src/parseExpensiMark.ts | 42 ++------------------------ src/rangeUtils.ts | 42 ++++++++++++++++++++++++++ src/web/utils/parserUtils.ts | 2 +- 6 files changed, 48 insertions(+), 44 deletions(-) create mode 100644 src/rangeUtils.ts diff --git a/src/__tests__/parseExpensiMark.test.ts b/src/__tests__/parseExpensiMark.test.ts index 260ae422f..b49f46fa3 100644 --- a/src/__tests__/parseExpensiMark.test.ts +++ b/src/__tests__/parseExpensiMark.test.ts @@ -1,6 +1,6 @@ import {expect} from '@jest/globals'; import type {MarkdownRange} from '../commonTypes'; -import {parseExpensiMark} from '../parseExpensiMark'; +import parseExpensiMark from '../parseExpensiMark'; declare module 'expect' { interface Matchers { diff --git a/src/__tests__/webParser.test.tsx b/src/__tests__/webParser.test.tsx index 4a9a94994..8fcd31400 100644 --- a/src/__tests__/webParser.test.tsx +++ b/src/__tests__/webParser.test.tsx @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import {expect} from '@jest/globals'; import {parseRangesToHTMLNodes} from '../web/utils/parserUtils'; -import {parseExpensiMark} from '../parseExpensiMark'; +import parseExpensiMark from '../parseExpensiMark'; declare module 'expect' { interface Matchers { diff --git a/src/index.tsx b/src/index.tsx index b57e2b975..4f3b1d607 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,4 +1,4 @@ export {default as MarkdownTextInput} from './MarkdownTextInput'; export type {MarkdownTextInputProps, MarkdownStyle} from './MarkdownTextInput'; export type {MarkdownType, MarkdownRange} from './commonTypes'; -export {parseExpensiMark} from './parseExpensiMark'; +export {default as parseExpensiMark} from './parseExpensiMark'; diff --git a/src/parseExpensiMark.ts b/src/parseExpensiMark.ts index 1d8e64f0e..8147de73b 100644 --- a/src/parseExpensiMark.ts +++ b/src/parseExpensiMark.ts @@ -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'; @@ -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 []; @@ -292,4 +254,4 @@ function parseExpensiMark(markdown: string): MarkdownRange[] { return groupedRanges; } -export {parseExpensiMark, sortRanges}; +export default parseExpensiMark; diff --git a/src/rangeUtils.ts b/src/rangeUtils.ts new file mode 100644 index 000000000..b64648219 --- /dev/null +++ b/src/rangeUtils.ts @@ -0,0 +1,42 @@ +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[]); +} + +export {sortRanges, groupRanges}; diff --git a/src/web/utils/parserUtils.ts b/src/web/utils/parserUtils.ts index 36a73f146..a6a855017 100644 --- a/src/web/utils/parserUtils.ts +++ b/src/web/utils/parserUtils.ts @@ -6,7 +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} from '../../parseExpensiMark'; +import {sortRanges} from '../../rangeUtils'; type Paragraph = { text: string;