Archived
1
0
Fork 0

par(md): add loop...

... to allow parse many headers
This commit is contained in:
Dmitriy Pleshevskiy 2022-06-11 23:20:47 +03:00
parent 5bd148bf17
commit 328343ca76
Signed by: pleshevskiy
GPG key ID: 1B59187B161C0215
2 changed files with 74 additions and 25 deletions

View file

@ -4,6 +4,16 @@ import { MarkdownParser } from "./md.ts";
const ren = new HtmlStrRenderer(); const ren = new HtmlStrRenderer();
Deno.test({
name: "should skip new line character",
fn: () => {
const par = new MarkdownParser();
assertEquals(ren.render(par.parse("\n")), "");
assertEquals(ren.render(par.parse("\r\n")), "");
assertEquals(ren.render(par.parse("\n\r\n")), "");
},
});
Deno.test({ Deno.test({
name: "should parse empty ATX header", name: "should parse empty ATX header",
fn: () => { fn: () => {
@ -42,6 +52,8 @@ Deno.test({
assertEquals(ren.render(par.parse(" # hello")), "<h1>hello</h1>"); assertEquals(ren.render(par.parse(" # hello")), "<h1>hello</h1>");
assertEquals(ren.render(par.parse(" # hello")), "<h1>hello</h1>"); assertEquals(ren.render(par.parse(" # hello")), "<h1>hello</h1>");
assertEquals(ren.render(par.parse(" # hello")), "<h1>hello</h1>"); assertEquals(ren.render(par.parse(" # hello")), "<h1>hello</h1>");
assertEquals(ren.render(par.parse("\n # hello")), "<h1>hello</h1>");
assertEquals(ren.render(par.parse("\r\n # hello")), "<h1>hello</h1>");
}, },
}); });
@ -56,3 +68,21 @@ Deno.test({
assertEquals(ren.render(par.parse("###### hello #")), "<h6>hello</h6>"); assertEquals(ren.render(par.parse("###### hello #")), "<h6>hello</h6>");
}, },
}); });
Deno.test({
name: "should parse many headers with text",
fn: () => {
const par = new MarkdownParser();
const input = `\
# hello
## world
### this is
#### my world!`;
assertEquals(
ren.render(par.parse(input)),
"<h1>hello</h1><h2>world</h2><h3>this is</h3><h4>my world!</h4>",
);
},
});

View file

@ -2,6 +2,8 @@ import { AnyNode, Elem, Fragment, TextNode } from "../core/node.ts";
import { isNil } from "../core/utils.ts"; import { isNil } from "../core/utils.ts";
import { Parser } from "./types.ts"; import { Parser } from "./types.ts";
const RE_NEW_LINE = /^\r?\n/;
const RE_OPEN_ATX_HEADING = /^\s{0,3}(#{1,6})(\s|$)/; const RE_OPEN_ATX_HEADING = /^\s{0,3}(#{1,6})(\s|$)/;
const RE_CLOSE_ATX_HEADING = /(^|\s+)#*\s*$/; const RE_CLOSE_ATX_HEADING = /(^|\s+)#*\s*$/;
@ -11,6 +13,16 @@ export class MarkdownParser implements Parser {
let readStr = input; let readStr = input;
while (readStr.trim().length) {
{
// 1. clear new line character
const match = RE_NEW_LINE.exec(readStr);
if (!isNil(match)) {
readStr = readStr.slice(match[0].length);
}
}
// 2. try to find atx heading sequence
const match = RE_OPEN_ATX_HEADING.exec(readStr); const match = RE_OPEN_ATX_HEADING.exec(readStr);
if (!isNil(match)) { if (!isNil(match)) {
readStr = readStr.slice(match[0].length); readStr = readStr.slice(match[0].length);
@ -25,12 +37,16 @@ export class MarkdownParser implements Parser {
if (match[2].length > 0) { if (match[2].length > 0) {
const endMatch = RE_CLOSE_ATX_HEADING.exec(readStr); const endMatch = RE_CLOSE_ATX_HEADING.exec(readStr);
const headingContent = isNil(endMatch) const headingContent = !isNil(endMatch)
? readStr.split("\n", 1)[0] ? readStr.slice(0, endMatch.index)
: readStr.slice(0, endMatch.index); : readStr.includes("\n")
readStr = readStr.slice(headingContent.length); ? readStr.slice(0, readStr.indexOf("\n") + 1)
: readStr;
readStr = readStr.slice(
headingContent.length + (endMatch?.[0].length ?? 0),
);
if (headingContent.trim().length) { if (headingContent.length) {
const text: AstText = { const text: AstText = {
kind: AstKind.Text, kind: AstKind.Text,
content: headingContent.trim(), content: headingContent.trim(),
@ -38,6 +54,9 @@ export class MarkdownParser implements Parser {
atxHeading.content.push(text); atxHeading.content.push(text);
} }
} }
} else {
break;
}
} }
return new Fragment(ast.content.map(Heading)); return new Fragment(ast.content.map(Heading));