|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import { Lexer } from "marked"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function parseMarkdownIntoBlocks(markdown: string): string[] { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const hasFootnoteReference = /\[\^[^\]\s]{1,200}\](?!:)/.test(markdown); |
|
|
const hasFootnoteDefinition = /\[\^[^\]\s]{1,200}\]:/.test(markdown); |
|
|
|
|
|
|
|
|
|
|
|
if (hasFootnoteReference || hasFootnoteDefinition) { |
|
|
return [markdown]; |
|
|
} |
|
|
|
|
|
const tokens = Lexer.lex(markdown, { gfm: true }); |
|
|
|
|
|
|
|
|
const mergedBlocks: string[] = []; |
|
|
const htmlStack: string[] = []; |
|
|
|
|
|
for (let i = 0; i < tokens.length; i++) { |
|
|
const token = tokens[i]; |
|
|
const currentBlock = token.raw; |
|
|
|
|
|
|
|
|
if (htmlStack.length > 0) { |
|
|
|
|
|
mergedBlocks[mergedBlocks.length - 1] += currentBlock; |
|
|
|
|
|
|
|
|
if (token.type === "html") { |
|
|
const closingTagMatch = currentBlock.match(/<\/(\w+)>/); |
|
|
if (closingTagMatch) { |
|
|
const closingTag = closingTagMatch[1]; |
|
|
|
|
|
if (htmlStack[htmlStack.length - 1] === closingTag) { |
|
|
htmlStack.pop(); |
|
|
} |
|
|
} |
|
|
} |
|
|
continue; |
|
|
} |
|
|
|
|
|
|
|
|
if (token.type === "html" && token.block) { |
|
|
const openingTagMatch = currentBlock.match(/<(\w+)[\s>]/); |
|
|
if (openingTagMatch) { |
|
|
const tagName = openingTagMatch[1]; |
|
|
|
|
|
const hasClosingTag = currentBlock.includes(`</${tagName}>`); |
|
|
if (!hasClosingTag) { |
|
|
|
|
|
htmlStack.push(tagName); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (currentBlock.trim() === "$$" && mergedBlocks.length > 0) { |
|
|
const previousBlock = mergedBlocks.at(-1); |
|
|
|
|
|
if (!previousBlock) { |
|
|
mergedBlocks.push(currentBlock); |
|
|
continue; |
|
|
} |
|
|
|
|
|
|
|
|
const prevStartsWith$$ = previousBlock.trimStart().startsWith("$$"); |
|
|
const prevDollarCount = (previousBlock.match(/\$\$/g) || []).length; |
|
|
|
|
|
|
|
|
if (prevStartsWith$$ && prevDollarCount % 2 === 1) { |
|
|
mergedBlocks[mergedBlocks.length - 1] = previousBlock + currentBlock; |
|
|
continue; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (mergedBlocks.length > 0 && currentBlock.trimEnd().endsWith("$$")) { |
|
|
const previousBlock = mergedBlocks.at(-1); |
|
|
|
|
|
if (!previousBlock) { |
|
|
mergedBlocks.push(currentBlock); |
|
|
continue; |
|
|
} |
|
|
|
|
|
const prevStartsWith$$ = previousBlock.trimStart().startsWith("$$"); |
|
|
const prevDollarCount = (previousBlock.match(/\$\$/g) || []).length; |
|
|
const currDollarCount = (currentBlock.match(/\$\$/g) || []).length; |
|
|
|
|
|
|
|
|
|
|
|
if ( |
|
|
prevStartsWith$$ && |
|
|
prevDollarCount % 2 === 1 && |
|
|
!currentBlock.trimStart().startsWith("$$") && |
|
|
currDollarCount === 1 |
|
|
) { |
|
|
mergedBlocks[mergedBlocks.length - 1] = previousBlock + currentBlock; |
|
|
continue; |
|
|
} |
|
|
} |
|
|
|
|
|
mergedBlocks.push(currentBlock); |
|
|
} |
|
|
|
|
|
return mergedBlocks; |
|
|
} |
|
|
|