mirror of
https://github.com/hcengineering/platform.git
synced 2025-06-12 13:42:38 +00:00
fix: handle links with spaces in markdown (#9164)
Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com>
This commit is contained in:
parent
14310dfa6f
commit
4c24bd5db9
@ -13,6 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
import { MarkupNode } from '@hcengineering/text-core'
|
||||||
import { markdownToMarkup, markupToMarkdown } from '..'
|
import { markdownToMarkup, markupToMarkdown } from '..'
|
||||||
import { isMarkdownsEquals } from '../compare'
|
import { isMarkdownsEquals } from '../compare'
|
||||||
|
|
||||||
@ -855,8 +856,65 @@ Lorem ipsum dolor sit amet.
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('markupToMarkdown', () => {
|
||||||
|
const tests: Array<{ name: string, markdown: string, markup: object }> = [
|
||||||
|
{
|
||||||
|
name: 'links',
|
||||||
|
markdown: `[Link](https://example.com)
|
||||||
|
|
||||||
|
[Link with spaces](<https://example.com/with spaces>)
|
||||||
|
|
||||||
|
[Link with spaces and braces](<https://example.com/\\<with spaces\\>>)`,
|
||||||
|
markup: {
|
||||||
|
type: 'doc',
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: 'paragraph',
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
text: 'Link',
|
||||||
|
marks: [{ type: 'link', attrs: { href: 'https://example.com' } }]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'paragraph',
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
text: 'Link with spaces',
|
||||||
|
marks: [{ type: 'link', attrs: { href: 'https://example.com/with spaces' } }]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'paragraph',
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
text: 'Link with spaces and braces',
|
||||||
|
marks: [{ type: 'link', attrs: { href: 'https://example.com/<with spaces>' } }]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
describe('to markdown', () => {
|
||||||
|
tests.forEach(({ name, markdown, markup }) => {
|
||||||
|
it(name, () => {
|
||||||
|
const result = markupToMarkdown(markup as MarkupNode, options)
|
||||||
|
expect(result).toEqual(markdown)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('markdownToMarkup -> markupToMarkdown', () => {
|
describe('markdownToMarkup -> markupToMarkdown', () => {
|
||||||
const tests: Array<{ name: string, markdown: string }> = [
|
const tests: Array<{ name: string, markdown: string, alternate?: string }> = [
|
||||||
{ name: 'Italic', markdown: '*Asteriscs* and _Underscores_' },
|
{ name: 'Italic', markdown: '*Asteriscs* and _Underscores_' },
|
||||||
{ name: 'Bold', markdown: '**Asteriscs** and __Underscores__' },
|
{ name: 'Bold', markdown: '**Asteriscs** and __Underscores__' },
|
||||||
{ name: 'Bullet list with asteriscs', markdown: 'Asterisks :\r\n* Firstly\r\n* Secondly' },
|
{ name: 'Bullet list with asteriscs', markdown: 'Asterisks :\r\n* Firstly\r\n* Secondly' },
|
||||||
@ -878,6 +936,16 @@ describe('markdownToMarkup -> markupToMarkdown', () => {
|
|||||||
name: 'Link',
|
name: 'Link',
|
||||||
markdown: 'See [link](https://example.com)'
|
markdown: 'See [link](https://example.com)'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'Link with spaces',
|
||||||
|
markdown: 'See [link](<https://example.com/with spaces>)',
|
||||||
|
alternate: 'See [link](https://example.com/with%20spaces)'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Link with spaces and braces',
|
||||||
|
markdown: 'See [link](<https://example.com/\\<with spaces\\>>)',
|
||||||
|
alternate: 'See [link](https://example.com/%3Cwith%20spaces%3E)'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'Codeblock',
|
name: 'Codeblock',
|
||||||
markdown: '```typescript\nconst x: number = 42;\n```'
|
markdown: '```typescript\nconst x: number = 42;\n```'
|
||||||
@ -901,11 +969,11 @@ describe('markdownToMarkup -> markupToMarkdown', () => {
|
|||||||
// }
|
// }
|
||||||
]
|
]
|
||||||
|
|
||||||
tests.forEach(({ name, markdown }) => {
|
tests.forEach(({ name, markdown, alternate }) => {
|
||||||
it(name, () => {
|
it(name, () => {
|
||||||
const json = markdownToMarkup(markdown, options)
|
const json = markdownToMarkup(markdown, options)
|
||||||
const serialized = markupToMarkdown(json, options)
|
const serialized = markupToMarkdown(json, options)
|
||||||
expect(serialized).toEqualMarkdown(markdown)
|
expect(serialized).toEqualMarkdown(alternate ?? markdown)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -351,11 +351,16 @@ export const storeMarks: Record<string, MarkProcessor> = {
|
|||||||
} else {
|
} else {
|
||||||
const { inAutolink } = state
|
const { inAutolink } = state
|
||||||
state.inAutolink = undefined
|
state.inAutolink = undefined
|
||||||
|
|
||||||
|
const href = (mark.attrs?.href as string) ?? ''
|
||||||
|
// eslint-disable-next-line
|
||||||
|
const url = href.replace(/[\(\)"\\<>]/g, '\\$&')
|
||||||
|
const hasSpaces = url.includes(' ')
|
||||||
|
|
||||||
return inAutolink === true
|
return inAutolink === true
|
||||||
? '>'
|
? '>'
|
||||||
: '](' +
|
: '](' +
|
||||||
// eslint-disable-next-line
|
(hasSpaces ? `<${url}>` : url) +
|
||||||
(mark.attrs?.href as string).replace(/[\(\)"]/g, '\\$&') +
|
|
||||||
(mark.attrs?.title !== undefined ? ` "${(mark.attrs?.title as string).replace(/"/g, '\\"')}"` : '') +
|
(mark.attrs?.title !== undefined ? ` "${(mark.attrs?.title as string).replace(/"/g, '\\"')}"` : '') +
|
||||||
')'
|
')'
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user