From 10445d6ba0fe3e1c2286d7e22acc8c5feba9856e Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Tue, 25 Jun 2024 13:28:55 +0800 Subject: [PATCH 1/3] capture newline as the code fence content --- __tests__/ExpensiMark-HTML-test.js | 114 ++++++++++++++--------------- lib/ExpensiMark.js | 2 +- 2 files changed, 58 insertions(+), 58 deletions(-) diff --git a/__tests__/ExpensiMark-HTML-test.js b/__tests__/ExpensiMark-HTML-test.js index 763df5b6..270ddc5b 100644 --- a/__tests__/ExpensiMark-HTML-test.js +++ b/__tests__/ExpensiMark-HTML-test.js @@ -24,7 +24,7 @@ test('Test multi-line bold markdown replacement', () => { test('Test bold within code blocks is skipped', () => { const testString = 'bold\n```\n*not a bold*\n```\nThis is *bold*'; - const replacedString = 'bold
*not a bold*
This is bold'; + const replacedString = 'bold

*not a bold*
This is bold'; expect(parser.replace(testString)).toBe(replacedString); }); @@ -45,7 +45,7 @@ test('Test heading markdown replacement', () => { // Sections starting with > are successfully wrapped with
test('Test quote markdown replacement', () => { const quoteTestStartString = '> This is a *quote* that started on a new line.\nHere is a >quote that did not\n```\nhere is a codefenced quote\n>it should not be quoted\n```'; - const quoteTestReplacedString = '
This is a quote that started on a new line.
Here is a >quote that did not
here is a codefenced quote
>it should not be quoted
'; + const quoteTestReplacedString = '
This is a quote that started on a new line.
Here is a >quote that did not

here is a codefenced quote
>it should not be quoted
'; expect(parser.replace(quoteTestStartString)).toBe(quoteTestReplacedString); }); @@ -219,7 +219,7 @@ test('Test emails within other markdown', () => { + '__test@example.com__ ' + '__test@example.com_'; const result = '
test@example.com
' - + '
test@example.com
' + + '

test@example.com
' + 'test@example.com
' + 'test@example.com ' + 'test@example.com_ ' @@ -421,27 +421,27 @@ test('Test period replacements', () => { test('Test code fencing', () => { const codeFenceExampleMarkdown = '```\nconst javaScript = \'javaScript\'\n```'; - expect(parser.replace(codeFenceExampleMarkdown)).toBe('
const javaScript = 'javaScript'
'); + expect(parser.replace(codeFenceExampleMarkdown)).toBe('

const javaScript = 'javaScript'
'); }); test('Test code fencing with spaces and new lines', () => { let codeFenceExample = '```\nconst javaScript = \'javaScript\'\n const php = \'php\'\n```'; - expect(parser.replace(codeFenceExample)).toBe('
const javaScript = 'javaScript'
const php = 'php'
'); + expect(parser.replace(codeFenceExample)).toBe('

const javaScript = 'javaScript'
const php = 'php'
'); codeFenceExample = '```\n\n# test\n\n```'; - expect(parser.replace(codeFenceExample)).toBe('

# test

'); + expect(parser.replace(codeFenceExample)).toBe('


# test

'); codeFenceExample = '```\n\n\n# test\n\n```'; - expect(parser.replace(codeFenceExample)).toBe('


# test

'); + expect(parser.replace(codeFenceExample)).toBe('



# test

'); codeFenceExample = '```\r\n# test\r\n```'; - expect(parser.replace(codeFenceExample)).toBe('
# test
'); + expect(parser.replace(codeFenceExample)).toBe('

# test
'); codeFenceExample = '```\r\n\r\n# test\r\n\r\n```'; - expect(parser.replace(codeFenceExample)).toBe('

# test

'); + expect(parser.replace(codeFenceExample)).toBe('


# test

'); codeFenceExample = '```\r\n\r\n\r\n# test\r\n\r\n```'; - expect(parser.replace(codeFenceExample)).toBe('


# test

'); + expect(parser.replace(codeFenceExample)).toBe('



# test

'); }); test('Test inline code blocks', () => { @@ -496,45 +496,45 @@ test('Test inline code blocks with two backticks', () => { test('Test code fencing with ExpensiMark syntax inside', () => { const codeFenceExample = '```\nThis is how you can write ~strikethrough~, *bold*, _italics_, and [links](https://www.expensify.com)\n```'; - expect(parser.replace(codeFenceExample)).toBe('
This is how you can write ~strikethrough~, *bold*, _italics_, and [links](https://www.expensify.com)
'); + expect(parser.replace(codeFenceExample)).toBe('

This is how you can write ~strikethrough~, *bold*, _italics_, and [links](https://www.expensify.com)
'); }); test('Test code fencing with ExpensiMark syntax outside', () => { let codeFenceExample = '# Test1 ```\ncode\n``` Test2'; - expect(parser.replace(codeFenceExample)).toBe('

Test1

code
Test2'); + expect(parser.replace(codeFenceExample)).toBe('

Test1


code
Test2'); codeFenceExample = '*Test1 ```\ncode\n``` Test2*'; - expect(parser.replace(codeFenceExample)).toBe('*Test1
code
Test2*'); - expect(parser.replace(codeFenceExample, {shouldKeepRawInput: true})).toBe('*Test1
code\n
Test2*'); + expect(parser.replace(codeFenceExample)).toBe('*Test1

code
Test2*'); + expect(parser.replace(codeFenceExample, {shouldKeepRawInput: true})).toBe('*Test1
\ncode\n
Test2*'); codeFenceExample = '_Test1 ```\ncode\n``` Test2_'; - expect(parser.replace(codeFenceExample)).toBe('_Test1
code
Test2_'); - expect(parser.replace(codeFenceExample, {shouldKeepRawInput: true})).toBe('_Test1
code\n
Test2_'); + expect(parser.replace(codeFenceExample)).toBe('_Test1

code
Test2_'); + expect(parser.replace(codeFenceExample, {shouldKeepRawInput: true})).toBe('_Test1
\ncode\n
Test2_'); codeFenceExample = '~Test1 ```\ncode\n``` Test2~'; - expect(parser.replace(codeFenceExample)).toBe('~Test1
code
Test2~'); - expect(parser.replace(codeFenceExample, {shouldKeepRawInput: true})).toBe('~Test1
code\n
Test2~'); + expect(parser.replace(codeFenceExample)).toBe('~Test1

code
Test2~'); + expect(parser.replace(codeFenceExample, {shouldKeepRawInput: true})).toBe('~Test1
\ncode\n
Test2~'); codeFenceExample = '[```\ncode\n```](google.com)'; - expect(parser.replace(codeFenceExample)).toBe('[
code
](google.com)'); - expect(parser.replace(codeFenceExample, {shouldKeepRawInput: true})).toBe('[
code\n
](google.com)'); + expect(parser.replace(codeFenceExample)).toBe('[

code
](google.com)'); + expect(parser.replace(codeFenceExample, {shouldKeepRawInput: true})).toBe('[
\ncode\n
](google.com)'); }); test('Test code fencing with additional backticks inside', () => { let nestedBackticks = '```\n`test`\n```'; - expect(parser.replace(nestedBackticks)).toBe('
`test`
'); + expect(parser.replace(nestedBackticks)).toBe('

`test`
'); nestedBackticks = '```\n`\ntest\n`\n```'; - expect(parser.replace(nestedBackticks)).toBe('
`
test
`
'); + expect(parser.replace(nestedBackticks)).toBe('

`
test
`
'); nestedBackticks = '```\n``\n```'; - expect(parser.replace(nestedBackticks)).toBe('
``
'); + expect(parser.replace(nestedBackticks)).toBe('

``
'); nestedBackticks = '```\n`\n`\n```'; - expect(parser.replace(nestedBackticks)).toBe('
`
`
'); + expect(parser.replace(nestedBackticks)).toBe('

`
`
'); nestedBackticks = '```\n`This is how you can write ~strikethrough~, *bold*, _italics_, and [links](https://www.expensify.com)`\n```'; - expect(parser.replace(nestedBackticks)).toBe('
`This is how you can write ~strikethrough~, *bold*, _italics_, and [links](https://www.expensify.com)`
'); + expect(parser.replace(nestedBackticks)).toBe('

`This is how you can write ~strikethrough~, *bold*, _italics_, and [links](https://www.expensify.com)`
'); }); test('Test combination replacements', () => { @@ -1013,7 +1013,7 @@ test('Test autolink replacement to avoid parsing nested links', () => { test('Test quotes markdown replacement with text matching inside and outside codefence without spaces', () => { const testString = 'The next line should be quoted\n> Hello,I’mtext\n```\nThe next line should not be quoted\n>Hello,I’mtext\nsince its inside a codefence\n```'; - const resultString = 'The next line should be quoted
Hello,I’mtext
The next line should not be quoted
>Hello,I’mtext
since its inside a codefence
'; + const resultString = 'The next line should be quoted
Hello,I’mtext

The next line should not be quoted
>Hello,I’mtext
since its inside a codefence
'; expect(parser.replace(testString)).toBe(resultString); }); @@ -1021,7 +1021,7 @@ test('Test quotes markdown replacement with text matching inside and outside cod test('Test quotes markdown replacement with text matching inside and outside codefence at the same line', () => { const testString = 'The next line should be quoted\n> Hello,I’mtext\nThe next line should not be quoted\n```\n>Hello,I’mtext\n```\nsince its inside a codefence'; - const resultString = 'The next line should be quoted
Hello,I’mtext
The next line should not be quoted
>Hello,I’mtext
since its inside a codefence'; + const resultString = 'The next line should be quoted
Hello,I’mtext
The next line should not be quoted

>Hello,I’mtext
since its inside a codefence'; expect(parser.replace(testString)).toBe(resultString); }); @@ -1029,7 +1029,7 @@ test('Test quotes markdown replacement with text matching inside and outside cod test('Test quotes markdown replacement with text matching inside and outside codefence at the end of the text', () => { const testString = 'The next line should be quoted\n> Hello,I’mtext\nThe next line should not be quoted\n```\n>Hello,I’mtext\n```'; - const resultString = 'The next line should be quoted
Hello,I’mtext
The next line should not be quoted
>Hello,I’mtext
'; + const resultString = 'The next line should be quoted
Hello,I’mtext
The next line should not be quoted

>Hello,I’mtext
'; expect(parser.replace(testString)).toBe(resultString); }); @@ -1037,7 +1037,7 @@ test('Test quotes markdown replacement with text matching inside and outside cod test('Test quotes markdown replacement with text matching inside and outside codefence with quotes at the end of the text', () => { const testString = 'The next line should be quoted\n```\n> Hello,I’mtext\n```\nThe next line should not be quoted\n> Hello,I’mtext'; - const resultString = 'The next line should be quoted
> Hello,I’mtext
The next line should not be quoted
Hello,I’mtext
'; + const resultString = 'The next line should be quoted

> Hello,I’mtext
The next line should not be quoted
Hello,I’mtext
'; expect(parser.replace(testString)).toBe(resultString); }); @@ -1045,7 +1045,7 @@ test('Test quotes markdown replacement with text matching inside and outside cod test('Test quotes markdown replacement and removing
from
 and 

', () => { const testString = 'The next line should be quoted\n```\n>Hello,I’mtext\n```\nThe next line should not be quoted'; - const resultString = 'The next line should be quoted
>Hello,I’mtext
The next line should not be quoted'; + const resultString = 'The next line should be quoted

>Hello,I’mtext
The next line should not be quoted'; expect(parser.replace(testString)).toBe(resultString); }); @@ -1280,13 +1280,13 @@ test('Test for user mention with invalid username', () => { test('Test for user mention with codefence style', () => { const testString = '```\n@username@expensify.com\n```'; - const resultString = '
@username@expensify.com
'; + const resultString = '

@username@expensify.com
'; expect(parser.replace(testString)).toBe(resultString); }); test('Test for room mention with codefence style', () => { const testString = '```\n#room\n```'; - const resultString = '
#room
'; + const resultString = '

#room
'; expect(parser.replace(testString)).toBe(resultString); }); @@ -1298,7 +1298,7 @@ test('Test for user mention with inlineCodeBlock style', () => { test('Test for user mention with text with codefence style', () => { const testString = '```\nhi @username@expensify.com\n```'; - const resultString = '
hi @username@expensify.com
'; + const resultString = '

hi @username@expensify.com
'; expect(parser.replace(testString)).toBe(resultString); }); @@ -1328,7 +1328,7 @@ test('Test for user mention with user email includes underscores', () => { test('Test for @here mention with codefence style', () => { const testString = '```\n@here\n```'; - const resultString = '
@here
'; + const resultString = '

@here
'; expect(parser.replace(testString)).toBe(resultString); }); @@ -1593,8 +1593,8 @@ test('Test link with code fence inside the alias text part', () => { const testString = '[```\ncode\n```](google.com) ' + '[test ```\ncode\n``` test](google.com)'; - const resultString = '[
code
](google.com) ' - + '[test
code
test](google.com)'; + const resultString = '[

code
](google.com) ' + + '[test

code
test](google.com)'; expect(parser.replace(testString)).toBe(resultString); }); @@ -1625,47 +1625,47 @@ test('Linebreak between end of text and start of code block should be remained', const testCases = [ { testString: '```\ncode1\n```\ntext\n```\ncode2\n```', - resultString: '
code1
text
code2
', + resultString: '

code1
text

code2
', }, { testString: 'text\n```\ncode\n```', - resultString: 'text
code
', + resultString: 'text

code
', }, { testString: '|\n```\ncode\n```', - resultString: '|
code
', + resultString: '|

code
', }, { testString: 'text1```\ncode\n```text2', - resultString: 'text1
code
text2', + resultString: 'text1

code
text2', }, { testString: 'text1 ```\n code \n``` text2', - resultString: 'text1
 code 
text2', + resultString: 'text1

code
text2', }, { testString: 'text1\n```\ncode\n```\ntext2', - resultString: 'text1
code
text2', + resultString: 'text1

code
text2', }, { testString: 'text1\n```\n code \n```\ntext2', - resultString: 'text1
 code 
text2', + resultString: 'text1

code
text2', }, { testString: 'text1\n```\n\ncode\n```\ntext2', - resultString: 'text1

code
text2', + resultString: 'text1


code
text2', }, { testString: 'text1\n```\n\ncode\n\n```\ntext2', - resultString: 'text1

code

text2', + resultString: 'text1


code

text2', }, { testString: 'text1\n```\n\n\ncode\n\n```\ntext2', - resultString: 'text1


code

text2', + resultString: 'text1



code

text2', }, { testString: 'text1\n```\n\ncode\n\n\n```\ntext2', - resultString: 'text1

code


text2', + resultString: 'text1


code


text2', }, ]; testCases.forEach(({testString, resultString}) => { @@ -1687,12 +1687,12 @@ test('Test autoEmail with markdown of
, , ,  and code block
test@gmail.com ' + + '

code block
test@gmail.com ' + 'Googletest@gmail.com ' + 'test@gmail.com ' + 'test

test@gmail.com
' + 'test@expensify.com ' - + '
test@expensify.com
' + + '

test@expensify.com
' + '@test@expensify.com ' + '@username@expensify.com ' + 'https://staging.new.expensify.com/details/test@expensify.com ' @@ -1799,14 +1799,14 @@ describe('when should keep raw input flag is enabled', () => { test('quote with other markdowns', () => { const quoteTestStartString = '> This is a *quote* that started on a new line.\nHere is a >quote that did not\n```\nhere is a codefenced quote\n>it should not be quoted\n```'; - const quoteTestReplacedString = '
This is a quote that started on a new line.
\nHere is a >quote that did not\n
here is a codefenced quote\n>it should not be quoted\n
'; + const quoteTestReplacedString = '
This is a quote that started on a new line.
\nHere is a >quote that did not\n
\nhere is a codefenced quote\n>it should not be quoted\n
'; expect(parser.replace(quoteTestStartString, {shouldKeepRawInput: true})).toBe(quoteTestReplacedString); }); test('codeBlock with newlines', () => { const quoteTestStartString = '```\nhello world\n```'; - const quoteTestReplacedString = '
hello world\n
'; + const quoteTestReplacedString = '
\nhello world\n
'; expect(parser.replace(quoteTestStartString, {shouldKeepRawInput: true})).toBe(quoteTestReplacedString); }); @@ -1860,19 +1860,19 @@ describe('when should keep raw input flag is enabled', () => { test('Test code fence within inline code', () => { let testString = 'Hello world `(```\ntest\n```)` Hello world'; - expect(parser.replace(testString)).toBe('Hello world `(
test
)` Hello world'); + expect(parser.replace(testString)).toBe('Hello world `(

test
)` Hello world'); testString = 'Hello world `(```\ntest\ntest\n```)` Hello world'; - expect(parser.replace(testString)).toBe('Hello world `(
test
test
)` Hello world'); + expect(parser.replace(testString)).toBe('Hello world `(

test
test
)` Hello world'); testString = 'Hello world ```\n(`test`)\n``` Hello world'; - expect(parser.replace(testString)).toBe('Hello world
(`test`)
Hello world'); + expect(parser.replace(testString)).toBe('Hello world

(`test`)
Hello world'); testString = 'Hello world `test`space```\nblock\n``` Hello world'; - expect(parser.replace(testString)).toBe('Hello world testspace
block
Hello world'); + expect(parser.replace(testString)).toBe('Hello world testspace

block
Hello world'); testString = 'Hello world ```\nblock\n```space`test` Hello world'; - expect(parser.replace(testString)).toBe('Hello world
block
spacetest Hello world'); + expect(parser.replace(testString)).toBe('Hello world

block
spacetest Hello world'); }); test('Test italic/bold/strikethrough markdown to keep consistency', () => { @@ -2130,7 +2130,7 @@ describe('room mentions', () => { test('room mention inside code block should not be rendered', () => { const testString = '```\n#room\n```'; - const resultString = '
#room
'; + const resultString = '

#room
'; expect(parser.replace(testString)).toBe(resultString); }); diff --git a/lib/ExpensiMark.js b/lib/ExpensiMark.js index c1f437ff..6cb8a953 100644 --- a/lib/ExpensiMark.js +++ b/lib/ExpensiMark.js @@ -48,7 +48,7 @@ export default class ExpensiMark { name: 'codeFence', // ` is a backtick symbol we are matching on three of them before then after a new line character - regex: /(```(?:\r\n|\n))((?:\s*?(?!(?:\r\n|\n)?```(?!`))[\S])+\s*?(?:\r\n|\n))(```)/g, + regex: /(```)((?:\r\n|\n)(?:\s*?(?!(?:\r\n|\n)?```(?!`))[\S])+\s*?(?:\r\n|\n))(```)/g, // We're using a function here to perform an additional replace on the content // inside the backticks because Android is not able to use
 tags and does

From 3ab10bfe69cf141d5be9a9980e8fc2ddd891d5d8 Mon Sep 17 00:00:00 2001
From: Bernhard Owen Josephus 
Date: Fri, 28 Jun 2024 16:15:03 +0800
Subject: [PATCH 2/3] add the newline as pre content for raw input only

---
 __tests__/ExpensiMark-HTML-test.js | 102 ++++++++++++++---------------
 lib/ExpensiMark.ts                 |   8 +--
 2 files changed, 55 insertions(+), 55 deletions(-)

diff --git a/__tests__/ExpensiMark-HTML-test.js b/__tests__/ExpensiMark-HTML-test.js
index 2a7fc053..7854b552 100644
--- a/__tests__/ExpensiMark-HTML-test.js
+++ b/__tests__/ExpensiMark-HTML-test.js
@@ -22,7 +22,7 @@ test('Test multi-line bold markdown replacement', () => {
 
 test('Test bold within code blocks is skipped', () => {
     const testString = 'bold\n```\n*not a bold*\n```\nThis is *bold*';
-    const replacedString = 'bold

*not a bold*
This is bold'; + const replacedString = 'bold
*not a bold*
This is bold'; expect(parser.replace(testString)).toBe(replacedString); }); @@ -44,7 +44,7 @@ test('Test heading markdown replacement', () => { test('Test quote markdown replacement', () => { const quoteTestStartString = '> This is a *quote* that started on a new line.\nHere is a >quote that did not\n```\nhere is a codefenced quote\n>it should not be quoted\n```'; const quoteTestReplacedString = - '
This is a quote that started on a new line.
Here is a >quote that did not

here is a codefenced quote
>it should not be quoted
'; + '
This is a quote that started on a new line.
Here is a >quote that did not
here is a codefenced quote
>it should not be quoted
'; expect(parser.replace(quoteTestStartString)).toBe(quoteTestReplacedString); }); @@ -197,7 +197,7 @@ test('Test emails within other markdown', () => { '> test@example.com\n' + '```\ntest@example.com\n```\n' + '`test@example.com`\n' + '_test@example.com_ ' + '_test@example.com__ ' + '__test@example.com__ ' + '__test@example.com_'; const result = '
test@example.com
' + - '

test@example.com
' + + '
test@example.com
' + 'test@example.com
' + 'test@example.com ' + 'test@example.com_ ' + @@ -402,27 +402,27 @@ test('Test period replacements', () => { test('Test code fencing', () => { const codeFenceExampleMarkdown = "```\nconst javaScript = 'javaScript'\n```"; - expect(parser.replace(codeFenceExampleMarkdown)).toBe('

const javaScript = 'javaScript'
'); + expect(parser.replace(codeFenceExampleMarkdown)).toBe('
const javaScript = 'javaScript'
'); }); test('Test code fencing with spaces and new lines', () => { let codeFenceExample = "```\nconst javaScript = 'javaScript'\n const php = 'php'\n```"; - expect(parser.replace(codeFenceExample)).toBe('

const javaScript = 'javaScript'
const php = 'php'
'); + expect(parser.replace(codeFenceExample)).toBe('
const javaScript = 'javaScript'
const php = 'php'
'); codeFenceExample = '```\n\n# test\n\n```'; - expect(parser.replace(codeFenceExample)).toBe('


# test

'); + expect(parser.replace(codeFenceExample)).toBe('

# test

'); codeFenceExample = '```\n\n\n# test\n\n```'; - expect(parser.replace(codeFenceExample)).toBe('



# test

'); + expect(parser.replace(codeFenceExample)).toBe('


# test

'); codeFenceExample = '```\r\n# test\r\n```'; - expect(parser.replace(codeFenceExample)).toBe('

# test
'); + expect(parser.replace(codeFenceExample)).toBe('
# test
'); codeFenceExample = '```\r\n\r\n# test\r\n\r\n```'; - expect(parser.replace(codeFenceExample)).toBe('


# test

'); + expect(parser.replace(codeFenceExample)).toBe('

# test

'); codeFenceExample = '```\r\n\r\n\r\n# test\r\n\r\n```'; - expect(parser.replace(codeFenceExample)).toBe('



# test

'); + expect(parser.replace(codeFenceExample)).toBe('


# test

'); }); test('Test inline code blocks', () => { @@ -474,28 +474,28 @@ test('Test inline code blocks with two backticks', () => { test('Test code fencing with ExpensiMark syntax inside', () => { const codeFenceExample = '```\nThis is how you can write ~strikethrough~, *bold*, _italics_, and [links](https://www.expensify.com)\n```'; expect(parser.replace(codeFenceExample)).toBe( - '

This is how you can write ~strikethrough~, *bold*, _italics_, and [links](https://www.expensify.com)
', + '
This is how you can write ~strikethrough~, *bold*, _italics_, and [links](https://www.expensify.com)
', ); }); test('Test code fencing with ExpensiMark syntax outside', () => { let codeFenceExample = '# Test1 ```\ncode\n``` Test2'; - expect(parser.replace(codeFenceExample)).toBe('

Test1


code
Test2'); + expect(parser.replace(codeFenceExample)).toBe('

Test1

code
Test2'); codeFenceExample = '*Test1 ```\ncode\n``` Test2*'; - expect(parser.replace(codeFenceExample)).toBe('*Test1

code
Test2*'); + expect(parser.replace(codeFenceExample)).toBe('*Test1
code
Test2*'); expect(parser.replace(codeFenceExample, {shouldKeepRawInput: true})).toBe('*Test1
\ncode\n
Test2*'); codeFenceExample = '_Test1 ```\ncode\n``` Test2_'; - expect(parser.replace(codeFenceExample)).toBe('_Test1

code
Test2_'); + expect(parser.replace(codeFenceExample)).toBe('_Test1
code
Test2_'); expect(parser.replace(codeFenceExample, {shouldKeepRawInput: true})).toBe('_Test1
\ncode\n
Test2_'); codeFenceExample = '~Test1 ```\ncode\n``` Test2~'; - expect(parser.replace(codeFenceExample)).toBe('~Test1

code
Test2~'); + expect(parser.replace(codeFenceExample)).toBe('~Test1
code
Test2~'); expect(parser.replace(codeFenceExample, {shouldKeepRawInput: true})).toBe('~Test1
\ncode\n
Test2~'); codeFenceExample = '[```\ncode\n```](google.com)'; - expect(parser.replace(codeFenceExample)).toBe('[

code
](google.com)'); + expect(parser.replace(codeFenceExample)).toBe('[
code
](google.com)'); expect(parser.replace(codeFenceExample, {shouldKeepRawInput: true})).toBe( '[
\ncode\n
](google.com)', ); @@ -503,20 +503,20 @@ test('Test code fencing with ExpensiMark syntax outside', () => { test('Test code fencing with additional backticks inside', () => { let nestedBackticks = '```\n`test`\n```'; - expect(parser.replace(nestedBackticks)).toBe('

`test`
'); + expect(parser.replace(nestedBackticks)).toBe('
`test`
'); nestedBackticks = '```\n`\ntest\n`\n```'; - expect(parser.replace(nestedBackticks)).toBe('

`
test
`
'); + expect(parser.replace(nestedBackticks)).toBe('
`
test
`
'); nestedBackticks = '```\n``\n```'; - expect(parser.replace(nestedBackticks)).toBe('

``
'); + expect(parser.replace(nestedBackticks)).toBe('
``
'); nestedBackticks = '```\n`\n`\n```'; - expect(parser.replace(nestedBackticks)).toBe('

`
`
'); + expect(parser.replace(nestedBackticks)).toBe('
`
`
'); nestedBackticks = '```\n`This is how you can write ~strikethrough~, *bold*, _italics_, and [links](https://www.expensify.com)`\n```'; expect(parser.replace(nestedBackticks)).toBe( - '

`This is how you can write ~strikethrough~, *bold*, _italics_, and [links](https://www.expensify.com)`
', + '
`This is how you can write ~strikethrough~, *bold*, _italics_, and [links](https://www.expensify.com)`
', ); }); @@ -1034,7 +1034,7 @@ test('Test quotes markdown replacement with text matching inside and outside cod const testString = 'The next line should be quoted\n> Hello,I’mtext\n```\nThe next line should not be quoted\n>Hello,I’mtext\nsince its inside a codefence\n```'; const resultString = - 'The next line should be quoted
Hello,I’mtext

The next line should not be quoted
>Hello,I’mtext
since its inside a codefence
'; + 'The next line should be quoted
Hello,I’mtext
The next line should not be quoted
>Hello,I’mtext
since its inside a codefence
'; expect(parser.replace(testString)).toBe(resultString); }); @@ -1043,7 +1043,7 @@ test('Test quotes markdown replacement with text matching inside and outside cod const testString = 'The next line should be quoted\n> Hello,I’mtext\nThe next line should not be quoted\n```\n>Hello,I’mtext\n```\nsince its inside a codefence'; const resultString = - 'The next line should be quoted
Hello,I’mtext
The next line should not be quoted

>Hello,I’mtext
since its inside a codefence'; + 'The next line should be quoted
Hello,I’mtext
The next line should not be quoted
>Hello,I’mtext
since its inside a codefence'; expect(parser.replace(testString)).toBe(resultString); }); @@ -1051,7 +1051,7 @@ test('Test quotes markdown replacement with text matching inside and outside cod test('Test quotes markdown replacement with text matching inside and outside codefence at the end of the text', () => { const testString = 'The next line should be quoted\n> Hello,I’mtext\nThe next line should not be quoted\n```\n>Hello,I’mtext\n```'; - const resultString = 'The next line should be quoted
Hello,I’mtext
The next line should not be quoted

>Hello,I’mtext
'; + const resultString = 'The next line should be quoted
Hello,I’mtext
The next line should not be quoted
>Hello,I’mtext
'; expect(parser.replace(testString)).toBe(resultString); }); @@ -1059,7 +1059,7 @@ test('Test quotes markdown replacement with text matching inside and outside cod test('Test quotes markdown replacement with text matching inside and outside codefence with quotes at the end of the text', () => { const testString = 'The next line should be quoted\n```\n> Hello,I’mtext\n```\nThe next line should not be quoted\n> Hello,I’mtext'; - const resultString = 'The next line should be quoted

> Hello,I’mtext
The next line should not be quoted
Hello,I’mtext
'; + const resultString = 'The next line should be quoted
> Hello,I’mtext
The next line should not be quoted
Hello,I’mtext
'; expect(parser.replace(testString)).toBe(resultString); }); @@ -1067,7 +1067,7 @@ test('Test quotes markdown replacement with text matching inside and outside cod test('Test quotes markdown replacement and removing
from
 and 

', () => { const testString = 'The next line should be quoted\n```\n>Hello,I’mtext\n```\nThe next line should not be quoted'; - const resultString = 'The next line should be quoted

>Hello,I’mtext
The next line should not be quoted'; + const resultString = 'The next line should be quoted
>Hello,I’mtext
The next line should not be quoted'; expect(parser.replace(testString)).toBe(resultString); }); @@ -1319,13 +1319,13 @@ test('Test for user mention with invalid username', () => { test('Test for user mention with codefence style', () => { const testString = '```\n@username@expensify.com\n```'; - const resultString = '

@username@expensify.com
'; + const resultString = '
@username@expensify.com
'; expect(parser.replace(testString)).toBe(resultString); }); test('Test for room mention with codefence style', () => { const testString = '```\n#room\n```'; - const resultString = '

#room
'; + const resultString = '
#room
'; expect(parser.replace(testString)).toBe(resultString); }); @@ -1337,7 +1337,7 @@ test('Test for user mention with inlineCodeBlock style', () => { test('Test for user mention with text with codefence style', () => { const testString = '```\nhi @username@expensify.com\n```'; - const resultString = '

hi @username@expensify.com
'; + const resultString = '
hi @username@expensify.com
'; expect(parser.replace(testString)).toBe(resultString); }); @@ -1367,7 +1367,7 @@ test('Test for user mention with user email includes underscores', () => { test('Test for @here mention with codefence style', () => { const testString = '```\n@here\n```'; - const resultString = '

@here
'; + const resultString = '
@here
'; expect(parser.replace(testString)).toBe(resultString); }); @@ -1637,8 +1637,8 @@ test('Test link with code fence inside the alias text part', () => { const testString = '[```\ncode\n```](google.com) ' + '[test ```\ncode\n``` test](google.com)'; const resultString = - '[

code
](google.com) ' + - '[test

code
test](google.com)'; + '[
code
](google.com) ' + + '[test
code
test](google.com)'; expect(parser.replace(testString)).toBe(resultString); }); @@ -1669,47 +1669,47 @@ test('Linebreak between end of text and start of code block should be remained', const testCases = [ { testString: '```\ncode1\n```\ntext\n```\ncode2\n```', - resultString: '

code1
text

code2
', + resultString: '
code1
text
code2
', }, { testString: 'text\n```\ncode\n```', - resultString: 'text

code
', + resultString: 'text
code
', }, { testString: '|\n```\ncode\n```', - resultString: '|

code
', + resultString: '|
code
', }, { testString: 'text1```\ncode\n```text2', - resultString: 'text1

code
text2', + resultString: 'text1
code
text2', }, { testString: 'text1 ```\n code \n``` text2', - resultString: 'text1

code
text2', + resultString: 'text1
 code 
text2', }, { testString: 'text1\n```\ncode\n```\ntext2', - resultString: 'text1

code
text2', + resultString: 'text1
code
text2', }, { testString: 'text1\n```\n code \n```\ntext2', - resultString: 'text1

code
text2', + resultString: 'text1
 code 
text2', }, { testString: 'text1\n```\n\ncode\n```\ntext2', - resultString: 'text1


code
text2', + resultString: 'text1

code
text2', }, { testString: 'text1\n```\n\ncode\n\n```\ntext2', - resultString: 'text1


code

text2', + resultString: 'text1

code

text2', }, { testString: 'text1\n```\n\n\ncode\n\n```\ntext2', - resultString: 'text1



code

text2', + resultString: 'text1


code

text2', }, { testString: 'text1\n```\n\ncode\n\n\n```\ntext2', - resultString: 'text1


code


text2', + resultString: 'text1

code


text2', }, ]; testCases.forEach(({testString, resultString}) => { @@ -1733,12 +1733,12 @@ test('Test autoEmail with markdown of
, , ,  and 
code block
test@gmail.com ' + + '
code block
test@gmail.com ' + 'Googletest@gmail.com ' + 'test@gmail.com ' + 'test

test@gmail.com
' + 'test@expensify.com ' + - '

test@expensify.com
' + + '
test@expensify.com
' + '@test@expensify.com ' + '@username@expensify.com ' + 'https://staging.new.expensify.com/details/test@expensify.com ' + @@ -1907,19 +1907,19 @@ describe('when should keep raw input flag is enabled', () => { test('Test code fence within inline code', () => { let testString = 'Hello world `(```\ntest\n```)` Hello world'; - expect(parser.replace(testString)).toBe('Hello world `(

test
)` Hello world'); + expect(parser.replace(testString)).toBe('Hello world `(
test
)` Hello world'); testString = 'Hello world `(```\ntest\ntest\n```)` Hello world'; - expect(parser.replace(testString)).toBe('Hello world `(

test
test
)` Hello world'); + expect(parser.replace(testString)).toBe('Hello world `(
test
test
)` Hello world'); testString = 'Hello world ```\n(`test`)\n``` Hello world'; - expect(parser.replace(testString)).toBe('Hello world

(`test`)
Hello world'); + expect(parser.replace(testString)).toBe('Hello world
(`test`)
Hello world'); testString = 'Hello world `test`space```\nblock\n``` Hello world'; - expect(parser.replace(testString)).toBe('Hello world testspace

block
Hello world'); + expect(parser.replace(testString)).toBe('Hello world testspace
block
Hello world'); testString = 'Hello world ```\nblock\n```space`test` Hello world'; - expect(parser.replace(testString)).toBe('Hello world

block
spacetest Hello world'); + expect(parser.replace(testString)).toBe('Hello world
block
spacetest Hello world'); }); test('Test italic/bold/strikethrough markdown to keep consistency', () => { @@ -2220,7 +2220,7 @@ describe('room mentions', () => { test('room mention inside code block should not be rendered', () => { const testString = '```\n#room\n```'; - const resultString = '

#room
'; + const resultString = '
#room
'; expect(parser.replace(testString)).toBe(resultString); }); diff --git a/lib/ExpensiMark.ts b/lib/ExpensiMark.ts index 37f8ab29..3504438e 100644 --- a/lib/ExpensiMark.ts +++ b/lib/ExpensiMark.ts @@ -129,7 +129,7 @@ export default class ExpensiMark { name: 'codeFence', // ` is a backtick symbol we are matching on three of them before then after a new line character - regex: /(```)((?:\r\n|\n)(?:\s*?(?!(?:\r\n|\n)?```(?!`))[\S])+\s*?(?:\r\n|\n))(```)/g, + regex: /(```(\r\n|\n))((?:\s*?(?!(?:\r\n|\n)?```(?!`))[\S])+\s*?(?:\r\n|\n))(```)/g, // We're using a function here to perform an additional replace on the content // inside the backticks because Android is not able to use
 tags and does
@@ -137,13 +137,13 @@ export default class ExpensiMark {
                 // with the new lines here since they need to be converted into 
. And we don't // want to do this anywhere else since that would break HTML. //   will create styling issues so use - replacement: (_extras, _match, _g1, textWithinFences) => { + replacement: (_extras, _match, _g1, _g2, textWithinFences) => { const group = textWithinFences.replace(/(?:(?![\n\r])\s)/g, ' '); return `
${group}
`; }, - rawInputReplacement: (_extras, _match, _g1, textWithinFences) => { + rawInputReplacement: (_extras, _match, _g1, g2, textWithinFences) => { const group = textWithinFences.replace(/(?:(?![\n\r])\s)/g, ' ').replace(/|<\/emoji>/g, ''); - return `
${group}
`; + return `
${g2}${group}
`; }, }, From 4cbb0cefa77061b759c0bddab3c25a97f626e2fc Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Sat, 29 Jun 2024 10:45:24 +0800 Subject: [PATCH 3/3] update group name --- lib/ExpensiMark.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ExpensiMark.ts b/lib/ExpensiMark.ts index 3504438e..311974cb 100644 --- a/lib/ExpensiMark.ts +++ b/lib/ExpensiMark.ts @@ -141,9 +141,9 @@ export default class ExpensiMark { const group = textWithinFences.replace(/(?:(?![\n\r])\s)/g, ' '); return `
${group}
`; }, - rawInputReplacement: (_extras, _match, _g1, g2, textWithinFences) => { + rawInputReplacement: (_extras, _match, _g1, newLineCharacter, textWithinFences) => { const group = textWithinFences.replace(/(?:(?![\n\r])\s)/g, ' ').replace(/|<\/emoji>/g, ''); - return `
${g2}${group}
`; + return `
${newLineCharacter}${group}
`; }, },