par(md): add softbreak
This commit is contained in:
parent
9551f3ae1e
commit
53c4f4039c
2 changed files with 45 additions and 17 deletions
|
@ -52,7 +52,6 @@ Deno.test({
|
||||||
|
|
||||||
Deno.test({
|
Deno.test({
|
||||||
name: "should parse ATX header if line contains additional spaces",
|
name: "should parse ATX header if line contains additional spaces",
|
||||||
only: true,
|
|
||||||
fn: () => {
|
fn: () => {
|
||||||
const par = new MarkdownParser();
|
const par = new MarkdownParser();
|
||||||
assertEquals(ren.render(par.parse(" # hello")), "<h1>hello</h1>");
|
assertEquals(ren.render(par.parse(" # hello")), "<h1>hello</h1>");
|
||||||
|
@ -101,3 +100,16 @@ Deno.test({
|
||||||
assertEquals(ren.render(par.parse("hello")), "<p>hello</p>");
|
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>");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
48
par/md.ts
48
par/md.ts
|
@ -34,11 +34,15 @@ function DocChild(content: AstDocumentChild): Elem {
|
||||||
}
|
}
|
||||||
|
|
||||||
function Heading(ast: AstAtxHeading): 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 {
|
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 {
|
function Text(ast: AstText): TextNode {
|
||||||
|
@ -92,13 +96,22 @@ function parseParagraph(ast: AstDocument, readStr: string): string | null {
|
||||||
};
|
};
|
||||||
ast.content.push(paragraph);
|
ast.content.push(paragraph);
|
||||||
|
|
||||||
const paragraphInlineContent = readStr.includes("\n")
|
let paragraphInlineContent = "";
|
||||||
? readStr.slice(0, readStr.indexOf("\n") + 1)
|
while (!RE_EMPTY_LINE.test(readStr)) {
|
||||||
: 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(
|
function parseInlineContent(
|
||||||
|
@ -107,11 +120,11 @@ function parseInlineContent(
|
||||||
): string | null {
|
): string | null {
|
||||||
if (!readStr.length) return null;
|
if (!readStr.length) return null;
|
||||||
|
|
||||||
const text: AstText = {
|
const parts = readStr.split("\n").filter(Boolean).map(
|
||||||
kind: AstKind.Text,
|
(textPart): AstText => ({ kind: AstKind.Text, content: textPart }),
|
||||||
content: readStr.trim(),
|
);
|
||||||
};
|
|
||||||
ast.content.push(text);
|
ast.content = parts;
|
||||||
|
|
||||||
return readStr;
|
return readStr;
|
||||||
}
|
}
|
||||||
|
@ -121,16 +134,19 @@ function parseInlineContent(
|
||||||
type AstDocument = BaseAstItem<AstKind.Document, AstDocumentChild[]>;
|
type AstDocument = BaseAstItem<AstKind.Document, AstDocumentChild[]>;
|
||||||
type AstDocumentChild = AstAtxHeading | AstParagraph;
|
type AstDocumentChild = AstAtxHeading | AstParagraph;
|
||||||
|
|
||||||
interface AstAtxHeading extends BaseAstItem<AstKind.AtxHeading, AstText[]> {
|
interface AstAtxHeading
|
||||||
|
extends BaseAstItem<AstKind.AtxHeading, AstInlineContent[]> {
|
||||||
level: HeadingLevel;
|
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 AstText = BaseAstItem<AstKind.Text, string>;
|
||||||
|
|
||||||
type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
|
|
||||||
|
|
||||||
interface BaseAstItem<K extends AstKind, Cont> {
|
interface BaseAstItem<K extends AstKind, Cont> {
|
||||||
kind: K;
|
kind: K;
|
||||||
content: Cont;
|
content: Cont;
|
||||||
|
|
Reference in a new issue