Эх сурвалжийг харах

fix(HTMLParser): fix ghCodeBlocks being parsed inside code tags

When using html pre/code tags to wrap github's fenced code block syntax,
showdown would parsed them instead of treating them like plain code.

Closes #229
Estevão Soares dos Santos 9 жил өмнө
parent
commit
7d0436d210

+ 41 - 16
dist/showdown.js

@@ -1,4 +1,4 @@
-;/*! showdown 02-01-2016 */
+;/*! showdown 25-01-2016 */
 (function(){
 /**
  * Created by Tivie on 13-07-2015.
@@ -929,7 +929,8 @@ showdown.Converter = function (converterOptions) {
       hashLinkCounts:  {},
       langExtensions:  langExtensions,
       outputModifiers: outputModifiers,
-      converter:       this
+      converter:       this,
+      ghCodeBlocks:    []
     };
 
     // attacklab: Replace ~ with ~T
@@ -1628,6 +1629,7 @@ showdown.subParser('githubCodeBlocks', function (text, options, globals) {
   text = text.replace(/(?:^|\n)```(.*)\n([\s\S]*?)\n```/g, function (wholeMatch, language, codeblock) {
     var end = (options.omitExtraWLInCodeBlocks) ? '' : '\n';
 
+    // First parse the github code block
     codeblock = showdown.subParser('encodeCode')(codeblock);
     codeblock = showdown.subParser('detab')(codeblock);
     codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines
@@ -1635,15 +1637,18 @@ showdown.subParser('githubCodeBlocks', function (text, options, globals) {
 
     codeblock = '<pre><code' + (language ? ' class="' + language + ' language-' + language + '"' : '') + '>' + codeblock + end + '</code></pre>';
 
-    return showdown.subParser('hashBlock')(codeblock, options, globals);
+    codeblock = showdown.subParser('hashBlock')(codeblock, options, globals);
+
+    // Since GHCodeblocks can be false positives, we need to
+    // store the primitive text and the parsed text in a global var,
+    // and then return a token
+    return '\n\n~G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\n\n';
   });
 
   // attacklab: strip sentinel
   text = text.replace(/~0/, '');
 
-  text = globals.converter._dispatch('githubCodeBlocks.after', text, options);
-
-  return text;
+  return globals.converter._dispatch('githubCodeBlocks.after', text, options);
 });
 
 showdown.subParser('hashBlock', function (text, options, globals) {
@@ -2143,11 +2148,10 @@ showdown.subParser('paragraphs', function (text, options, globals) {
 
   for (var i = 0; i < end; i++) {
     var str = grafs[i];
-
     // if this is an HTML marker, copy it
-    if (str.search(/~K(\d+)K/g) >= 0) {
+    if (str.search(/~(K|G)(\d+)\1/g) >= 0) {
       grafsOut.push(str);
-    } else if (str.search(/\S/) >= 0) {
+    } else {
       str = showdown.subParser('spanGamut')(str, options, globals);
       str = str.replace(/^([ \t]*)/g, '<p>');
       str += '</p>';
@@ -2157,18 +2161,39 @@ showdown.subParser('paragraphs', function (text, options, globals) {
 
   /** Unhashify HTML blocks */
   end = grafsOut.length;
+  console.log(text);
   for (i = 0; i < end; i++) {
-    var blockText = '';
+    var blockText = '',
+        grafsOutIt = grafsOut[i],
+        child = false,
+        codeFlag = false;
     // if this is a marker for an html block...
-    while (grafsOut[i].search(/~K(\d+)K/) >= 0) {
-      blockText = globals.gHtmlBlocks[RegExp.$1];
+    while (grafsOutIt.search(/~(K|G)(\d+)\1/) >= 0) {
+      var delim = RegExp.$1,
+          num   = RegExp.$2;
+
+      if (delim === 'K') {
+        blockText = globals.gHtmlBlocks[num];
+      } else {
+        // we need to check if ghBlock is a false positive
+        blockText = (codeFlag) ? globals.ghCodeBlocks[num].text : globals.ghCodeBlocks[num].codeblock;
+      }
       blockText = blockText.replace(/\$/g, '$$$$'); // Escape any dollar signs
-      grafsOut[i] = grafsOut[i].replace(/~K\d+K/, blockText);
+
+      grafsOutIt = grafsOutIt.replace(/(\n\n)?~(K|G)\d+\2(\n\n)?/, blockText);
+      // Check if grafsOutIt is a pre->code
+      if (/^<pre\b[^>]*>\s*<code\b[^>]*>/.test(grafsOutIt)) {
+        codeFlag = true;
+      }
+      child = true;
     }
+    grafsOut[i] = grafsOutIt;
   }
-
-  text = globals.converter._dispatch('paragraphs.after', text, options);
-  return grafsOut.join('\n\n');
+  text = grafsOut.join('\n\n');
+  // Strip leading and trailing lines:
+  text = text.replace(/^\n+/g, '');
+  text = text.replace(/\n+$/g, '');
+  return globals.converter._dispatch('paragraphs.after', text, options);
 });
 
 /**

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
dist/showdown.js.map


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 1 - 1
dist/showdown.min.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
dist/showdown.min.js.map


+ 2 - 1
src/converter.js

@@ -242,7 +242,8 @@ showdown.Converter = function (converterOptions) {
       hashLinkCounts:  {},
       langExtensions:  langExtensions,
       outputModifiers: outputModifiers,
-      converter:       this
+      converter:       this,
+      ghCodeBlocks:    []
     };
 
     // attacklab: Replace ~ with ~T

+ 8 - 4
src/subParsers/githubCodeBlocks.js

@@ -23,6 +23,7 @@ showdown.subParser('githubCodeBlocks', function (text, options, globals) {
   text = text.replace(/(?:^|\n)```(.*)\n([\s\S]*?)\n```/g, function (wholeMatch, language, codeblock) {
     var end = (options.omitExtraWLInCodeBlocks) ? '' : '\n';
 
+    // First parse the github code block
     codeblock = showdown.subParser('encodeCode')(codeblock);
     codeblock = showdown.subParser('detab')(codeblock);
     codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines
@@ -30,13 +31,16 @@ showdown.subParser('githubCodeBlocks', function (text, options, globals) {
 
     codeblock = '<pre><code' + (language ? ' class="' + language + ' language-' + language + '"' : '') + '>' + codeblock + end + '</code></pre>';
 
-    return showdown.subParser('hashBlock')(codeblock, options, globals);
+    codeblock = showdown.subParser('hashBlock')(codeblock, options, globals);
+
+    // Since GHCodeblocks can be false positives, we need to
+    // store the primitive text and the parsed text in a global var,
+    // and then return a token
+    return '\n\n~G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\n\n';
   });
 
   // attacklab: strip sentinel
   text = text.replace(/~0/, '');
 
-  text = globals.converter._dispatch('githubCodeBlocks.after', text, options);
-
-  return text;
+  return globals.converter._dispatch('githubCodeBlocks.after', text, options);
 });

+ 30 - 10
src/subParsers/paragraphs.js

@@ -15,11 +15,10 @@ showdown.subParser('paragraphs', function (text, options, globals) {
 
   for (var i = 0; i < end; i++) {
     var str = grafs[i];
-
     // if this is an HTML marker, copy it
-    if (str.search(/~K(\d+)K/g) >= 0) {
+    if (str.search(/~(K|G)(\d+)\1/g) >= 0) {
       grafsOut.push(str);
-    } else if (str.search(/\S/) >= 0) {
+    } else {
       str = showdown.subParser('spanGamut')(str, options, globals);
       str = str.replace(/^([ \t]*)/g, '<p>');
       str += '</p>';
@@ -29,16 +28,37 @@ showdown.subParser('paragraphs', function (text, options, globals) {
 
   /** Unhashify HTML blocks */
   end = grafsOut.length;
+  console.log(text);
   for (i = 0; i < end; i++) {
-    var blockText = '';
+    var blockText = '',
+        grafsOutIt = grafsOut[i],
+        child = false,
+        codeFlag = false;
     // if this is a marker for an html block...
-    while (grafsOut[i].search(/~K(\d+)K/) >= 0) {
-      blockText = globals.gHtmlBlocks[RegExp.$1];
+    while (grafsOutIt.search(/~(K|G)(\d+)\1/) >= 0) {
+      var delim = RegExp.$1,
+          num   = RegExp.$2;
+
+      if (delim === 'K') {
+        blockText = globals.gHtmlBlocks[num];
+      } else {
+        // we need to check if ghBlock is a false positive
+        blockText = (codeFlag) ? globals.ghCodeBlocks[num].text : globals.ghCodeBlocks[num].codeblock;
+      }
       blockText = blockText.replace(/\$/g, '$$$$'); // Escape any dollar signs
-      grafsOut[i] = grafsOut[i].replace(/~K\d+K/, blockText);
+
+      grafsOutIt = grafsOutIt.replace(/(\n\n)?~(K|G)\d+\2(\n\n)?/, blockText);
+      // Check if grafsOutIt is a pre->code
+      if (/^<pre\b[^>]*>\s*<code\b[^>]*>/.test(grafsOutIt)) {
+        codeFlag = true;
+      }
+      child = true;
     }
+    grafsOut[i] = grafsOutIt;
   }
-
-  text = globals.converter._dispatch('paragraphs.after', text, options);
-  return grafsOut.join('\n\n');
+  text = grafsOut.join('\n\n');
+  // Strip leading and trailing lines:
+  text = text.replace(/^\n+/g, '');
+  text = text.replace(/\n+$/g, '');
+  return globals.converter._dispatch('paragraphs.after', text, options);
 });

+ 1 - 2
test/cases/list-with-code.html

@@ -2,6 +2,5 @@
   <li><p>A list item with code:</p>
 
     <pre><code>alert('Hello world!');
-    </code></pre>
-  </li>
+    </code></pre></li>
 </ul>

+ 2 - 4
test/issues/#183.gh-code-blocks-within-lists-do-not-render-properly.html

@@ -5,14 +5,12 @@
         <pre><code class="sh language-sh">$ git clone thing.git
 
 dfgdfg
-        </code></pre>
-    </li>
+        </code></pre></li>
     <li>
         <p>I am another thing!</p>
 
         <pre><code class="sh language-sh">$ git clone other-thing.git
 
 foobar
-        </code></pre>
-    </li>
+        </code></pre></li>
 </ol>

+ 25 - 0
test/issues/#229.2.code-being-parsed-inside-HTML-code-tags.html

@@ -0,0 +1,25 @@
+<pre lang="no-highlight"><code>
+    foo
+
+    ```javascript
+    var s = "JavaScript syntax highlighting";
+    alert(s);
+    ```
+
+    bar
+</code></pre>
+
+<p>this is a long paragraph</p>
+
+<p>this is another long paragraph</p>
+
+<pre lang="no-highlight"><code>```javascript
+var s = "JavaScript syntax highlighting";
+alert(s);
+```
+
+```python
+s = "Python syntax highlighting"
+print s
+```
+</code></pre>

+ 25 - 0
test/issues/#229.2.code-being-parsed-inside-HTML-code-tags.md

@@ -0,0 +1,25 @@
+<pre lang="no-highlight"><code>
+foo
+
+```javascript
+var s = "JavaScript syntax highlighting";
+alert(s);
+```
+
+bar
+</code></pre>
+
+this is a long paragraph
+
+this is another long paragraph
+
+<pre lang="no-highlight"><code>```javascript
+var s = "JavaScript syntax highlighting";
+alert(s);
+```
+
+```python
+s = "Python syntax highlighting"
+print s
+```
+</code></pre>

+ 16 - 0
test/issues/#229.code-being-parsed-inside-HTML-code-tags.html

@@ -0,0 +1,16 @@
+<pre lang="no-highlight"><code>
+```javascript
+var s = "JavaScript syntax highlighting";
+alert(s);
+```
+
+```python
+s = "Python syntax highlighting"
+print s
+```
+
+```
+No language indicated, so no syntax highlighting.
+But let's throw in a <b>tag</b>.
+```
+</code></pre>

+ 16 - 0
test/issues/#229.code-being-parsed-inside-HTML-code-tags.md

@@ -0,0 +1,16 @@
+<pre lang="no-highlight"><code>
+```javascript
+var s = "JavaScript syntax highlighting";
+alert(s);
+```
+
+```python
+s = "Python syntax highlighting"
+print s
+```
+
+```
+No language indicated, so no syntax highlighting.
+But let's throw in a <b>tag</b>.
+```
+</code></pre>

+ 4 - 4
test/karlcow/list-code.html

@@ -1,8 +1,8 @@
 <ul>
-<li><p>a list containing a block of code</p>
+    <li>
+        <p>a list containing a block of code</p>
 
-<pre><code>10 PRINT HELLO INFINITE
+        <pre><code>10 PRINT HELLO INFINITE
 20 GOTO 10
-</code></pre>
-</li>
+</code></pre></li>
 </ul>

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно