浏览代码

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](<>)`
Estevao Soares dos Santos 8 年之前
父节点
当前提交
30aa18c003

+ 28 - 21
dist/showdown.js

@@ -1,4 +1,4 @@
-;/*! showdown 28-05-2017 */
+;/*! showdown 30-05-2017 */
 (function(){
 /**
  * Created by Tivie on 13-07-2015.
@@ -1350,17 +1350,16 @@ showdown.subParser('anchors', function (text, options, globals) {
 
   text = globals.converter._dispatch('anchors.before', text, options, globals);
 
-  var writeAnchorTag = function (wholeMatch, m1, m2, m3, m4, m5, m6, m7) {
-    if (showdown.helper.isUndefined(m7)) {
-      m7 = '';
+  var writeAnchorTag = function (wholeMatch, linkText, linkId, url, m5, m6, title) {
+    if (showdown.helper.isUndefined(title)) {
+      title = '';
     }
-    wholeMatch = m1;
-    var linkText = m2,
-        linkId = m3.toLowerCase(),
-        url = m4,
-        title = m7;
+    linkId = linkId.toLowerCase();
 
-    if (!url) {
+    // Special case for explicit empty url
+    if (wholeMatch.search(/\(<?\s*>? ?(['"].*['"])?\)$/m) > -1) {
+      url = '';
+    } else if (!url) {
       if (!linkId) {
         // lower-case and turn embedded newlines into spaces
         linkId = linkText.toLowerCase().replace(/ ?\n/g, ' ');
@@ -1373,12 +1372,7 @@ showdown.subParser('anchors', function (text, options, globals) {
           title = globals.gTitles[linkId];
         }
       } else {
-        if (wholeMatch.search(/\(\s*\)$/m) > -1) {
-          // Special case for explicit empty url
-          url = '';
-        } else {
-          return wholeMatch;
-        }
+        return wholeMatch;
       }
     }
 
@@ -1405,16 +1399,21 @@ showdown.subParser('anchors', function (text, options, globals) {
   };
 
   // First, handle reference-style links: [link text] [id]
-  text = text.replace(/(\[((?:\[[^\]]*]|[^\[\]])*)][ ]?(?:\n[ ]*)?\[(.*?)])()()()()/g, writeAnchorTag);
+  text = text.replace(/\[((?:\[[^\]]*]|[^\[\]])*)] ?(?:\n *)?\[(.*?)]()()()()/g, writeAnchorTag);
 
   // Next, inline-style links: [link text](url "optional title")
-  text = text.replace(/(\[((?:\[[^\]]*]|[^\[\]])*)]\([ \t]*()<?(.*?(?:\(.*?\).*?)?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,
+  // cases with crazy urls like ./image/cat1).png
+  text = text.replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]?<([^>]*)>(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g,
+    writeAnchorTag);
+
+  // normal cases
+  text = text.replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]?<?([\S]+?(?:\([\S]*?\)[\S]*?)?)>?(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g,
                       writeAnchorTag);
 
   // handle reference-style shortcuts: [link text]
   // These must come last in case you've also got [link test][1]
   // or [link test](/foo)
-  text = text.replace(/(\[([^\[\]]+)])()()()()()/g, writeAnchorTag);
+  text = text.replace(/\[([^\[\]]+)]()()()()()/g, writeAnchorTag);
 
   // Lastly handle GithubMentions if option is enabled
   if (options.ghMentions) {
@@ -2174,7 +2173,8 @@ showdown.subParser('images', function (text, options, globals) {
 
   text = globals.converter._dispatch('images.before', text, options, globals);
 
-  var inlineRegExp      = /!\[(.*?)]\s?\([ \t]*()<?(\S+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(['"])(.*?)\6[ \t]*)?\)/g,
+  var inlineRegExp      = /!\[([^\]]*?)][ \t]*()\([ \t]?<?([\S]+?(?:\([\S]*?\)[\S]*?)?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\6)?[ \t]?\)/g,
+      crazyRegExp       = /!\[([^\]]*?)][ \t]*()\([ \t]?<([^>]*)>(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(?:(["'])([^"]*?)\6))?[ \t]?\)/g,
       referenceRegExp   = /!\[([^\]]*?)] ?(?:\n *)?\[(.*?)]()()()()()/g,
       refShortcutRegExp = /!\[([^\[\]]+)]()()()()()/g;
 
@@ -2189,8 +2189,11 @@ showdown.subParser('images', function (text, options, globals) {
     if (!title) {
       title = '';
     }
+    // Special case for explicit empty url
+    if (wholeMatch.search(/\(<?\s*>? ?(['"].*['"])?\)$/m) > -1) {
+      url = '';
 
-    if (url === '' || url === null) {
+    } else if (url === '' || url === null) {
       if (linkId === '' || linkId === null) {
         // lower-case and turn embedded newlines into spaces
         linkId = altText.toLowerCase().replace(/ ?\n/g, ' ');
@@ -2244,6 +2247,10 @@ showdown.subParser('images', function (text, options, globals) {
   text = text.replace(referenceRegExp, writeImageTag);
 
   // Next, handle inline images:  ![alt text](url =<width>x<height> "optional title")
+  // cases with crazy urls like ./image/cat1).png
+  text = text.replace(crazyRegExp, writeImageTag);
+
+  // normal cases
   text = text.replace(inlineRegExp, writeImageTag);
 
   // handle reference-style shortcuts: |[img text]

文件差异内容过多而无法显示
+ 0 - 0
dist/showdown.js.map


文件差异内容过多而无法显示
+ 1 - 1
dist/showdown.min.js


文件差异内容过多而无法显示
+ 0 - 0
dist/showdown.min.js.map


+ 17 - 18
src/subParsers/anchors.js

@@ -6,17 +6,16 @@ showdown.subParser('anchors', function (text, options, globals) {
 
   text = globals.converter._dispatch('anchors.before', text, options, globals);
 
-  var writeAnchorTag = function (wholeMatch, m1, m2, m3, m4, m5, m6, m7) {
-    if (showdown.helper.isUndefined(m7)) {
-      m7 = '';
+  var writeAnchorTag = function (wholeMatch, linkText, linkId, url, m5, m6, title) {
+    if (showdown.helper.isUndefined(title)) {
+      title = '';
     }
-    wholeMatch = m1;
-    var linkText = m2,
-        linkId = m3.toLowerCase(),
-        url = m4,
-        title = m7;
+    linkId = linkId.toLowerCase();
 
-    if (!url) {
+    // Special case for explicit empty url
+    if (wholeMatch.search(/\(<?\s*>? ?(['"].*['"])?\)$/m) > -1) {
+      url = '';
+    } else if (!url) {
       if (!linkId) {
         // lower-case and turn embedded newlines into spaces
         linkId = linkText.toLowerCase().replace(/ ?\n/g, ' ');
@@ -29,12 +28,7 @@ showdown.subParser('anchors', function (text, options, globals) {
           title = globals.gTitles[linkId];
         }
       } else {
-        if (wholeMatch.search(/\(\s*\)$/m) > -1) {
-          // Special case for explicit empty url
-          url = '';
-        } else {
-          return wholeMatch;
-        }
+        return wholeMatch;
       }
     }
 
@@ -61,16 +55,21 @@ showdown.subParser('anchors', function (text, options, globals) {
   };
 
   // First, handle reference-style links: [link text] [id]
-  text = text.replace(/(\[((?:\[[^\]]*]|[^\[\]])*)][ ]?(?:\n[ ]*)?\[(.*?)])()()()()/g, writeAnchorTag);
+  text = text.replace(/\[((?:\[[^\]]*]|[^\[\]])*)] ?(?:\n *)?\[(.*?)]()()()()/g, writeAnchorTag);
 
   // Next, inline-style links: [link text](url "optional title")
-  text = text.replace(/(\[((?:\[[^\]]*]|[^\[\]])*)]\([ \t]*()<?(.*?(?:\(.*?\).*?)?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,
+  // cases with crazy urls like ./image/cat1).png
+  text = text.replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]?<([^>]*)>(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g,
+    writeAnchorTag);
+
+  // normal cases
+  text = text.replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]?<?([\S]+?(?:\([\S]*?\)[\S]*?)?)>?(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g,
                       writeAnchorTag);
 
   // handle reference-style shortcuts: [link text]
   // These must come last in case you've also got [link test][1]
   // or [link test](/foo)
-  text = text.replace(/(\[([^\[\]]+)])()()()()()/g, writeAnchorTag);
+  text = text.replace(/\[([^\[\]]+)]()()()()()/g, writeAnchorTag);
 
   // Lastly handle GithubMentions if option is enabled
   if (options.ghMentions) {

+ 10 - 2
src/subParsers/images.js

@@ -6,7 +6,8 @@ showdown.subParser('images', function (text, options, globals) {
 
   text = globals.converter._dispatch('images.before', text, options, globals);
 
-  var inlineRegExp      = /!\[(.*?)]\s?\([ \t]*()<?(\S+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(['"])(.*?)\6[ \t]*)?\)/g,
+  var inlineRegExp      = /!\[([^\]]*?)][ \t]*()\([ \t]?<?([\S]+?(?:\([\S]*?\)[\S]*?)?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\6)?[ \t]?\)/g,
+      crazyRegExp       = /!\[([^\]]*?)][ \t]*()\([ \t]?<([^>]*)>(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(?:(["'])([^"]*?)\6))?[ \t]?\)/g,
       referenceRegExp   = /!\[([^\]]*?)] ?(?:\n *)?\[(.*?)]()()()()()/g,
       refShortcutRegExp = /!\[([^\[\]]+)]()()()()()/g;
 
@@ -21,8 +22,11 @@ showdown.subParser('images', function (text, options, globals) {
     if (!title) {
       title = '';
     }
+    // Special case for explicit empty url
+    if (wholeMatch.search(/\(<?\s*>? ?(['"].*['"])?\)$/m) > -1) {
+      url = '';
 
-    if (url === '' || url === null) {
+    } else if (url === '' || url === null) {
       if (linkId === '' || linkId === null) {
         // lower-case and turn embedded newlines into spaces
         linkId = altText.toLowerCase().replace(/ ?\n/g, ' ');
@@ -76,6 +80,10 @@ showdown.subParser('images', function (text, options, globals) {
   text = text.replace(referenceRegExp, writeImageTag);
 
   // Next, handle inline images:  ![alt text](url =<width>x<height> "optional title")
+  // cases with crazy urls like ./image/cat1).png
+  text = text.replace(crazyRegExp, writeImageTag);
+
+  // normal cases
   text = text.replace(inlineRegExp, writeImageTag);
 
   // handle reference-style shortcuts: |[img text]

+ 4 - 0
test/cases/anchors-followed-by-brakets.html

@@ -0,0 +1,4 @@
+<p>This is a <a href="https://en.wikipedia.org/wiki/Textile">link</a> (some other text)</p>
+<p>This is a <a href="https://en.wikipedia.org/wiki/Textile_(markup">link</a> (some other text)</p>
+<p>This is a <a href="https://en.wikipedia.org/wiki/Textile_(markup_language)">link</a> (some other text)</p>
+<p>This is a <a href="https://en.wikipedia.org/wiki/Textile_(markup_language)/foo">link</a> (some other text)</p>

+ 7 - 0
test/cases/anchors-followed-by-brakets.md

@@ -0,0 +1,7 @@
+This is a [link](https://en.wikipedia.org/wiki/Textile) (some other text)
+
+This is a [link](https://en.wikipedia.org/wiki/Textile_(markup) (some other text)
+
+This is a [link](https://en.wikipedia.org/wiki/Textile_(markup_language)) (some other text)
+
+This is a [link](https://en.wikipedia.org/wiki/Textile_(markup_language)/foo) (some other text)

+ 2 - 0
test/cases/images-followed-by-brackets.html

@@ -0,0 +1,2 @@
+<p><img src="./image/cat1.png" alt="image link" />(some text between brackets)</p>
+<p><img src="./image/cat(1).png" alt="image link" />(some text between brackets)</p>

+ 3 - 0
test/cases/images-followed-by-brackets.md

@@ -0,0 +1,3 @@
+![image link](<./image/cat1.png>)(some text between brackets)
+
+![image link](<./image/cat(1).png>)(some text between brackets)

+ 4 - 0
test/issues/#390.brackets-in-URL-break-images.html

@@ -0,0 +1,4 @@
+<p>This is an <img src="./image/cat(1).png" alt="image" /></p>
+<p>This is another <img src="./image/cat(1).png" alt="image" /></p>
+<p><a href="http://example.com"><img src="./image/cat(1).png" alt="image link" /></a></p>
+<p><a href="http://example.com"><img src="./image/cat1).png" alt="image link" /></a></p>

+ 9 - 0
test/issues/#390.brackets-in-URL-break-images.md

@@ -0,0 +1,9 @@
+This is an ![image][]
+
+[image]: ./image/cat(1).png
+
+This is another ![image](./image/cat(1).png)
+
+[![image link](./image/cat(1).png)](http://example.com)
+
+[![image link](<./image/cat1).png>)](http://example.com)

+ 1 - 0
test/issues/#390.brackets-in-URL-break-links.html

@@ -1,2 +1,3 @@
 <p>This is a <a href="https://en.wikipedia.org/wiki/Textile_(markup_language)" title="Textile">link</a>.</p>
 <p>This is another <a href="https://en.wikipedia.org/wiki/Textile_(markup_language)" title="Textile">link</a>.</p>
+<p><a href="./image/cat1).png" title="title">link</a></p>

+ 2 - 0
test/issues/#390.brackets-in-URL-break-links.md

@@ -3,3 +3,5 @@ This is a [link][].
 [link]: https://en.wikipedia.org/wiki/Textile_(markup_language) "Textile"
 
 This is another [link](https://en.wikipedia.org/wiki/Textile_(markup_language) "Textile").
+
+[link](<./image/cat1).png> "title")

+ 5 - 0
test/issues/URLs-with-multiple-parenthesis.html

@@ -0,0 +1,5 @@
+<p><a href="./images(1)/cat(1).png">link</a></p>
+<p><a href="./images(1)/cat(1).png" title="title">link</a></p>
+<p><img src="./images(1)/cat(1).png" alt="image" /></p>
+<p><img src="./images(1)/cat(1).png" alt="image" title="title" /></p>
+<p><img src="./images(1)/cat(1).png" alt="image" title="title" width="800" height="600" /></p>

+ 9 - 0
test/issues/URLs-with-multiple-parenthesis.md

@@ -0,0 +1,9 @@
+[link](<./images(1)/cat(1).png>)
+
+[link](<./images(1)/cat(1).png> "title")
+
+![image](<./images(1)/cat(1).png>)
+
+![image](<./images(1)/cat(1).png> "title")
+
+![image](<./images(1)/cat(1).png> =800x600 "title")

+ 14 - 0
test/issues/crazy-urls.html

@@ -0,0 +1,14 @@
+<p><img src="images(1)/cat(1).png" alt="my cat" /></p>
+<p><a href="images(1)/cat(1).png">my cat</a></p>
+<p><img src="some.com/crazy url with spaces" alt="foo" /></p>
+<p><img src="some.com/crazy url with spaces" alt="foo" title="title" /></p>
+<p><a href="some.com/crazy url with spaces">foo</a></p>
+<p><a href="some.com/crazy url with spaces" title="title">foo</a></p>
+<p><img src="" alt="empty" /></p>
+<p><a href="">empty</a></p>
+<p><img src="" alt="empty" title="title" /></p>
+<p><a href="" title="title">empty</a></p>
+<p><img src="" alt="empty" /></p>
+<p><a href="">empty</a></p>
+<p><img src="" alt="empty" title="title" /></p>
+<p><a href="" title="title">empty</a></p>

+ 27 - 0
test/issues/crazy-urls.md

@@ -0,0 +1,27 @@
+![my cat](<images(1)/cat(1).png>)
+
+[my cat](<images(1)/cat(1).png>)
+
+![foo](<some.com/crazy url with spaces>)
+
+![foo](<some.com/crazy url with spaces> "title")
+
+[foo](<some.com/crazy url with spaces>)
+
+[foo](<some.com/crazy url with spaces> "title")
+
+![empty](<>)
+
+[empty](<>)
+
+![empty](<> "title")
+
+[empty](<> "title")
+
+![empty](< >)
+
+[empty](< >)
+
+![empty](< > "title")
+
+[empty](< > "title")

部分文件因为文件数量过多而无法显示