diff --git a/par/md.test.ts b/par/md.test.ts
index 0bc6c39..8852521 100644
--- a/par/md.test.ts
+++ b/par/md.test.ts
@@ -8,6 +8,7 @@ const ren = new HtmlStrRenderer();
Deno.test({
name: "should skip empty line",
+ only: true,
fn: () => {
const par = new MarkdownParser();
assertEquals(ren.render(par.parse("\n")), "");
@@ -21,15 +22,30 @@ Deno.test({
Deno.test({
name: "should parse empty ATX header",
+ only: true,
fn: () => {
const par = new MarkdownParser();
- const res = par.parse("#");
- assertEquals(ren.render(res), "
");
+ assertEquals(ren.render(par.parse("#")), "");
+ assertEquals(ren.render(par.parse("##")), "");
+ },
+});
+
+Deno.test({
+ name: "should parse ATX header if line contains additional spaces",
+ only: true,
+ fn: () => {
+ const par = new MarkdownParser();
+ assertEquals(ren.render(par.parse(" #")), "");
+ assertEquals(ren.render(par.parse(" #")), "");
+ assertEquals(ren.render(par.parse(" ##")), "");
+ assertEquals(ren.render(par.parse(" #")), "");
+ assertEquals(ren.render(par.parse(" ##")), "");
},
});
Deno.test({
name: "should parse ATX header with text",
+ only: true,
fn: () => {
const par = new MarkdownParser();
assertEquals(ren.render(par.parse("# hello")), "hello
");
@@ -50,16 +66,6 @@ Deno.test({
},
});
-Deno.test({
- name: "should parse ATX header if line contains additional spaces",
- fn: () => {
- const par = new MarkdownParser();
- assertEquals(ren.render(par.parse(" # hello")), "hello
");
- assertEquals(ren.render(par.parse(" # hello")), "hello
");
- assertEquals(ren.render(par.parse(" # hello")), "hello
");
- },
-});
-
Deno.test({
name: "should parse ATX header with closing sequence",
fn: () => {
diff --git a/par/md.ts b/par/md.ts
index 9eadfc8..e30b447 100644
--- a/par/md.ts
+++ b/par/md.ts
@@ -23,6 +23,8 @@ import { Parser } from "./types.ts";
const RE_EMPTY_LINE = /^[ ]*\r?\n/;
+const RE_ATX_HEADING = /^[ ]{0,3}(#{1,6})(?:$|([ ].+)(?:[ ]?#*[ ]*)?$)/;
+
const RE_OPEN_ATX_HEADING = /^[ ]{0,3}(#{1,6})([ ]|$)/;
const RE_CLOSE_ATX_HEADING = /(^|[ ]+)#*[ ]*$/;
@@ -35,20 +37,93 @@ export class MarkdownParser implements Parser {
parse(input: string): AnyNode {
const astDoc: AstDocument = { kind: AstKind.Document, content: [] };
- let readStr = input;
- while (readStr.length) {
- const newReadStr = skipEmptyLine(readStr) ??
- parseAtxHeading(astDoc, readStr) ??
- parseList(astDoc, readStr) ??
- parseParagraph(astDoc, readStr);
- if (isNil(newReadStr)) break;
- readStr = newReadStr;
+ const segments = splitLines(input);
+
+ console.log({ segments });
+
+ const res = parseHeaderFromSegments(segments);
+ if (res != null) {
+ astDoc.content.push(res.ast);
}
+ // let readStr = input;
+ // while (readStr.length) {
+ // const newReadStr = skipEmptyLine(readStr) ??
+ // parseAtxHeading(astDoc, readStr) ??
+ // parseList(astDoc, readStr) ??
+ // parseParagraph(astDoc, readStr);
+ // if (isNil(newReadStr)) break;
+ // readStr = newReadStr;
+ // }
+
return new Fragment(astDoc.content.map(DocChild));
}
}
+function parseHeaderFromSegments(
+ lines: Lines,
+): ParsedRes | null {
+ const headingMatch = RE_ATX_HEADING.exec(lines[0]);
+ if (headingMatch == null) return null;
+
+ const inlineContent = parseInlineContentFromSegments([headingMatch[2]]);
+
+ const ast: AstAtxHeading = {
+ kind: AstKind.AtxHeading,
+ content: [],
+ level: headingMatch[1].length as HeadingLevel,
+ };
+
+ return {
+ ast,
+ restLines: lines.slice(1),
+ };
+}
+
+function parseInlineContentFromSegments(
+ lines: Lines,
+): ParsedRes | null {
+ if (!lines.length) return null;
+
+ const linkMatch = RE_LINK.exec(readStr);
+ if (!isNil(linkMatch)) {
+ const astLink: AstLink = {
+ kind: AstKind.Link,
+ destination: encodeURI(linkMatch[3] ?? linkMatch[2]),
+ title: linkMatch[5],
+ content: [],
+ };
+
+ // 1. parse before link
+ parseText(ast, readStr.slice(0, linkMatch.index));
+
+ // 2. create link and parse inner content for link
+ ast.content.push(astLink);
+ parseText(astLink, linkMatch[1]);
+
+ // 3. parse rest text
+ return parseInlineContent(
+ ast,
+ readStr.slice(linkMatch.index + linkMatch[0].length),
+ );
+ } else {
+ return parseText(ast, readStr);
+ }
+}
+
+interface ParsedRes {
+ ast: T;
+ restLines: Lines;
+}
+
+function splitLines(input: string): Lines {
+ return input.split("\n");
+}
+
+type Lines = string[];
+
+// ---- OLD
+
function List(ast: AstList): Elem {
// switch (ast.kind)
return BulletList(ast);