Skip to content

Commit 30aa18c

Browse files
committed
fix(url parsing): fix url edge case parsing in images and links
Allow some edge cases to parse correctly. Example: `![img](.images/cat(1).png)`, `![img](<.image(1)/cat(1).png>)`, `[link](<>)`
1 parent 230f443 commit 30aa18c

18 files changed

+147
-46
lines changed

dist/showdown.js

Lines changed: 28 additions & 21 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/showdown.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/showdown.min.js

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/showdown.min.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/subParsers/anchors.js

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,16 @@ showdown.subParser('anchors', function (text, options, globals) {
66

77
text = globals.converter._dispatch('anchors.before', text, options, globals);
88

9-
var writeAnchorTag = function (wholeMatch, m1, m2, m3, m4, m5, m6, m7) {
10-
if (showdown.helper.isUndefined(m7)) {
11-
m7 = '';
9+
var writeAnchorTag = function (wholeMatch, linkText, linkId, url, m5, m6, title) {
10+
if (showdown.helper.isUndefined(title)) {
11+
title = '';
1212
}
13-
wholeMatch = m1;
14-
var linkText = m2,
15-
linkId = m3.toLowerCase(),
16-
url = m4,
17-
title = m7;
13+
linkId = linkId.toLowerCase();
1814

19-
if (!url) {
15+
// Special case for explicit empty url
16+
if (wholeMatch.search(/\(<?\s*>? ?(['"].*['"])?\)$/m) > -1) {
17+
url = '';
18+
} else if (!url) {
2019
if (!linkId) {
2120
// lower-case and turn embedded newlines into spaces
2221
linkId = linkText.toLowerCase().replace(/ ?\n/g, ' ');
@@ -29,12 +28,7 @@ showdown.subParser('anchors', function (text, options, globals) {
2928
title = globals.gTitles[linkId];
3029
}
3130
} else {
32-
if (wholeMatch.search(/\(\s*\)$/m) > -1) {
33-
// Special case for explicit empty url
34-
url = '';
35-
} else {
36-
return wholeMatch;
37-
}
31+
return wholeMatch;
3832
}
3933
}
4034

@@ -61,16 +55,21 @@ showdown.subParser('anchors', function (text, options, globals) {
6155
};
6256

6357
// First, handle reference-style links: [link text] [id]
64-
text = text.replace(/(\[((?:\[[^\]]*]|[^\[\]])*)][ ]?(?:\n[ ]*)?\[(.*?)])()()()()/g, writeAnchorTag);
58+
text = text.replace(/\[((?:\[[^\]]*]|[^\[\]])*)] ?(?:\n *)?\[(.*?)]()()()()/g, writeAnchorTag);
6559

6660
// Next, inline-style links: [link text](url "optional title")
67-
text = text.replace(/(\[((?:\[[^\]]*]|[^\[\]])*)]\([ \t]*()<?(.*?(?:\(.*?\).*?)?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,
61+
// cases with crazy urls like ./image/cat1).png
62+
text = text.replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]?<([^>]*)>(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g,
63+
writeAnchorTag);
64+
65+
// normal cases
66+
text = text.replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]?<?([\S]+?(?:\([\S]*?\)[\S]*?)?)>?(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g,
6867
writeAnchorTag);
6968

7069
// handle reference-style shortcuts: [link text]
7170
// These must come last in case you've also got [link test][1]
7271
// or [link test](/foo)
73-
text = text.replace(/(\[([^\[\]]+)])()()()()()/g, writeAnchorTag);
72+
text = text.replace(/\[([^\[\]]+)]()()()()()/g, writeAnchorTag);
7473

7574
// Lastly handle GithubMentions if option is enabled
7675
if (options.ghMentions) {

src/subParsers/images.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ showdown.subParser('images', function (text, options, globals) {
66

77
text = globals.converter._dispatch('images.before', text, options, globals);
88

9-
var inlineRegExp = /!\[(.*?)]\s?\([ \t]*()<?(\S+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(['"])(.*?)\6[ \t]*)?\)/g,
9+
var inlineRegExp = /!\[([^\]]*?)][ \t]*()\([ \t]?<?([\S]+?(?:\([\S]*?\)[\S]*?)?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\6)?[ \t]?\)/g,
10+
crazyRegExp = /!\[([^\]]*?)][ \t]*()\([ \t]?<([^>]*)>(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(?:(["'])([^"]*?)\6))?[ \t]?\)/g,
1011
referenceRegExp = /!\[([^\]]*?)] ?(?:\n *)?\[(.*?)]()()()()()/g,
1112
refShortcutRegExp = /!\[([^\[\]]+)]()()()()()/g;
1213

@@ -21,8 +22,11 @@ showdown.subParser('images', function (text, options, globals) {
2122
if (!title) {
2223
title = '';
2324
}
25+
// Special case for explicit empty url
26+
if (wholeMatch.search(/\(<?\s*>? ?(['"].*['"])?\)$/m) > -1) {
27+
url = '';
2428

25-
if (url === '' || url === null) {
29+
} else if (url === '' || url === null) {
2630
if (linkId === '' || linkId === null) {
2731
// lower-case and turn embedded newlines into spaces
2832
linkId = altText.toLowerCase().replace(/ ?\n/g, ' ');
@@ -76,6 +80,10 @@ showdown.subParser('images', function (text, options, globals) {
7680
text = text.replace(referenceRegExp, writeImageTag);
7781

7882
// Next, handle inline images: ![alt text](url =<width>x<height> "optional title")
83+
// cases with crazy urls like ./image/cat1).png
84+
text = text.replace(crazyRegExp, writeImageTag);
85+
86+
// normal cases
7987
text = text.replace(inlineRegExp, writeImageTag);
8088

8189
// handle reference-style shortcuts: |[img text]
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<p>This is a <a href="https://en.wikipedia.org/wiki/Textile">link</a> (some other text)</p>
2+
<p>This is a <a href="https://en.wikipedia.org/wiki/Textile_(markup">link</a> (some other text)</p>
3+
<p>This is a <a href="https://en.wikipedia.org/wiki/Textile_(markup_language)">link</a> (some other text)</p>
4+
<p>This is a <a href="https://en.wikipedia.org/wiki/Textile_(markup_language)/foo">link</a> (some other text)</p>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
This is a [link](https://en.wikipedia.org/wiki/Textile) (some other text)
2+
3+
This is a [link](https://en.wikipedia.org/wiki/Textile_(markup) (some other text)
4+
5+
This is a [link](https://en.wikipedia.org/wiki/Textile_(markup_language)) (some other text)
6+
7+
This is a [link](https://en.wikipedia.org/wiki/Textile_(markup_language)/foo) (some other text)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<p><img src="./image/cat1.png" alt="image link" />(some text between brackets)</p>
2+
<p><img src="./image/cat(1).png" alt="image link" />(some text between brackets)</p>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
![image link](<./image/cat1.png>)(some text between brackets)
2+
3+
![image link](<./image/cat(1).png>)(some text between brackets)

0 commit comments

Comments
 (0)