diff --git a/index.compiler.spec.tsx b/index.compiler.spec.tsx index 190137d0..ea860d8e 100644 --- a/index.compiler.spec.tsx +++ b/index.compiler.spec.tsx @@ -3529,6 +3529,149 @@ describe('footnotes', () => { `) }) + + it('should handle multiline footnotes', () => { + render( + compiler(theredoc` + foo[^abc] bar + + [^abc]: Baz + line2 + line3 + + After footnotes content + `) + ) + + expect(root.innerHTML).toMatchInlineSnapshot(` +
+
+

+ foo + + + abc + + + bar +

+

+ After footnotes content +

+
+ +
+ `) + }) + + it('should handle mixed multiline and singleline footnotes', () => { + render( + compiler(theredoc` + a[^a] b[^b] c[^c] + + [^a]: single + [^b]: bbbb + bbbb + bbbb + [^c]: single-c + `) + ) + + expect(root.innerHTML).toMatchInlineSnapshot(` +
+

+ a + + + a + + + b + + + b + + + c + + + c + + +

+ +
+ `) + }) + + it('should handle indented multiline footnote', () => { + render( + compiler(theredoc` + Here's a simple footnote,[^1] and here's a longer one.[^bignote] + + [^1]: This is the first footnote. + + [^bignote]: Here's one with multiple paragraphs and code. + + Indent paragraphs to include them in the footnote. + + \`{ my code }\` + + Add as many paragraphs as you like. + `) + ) + + expect(root.innerHTML).toMatchInlineSnapshot(` +
+

+ Here's a simple footnote, + + + 1 + + + and here's a longer one. + + + bignote + + +

+ +
+ `) + }) }) describe('options.namedCodesToUnicode', () => { diff --git a/index.tsx b/index.tsx index 0a8e5b48..e6839eee 100644 --- a/index.tsx +++ b/index.tsx @@ -187,7 +187,41 @@ const CODE_BLOCK_R = /^(?: {4}[^\n]+\n*)+(?:\n *)+\n?/ const CODE_INLINE_R = /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/ const CONSECUTIVE_NEWLINE_R = /^(?:\n *)*\n/ const CR_NEWLINE_R = /\r\n?/g -const FOOTNOTE_R = /^\[\^([^\]]+)](:.*)\n/ + +/** + * Matches footnotes on the format: + * + * [^key]: value + * + * Matches multiline footnotes + * + * [^key]: row + * row + * row + * + * And empty lines in indented multiline footnotes + * + * [^key]: indented with + * row + * + * row + * + * Explanation: + * + * 1. Look for the starting tag, eg: [^key] + * ^\[\^([^\]]+)] + * + * 2. The first line starts with a colon, and continues for the rest of the line + * :(.*) + * + * 3. Parse as many additional lines as possible. Matches new non-empty lines that doesn't begin with a new footnote definition. + * (\n(?!\[\^).+) + * + * 4. ...or allows for repeated newlines if the next line begins with at least four whitespaces. + * (\n+ {4,}.*) + */ +const FOOTNOTE_R = /^\[\^([^\]]+)](:(.*)((\n+ {4,}.*)|(\n(?!\[\^).+))*)/ + const FOOTNOTE_REFERENCE_R = /^\[\^([^\]]+)]/ const FORMFEED_R = /\f/g const FRONT_MATTER_R = /^---[ \t]*\n(.|\n)*\n---[ \t]*\n/