From 53c4f4039c5a6556b3cb8d8f1584e81f409e77fd Mon Sep 17 00:00:00 2001 From: Dmitriy Pleshevskiy <dmitriy@ideascup.me> Date: Sun, 12 Jun 2022 01:28:56 +0300 Subject: [PATCH] par(md): add softbreak --- par/md.test.ts | 14 +++++++++++++- par/md.ts | 48 ++++++++++++++++++++++++++++++++---------------- 2 files changed, 45 insertions(+), 17 deletions(-) diff --git a/par/md.test.ts b/par/md.test.ts index 45a24ba..1de1d6c 100644 --- a/par/md.test.ts +++ b/par/md.test.ts @@ -52,7 +52,6 @@ Deno.test({ Deno.test({ name: "should parse ATX header if line contains additional spaces", - only: true, fn: () => { const par = new MarkdownParser(); assertEquals(ren.render(par.parse(" # hello")), "<h1>hello</h1>"); @@ -101,3 +100,16 @@ Deno.test({ assertEquals(ren.render(par.parse("hello")), "<p>hello</p>"); }, }); + +Deno.test({ + name: "should parse paragraph with softbreak", + fn: () => { + const par = new MarkdownParser(); + + const input = `\ +hello +world`; + + assertEquals(ren.render(par.parse(input)), "<p>hello world</p>"); + }, +}); diff --git a/par/md.ts b/par/md.ts index 0cc3e1c..dd4ea9d 100644 --- a/par/md.ts +++ b/par/md.ts @@ -34,11 +34,15 @@ function DocChild(content: AstDocumentChild): Elem { } function Heading(ast: AstAtxHeading): Elem { - return new Elem(`h${ast.level}`, {}, ast.content.map(Text)); + return new Elem(`h${ast.level}`, {}, ast.content.map(InlineContent)); } function Paragraph(ast: AstParagraph): Elem { - return new Elem("p", {}, ast.content.map(Text)); + return new Elem("p", {}, ast.content.map(InlineContent)); +} + +function InlineContent(ast: AstInlineContent): TextNode { + return Text(ast); } function Text(ast: AstText): TextNode { @@ -92,13 +96,22 @@ function parseParagraph(ast: AstDocument, readStr: string): string | null { }; ast.content.push(paragraph); - const paragraphInlineContent = readStr.includes("\n") - ? readStr.slice(0, readStr.indexOf("\n") + 1) - : readStr; + let paragraphInlineContent = ""; + while (!RE_EMPTY_LINE.test(readStr)) { + console.log({ readStr }); + paragraphInlineContent += readStr.includes("\n") + ? readStr.slice(0, readStr.indexOf("\n") + 1) + : readStr; + readStr = readStr.slice(paragraphInlineContent.length); + } - parseInlineContent(paragraph, paragraphInlineContent); + console.log({ paragraphInlineContent, readStr }); - return readStr.slice(paragraphInlineContent.length); + if (paragraphInlineContent.length) { + parseInlineContent(paragraph, paragraphInlineContent); + } + + return readStr; } function parseInlineContent( @@ -107,11 +120,11 @@ function parseInlineContent( ): string | null { if (!readStr.length) return null; - const text: AstText = { - kind: AstKind.Text, - content: readStr.trim(), - }; - ast.content.push(text); + const parts = readStr.split("\n").filter(Boolean).map( + (textPart): AstText => ({ kind: AstKind.Text, content: textPart }), + ); + + ast.content = parts; return readStr; } @@ -121,16 +134,19 @@ function parseInlineContent( type AstDocument = BaseAstItem<AstKind.Document, AstDocumentChild[]>; type AstDocumentChild = AstAtxHeading | AstParagraph; -interface AstAtxHeading extends BaseAstItem<AstKind.AtxHeading, AstText[]> { +interface AstAtxHeading + extends BaseAstItem<AstKind.AtxHeading, AstInlineContent[]> { level: HeadingLevel; } -type AstParagraph = BaseAstItem<AstKind.Paragraph, AstText[]>; +type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6; + +type AstParagraph = BaseAstItem<AstKind.Paragraph, AstInlineContent[]>; + +type AstInlineContent = AstText; type AstText = BaseAstItem<AstKind.Text, string>; -type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6; - interface BaseAstItem<K extends AstKind, Cont> { kind: K; content: Cont;