diff --git a/src/config.ts b/src/config.ts index eb2b17a..86a36ff 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,4 +1,4 @@ -import { isWhiteSpaceOnly, splitSpecial, surround, tagSurround, trimNewLines } from './utilities'; +import { encodeUrlParens, isWhiteSpaceOnly, splitSpecial, surround, tagSurround, trimNewLines } from './utilities'; import { PostProcessResult, TranslatorConfigObject } from './translator'; import { NodeHtmlMarkdownOptions } from './options'; @@ -295,7 +295,7 @@ export const defaultTranslators: TranslatorConfigObject = { const title = node.getAttribute('title') || ''; return { - content: `![${alt}](${src}${title && ` "${title}"`})`, + content: `![${alt}](${encodeUrlParens(src)}${title && ` "${title}"`})`, recurse: false } }, diff --git a/src/utilities.ts b/src/utilities.ts index 4442b5d..59945fd 100644 --- a/src/utilities.ts +++ b/src/utilities.ts @@ -11,6 +11,13 @@ export const trimNewLines = (s: string) => s.replace(/^\n+|\n+$/g, ''); export const surround = (source: string, surroundStr: string) => `${surroundStr}${source}${surroundStr}`; export const isWhiteSpaceOnly = (s: string) => !/\S/.test(s); +/** + * Percent-encode parentheses in a markdown link/image destination. An unescaped `)` ends the + * destination early, so an `` would otherwise produce `![](foo)bar.png)`, + * which a parser reads as an image of `foo` followed by literal `bar.png)` text. + */ +export const encodeUrlParens = (url: string) => url.replace(/\(/g, '%28').replace(/\)/g, '%29'); + /** * Split string, preserving specific newline used for each line */ diff --git a/test/default-tags.test.ts b/test/default-tags.test.ts index a202691..cfb7b1e 100644 --- a/test/default-tags.test.ts +++ b/test/default-tags.test.ts @@ -59,14 +59,18 @@ describe(`Default Tags`, () => { test(`Image (img)`, () => { const url = `http://www.github.com/crosstype/` + // Parentheses in the src would otherwise break the markdown destination + const specialUrl = 'http://www.github.com/crosstype/img(123).png'; + const encodedSpecialUrl = 'http://www.github.com/crosstype/img%28123%29.png'; const res = translate(` a2 a4 + a5 `); - expect(res).toBe(`![](${url}1)` + ` ![](${url}3 "t3")` + ` ![a4](${url}4 "t4")`); + expect(res).toBe(`![](${url}1)` + ` ![](${url}3 "t3")` + ` ![a4](${url}4 "t4")` + ` ![a5](${encodedSpecialUrl})`); }); test(`Pre-formatted Text (pre)`, () => {