Skip to content

Commit

Permalink
fix: fix link with angle brackets around href (#1851)
Browse files Browse the repository at this point in the history
  • Loading branch information
UziTech committed Dec 10, 2020
1 parent 654d83d commit 656c3e4
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 32 deletions.
49 changes: 35 additions & 14 deletions src/Tokenizer.js
Expand Up @@ -457,34 +457,56 @@ module.exports = class Tokenizer {
link(src) {
const cap = this.rules.inline.link.exec(src);
if (cap) {
const lastParenIndex = findClosingBracket(cap[2], '()');
if (lastParenIndex > -1) {
const start = cap[0].indexOf('!') === 0 ? 5 : 4;
const linkLen = start + cap[1].length + lastParenIndex;
cap[2] = cap[2].substring(0, lastParenIndex);
cap[0] = cap[0].substring(0, linkLen).trim();
cap[3] = '';
const trimmedUrl = cap[2].trim();
if (!this.options.pedantic && trimmedUrl.startsWith('<')) {
// commonmark requires matching angle brackets
if (!trimmedUrl.endsWith('>')) {
return;
}

// ending angle bracket cannot be escaped
const rtrimSlash = rtrim(trimmedUrl.slice(0, -1), '\\');
if ((trimmedUrl.length - rtrimSlash.length) % 2 === 0) {
return;
}
} else {
// find closing parenthesis
const lastParenIndex = findClosingBracket(cap[2], '()');
if (lastParenIndex > -1) {
const start = cap[0].indexOf('!') === 0 ? 5 : 4;
const linkLen = start + cap[1].length + lastParenIndex;
cap[2] = cap[2].substring(0, lastParenIndex);
cap[0] = cap[0].substring(0, linkLen).trim();
cap[3] = '';
}
}
let href = cap[2];
let title = '';
if (this.options.pedantic) {
// split pedantic href and title
const link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href);

if (link) {
href = link[1];
title = link[3];
} else {
title = '';
}
} else {
title = cap[3] ? cap[3].slice(1, -1) : '';
}
href = href.trim().replace(/^<([\s\S]*)>$/, '$1');
const token = outputLink(cap, {

href = href.trim();
if (href.startsWith('<')) {
if (this.options.pedantic && !trimmedUrl.endsWith('>')) {
// pedantic allows starting angle bracket without ending angle bracket
href = href.slice(1);
} else {
href = href.slice(1, -1);
}
}
return outputLink(cap, {
href: href ? href.replace(this.rules.inline._escapes, '$1') : href,
title: title ? title.replace(this.rules.inline._escapes, '$1') : title
}, cap[0]);
return token;
}
}

Expand All @@ -502,8 +524,7 @@ module.exports = class Tokenizer {
text
};
}
const token = outputLink(cap, link, cap[0]);
return token;
return outputLink(cap, link, cap[0]);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/rules.js
Expand Up @@ -260,7 +260,7 @@ inline.tag = edit(inline.tag)
.getRegex();

inline._label = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/;
inline._href = /<(?:\\[<>]?|[^\s<>\\])*>|[^\s\x00-\x1f]*/;
inline._href = /<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/;
inline._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/;

inline.link = edit(inline.link)
Expand Down
12 changes: 4 additions & 8 deletions test/specs/commonmark/commonmark.0.29.json
Expand Up @@ -3939,8 +3939,7 @@
"example": 486,
"start_line": 7543,
"end_line": 7547,
"section": "Links",
"shouldFail": true
"section": "Links"
},
{
"markdown": "[link](foo\nbar)\n",
Expand All @@ -3964,26 +3963,23 @@
"example": 489,
"start_line": 7571,
"end_line": 7575,
"section": "Links",
"shouldFail": true
"section": "Links"
},
{
"markdown": "[link](<foo\\>)\n",
"html": "<p>[link](&lt;foo&gt;)</p>\n",
"example": 490,
"start_line": 7579,
"end_line": 7583,
"section": "Links",
"shouldFail": true
"section": "Links"
},
{
"markdown": "[a](<b)c\n[a](<b)c>\n[a](<b>c)\n",
"html": "<p>[a](&lt;b)c\n[a](&lt;b)c&gt;\n[a](<b>c)</p>\n",
"example": 491,
"start_line": 7588,
"end_line": 7596,
"section": "Links",
"shouldFail": true
"section": "Links"
},
{
"markdown": "[link](\\(foo\\))\n",
Expand Down
12 changes: 4 additions & 8 deletions test/specs/gfm/commonmark.0.29.json
Expand Up @@ -3939,8 +3939,7 @@
"example": 486,
"start_line": 7543,
"end_line": 7547,
"section": "Links",
"shouldFail": true
"section": "Links"
},
{
"markdown": "[link](foo\nbar)\n",
Expand All @@ -3964,26 +3963,23 @@
"example": 489,
"start_line": 7571,
"end_line": 7575,
"section": "Links",
"shouldFail": true
"section": "Links"
},
{
"markdown": "[link](<foo\\>)\n",
"html": "<p>[link](&lt;foo&gt;)</p>\n",
"example": 490,
"start_line": 7579,
"end_line": 7583,
"section": "Links",
"shouldFail": true
"section": "Links"
},
{
"markdown": "[a](<b)c\n[a](<b)c>\n[a](<b>c)\n",
"html": "<p>[a](&lt;b)c\n[a](&lt;b)c&gt;\n[a](<b>c)</p>\n",
"example": 491,
"start_line": 7588,
"end_line": 7596,
"section": "Links",
"shouldFail": true
"section": "Links"
},
{
"markdown": "[link](\\(foo\\))\n",
Expand Down
4 changes: 3 additions & 1 deletion test/specs/new/link_lt.html
@@ -1 +1,3 @@
<p><a href="%3Ctest">URL</a></p>
<p><a href="test">URL</a></p>

<p><a href="test%5C">URL</a></p>
5 changes: 5 additions & 0 deletions test/specs/new/link_lt.md
@@ -1 +1,6 @@
---
pedantic: true
---
[URL](<test)

[URL](<test\>)

1 comment on commit 656c3e4

@vercel
Copy link

@vercel vercel bot commented on 656c3e4 Dec 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.