Browse Source

Backport PR #11479: Fix malformed fenced code block Markdown rendering (#11500)

Co-authored-by: Michał Krassowski <5832902+krassowski@users.noreply.github.com>
MeeseeksMachine 3 years ago
parent
commit
9d8f543f18
2 changed files with 36 additions and 1 deletions
  1. 8 1
      packages/rendermime/src/latex.ts
  2. 28 0
      packages/rendermime/test/latex.spec.ts

+ 8 - 1
packages/rendermime/src/latex.ts

@@ -35,10 +35,17 @@ export function removeMath(text: string): { text: string; math: string[] } {
   // we still have to consider them at this point; the following issue has happened several times:
   //
   //     `$foo` and `$bar` are variables.  -->  <code>$foo ` and `$bar</code> are variables.
-  const hasCodeSpans = /`/.test(text);
+  const hasCodeSpans = text.includes('`') || text.includes('~~~');
   if (hasCodeSpans) {
     text = text
       .replace(/~/g, '~T')
+      // note: the `fence` (three or more consecutive tildes or backticks)
+      // can be followed by an `info string` but this cannot include backticks,
+      // see specification: https://spec.commonmark.org/0.30/#info-string
+      .replace(
+        /^(?<fence>`{3,}|(~T){3,})[^`\n]*\n([\s\S]*?)^\k<fence>`*$/gm,
+        wholematch => wholematch.replace(/\$/g, '~D')
+      )
       .replace(/(^|[^\\])(`+)([^\n]*?[^`\n])\2(?!`)/gm, wholematch =>
         wholematch.replace(/\$/g, '~D')
       );

+ 28 - 0
packages/rendermime/test/latex.spec.ts

@@ -19,6 +19,34 @@ describe('jupyter-ui', () => {
       expect(math).toEqual([]);
     });
 
+    it('should handle fenced code blocks', () => {
+      const input = '```\n$foo\n$bar\n```';
+      const { text, math } = removeMath(input);
+      expect(text).toBe(input);
+      expect(math).toEqual([]);
+    });
+
+    it('should handle tilde fenced code blocks', () => {
+      const input = '~~~\n$foo\n$bar\n~~~';
+      const { text, math } = removeMath(input);
+      expect(text).toBe(input);
+      expect(math).toEqual([]);
+    });
+
+    it('should handle long fenced code blocks', () => {
+      const input = '````\n$foo\n$bar\n```\n``````';
+      const { text, math } = removeMath(input);
+      expect(text).toBe(input);
+      expect(math).toEqual([]);
+    });
+
+    it('should handle fenced code blocks with info string', () => {
+      const input = '```R\ndata[data$foo > 1 & data$bar < 2,]\n```';
+      const { text, math } = removeMath(input);
+      expect(text).toBe(input);
+      expect(math).toEqual([]);
+    });
+
     it('should handle math markers', () => {
       const input = ' @@0@@ hello, $ /alpha $, there';
       const { text, math } = removeMath(input);