Skip to content

Commit

Permalink
fix(NcRichText) - escape XML-like content before markdown parsing
Browse files Browse the repository at this point in the history
Signed-off-by: Maksim Sukharev <antreesy.web@gmail.com>
  • Loading branch information
Antreesy committed Sep 6, 2023
1 parent fa6fcf5 commit 8551e90
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 18 deletions.
43 changes: 39 additions & 4 deletions cypress/component/richtext.cy.ts
Expand Up @@ -6,6 +6,19 @@ import NcRichText from '../../src/components/NcRichText/NcRichText.vue'

describe('NcRichText', () => {
describe('renders with markdown', () => {
describe('normal text', () => {
it('XML-like text (escaped and unescaped)', () => {
mount(NcRichText, {
propsData: {
text: '<span>text&lt;/span&gt;',
useMarkdown: true,
},
})

cy.get('p').should('have.text', '<span>text</span>')
})
})

describe('headings', () => {
it('heading (with hash (#) syntax divided with space from text)', () => {
const testCases = [
Expand Down Expand Up @@ -274,6 +287,17 @@ describe('NcRichText', () => {

cy.get('code').should('have.text', 'inline code')
})

it('inline code (with ignored bold, italic, XML-like syntax))', () => {
mount(NcRichText, {
propsData: {
text: '`inline code **bold text** _italic text_ <span>text&lt;/span&gt;`',
useMarkdown: true,
},
})

cy.get('code').should('have.text', 'inline code **bold text** _italic text_ <span>text</span>')
})
})

describe('multiline code', () => {
Expand Down Expand Up @@ -333,20 +357,20 @@ describe('NcRichText', () => {
cy.get('code').should('have.text', 'line 1\nline 2\nline 3\n')
})

it('multiline code (with ignored bold, italic, inline code syntax)', () => {
it('multiline code (with ignored bold, italic, inline code, XML-like syntax)', () => {
mount(NcRichText, {
propsData: {
text: '```\n**bold text**\n_italic text_\n`inline code`\n```',
text: '```\n**bold text**\n_italic text_\n`inline code`\n<span>text&lt;/span&gt;\n```',
useMarkdown: true,
},
})

cy.get('pre').should('have.text', '**bold text**\n_italic text_\n`inline code`\n')
cy.get('pre').should('have.text', '**bold text**\n_italic text_\n`inline code`\n<span>text</span>\n')
})
})

describe('blockquote', () => {
it('blockquote (with greater then (gt >) syntax)', () => {
it('blockquote (with greater then (>) syntax - normal)', () => {
mount(NcRichText, {
propsData: {
text: '> blockquote',
Expand All @@ -357,6 +381,17 @@ describe('NcRichText', () => {
cy.get('blockquote').should('have.text', '\nblockquote\n')
})

it('blockquote (with greater then (&gt;) syntax - escaped)', () => {
mount(NcRichText, {
propsData: {
text: '&gt; blockquote',
useMarkdown: true,
},
})

cy.get('blockquote').should('have.text', '\nblockquote\n')
})

it('blockquote (with bold, italic text, inline code)', () => {
mount(NcRichText, {
propsData: {
Expand Down
32 changes: 18 additions & 14 deletions src/components/NcRichText/NcRichText.vue
Expand Up @@ -192,6 +192,12 @@ export default {
})
.use(rehype2react, {
createElement: (tag, attrs, children) => {
// unescape special symbol "<" for simple text nodes
children = children?.map(child => typeof child === 'string'
? child.replace(/&lt;/gmi, '<')
: child,
)
if (!tag.startsWith('#')) {
return h(tag, attrs, children)
}
Expand All @@ -217,15 +223,15 @@ export default {
},
prefix: false,
})
.processSync(this.useMarkdown
// In order to correctly show newlines in Markdown,
// each newline contains a non-breaking space
? this.text.slice()
.replace(/\n>\n/g, '\n>\u00A0\n')
.replace(/\n{2,}/g, (match) => {
return '\n' + '\n\u00A0\n'.repeat(match.length - 1)
})
: this.text)
.processSync(this.text.slice()
// escape special symbol "<" to not treat text as HTML
.replace(/</gmi, '&lt;')
// unescape special symbol ">" to parse blockquotes
.replace(/&gt;/gmi, '>')
// add a non-breaking space to each newline to show them
.replace(/\n>\n/g, '\n>\u00A0\n')
.replace(/\n{2,}/g, (match) => '\n' + '\n\u00A0\n'.repeat(match.length - 1)),
)
.result
return h('div', { class: 'rich-text--wrapper' }, [
Expand All @@ -239,11 +245,9 @@ export default {
},
},
render(h) {
if (!this.useMarkdown) {
return this.renderPlaintext(h)
}
return this.renderMarkdown(h)
return this.useMarkdown
? this.renderMarkdown(h)
: this.renderPlaintext(h)
},
}
</script>
Expand Down

0 comments on commit 8551e90

Please sign in to comment.