Archived
1
0
Fork 0

commit experiments

This commit is contained in:
Dmitriy Pleshevskiy 2022-06-21 13:15:28 +03:00
parent 2d1fbf4be2
commit e89368d861
Signed by: pleshevskiy
GPG key ID: 1B59187B161C0215
2 changed files with 101 additions and 20 deletions

View file

@ -8,6 +8,7 @@ const ren = new HtmlStrRenderer();
Deno.test({ Deno.test({
name: "should skip empty line", name: "should skip empty line",
only: true,
fn: () => { fn: () => {
const par = new MarkdownParser(); const par = new MarkdownParser();
assertEquals(ren.render(par.parse("\n")), ""); assertEquals(ren.render(par.parse("\n")), "");
@ -21,15 +22,30 @@ Deno.test({
Deno.test({ Deno.test({
name: "should parse empty ATX header", name: "should parse empty ATX header",
only: true,
fn: () => { fn: () => {
const par = new MarkdownParser(); const par = new MarkdownParser();
const res = par.parse("#"); assertEquals(ren.render(par.parse("#")), "<h1></h1>");
assertEquals(ren.render(res), "<h1></h1>"); assertEquals(ren.render(par.parse("##")), "<h2></h2>");
},
});
Deno.test({
name: "should parse ATX header if line contains additional spaces",
only: true,
fn: () => {
const par = new MarkdownParser();
assertEquals(ren.render(par.parse(" #")), "<h1></h1>");
assertEquals(ren.render(par.parse(" #")), "<h1></h1>");
assertEquals(ren.render(par.parse(" ##")), "<h2></h2>");
assertEquals(ren.render(par.parse(" #")), "<h1></h1>");
assertEquals(ren.render(par.parse(" ##")), "<h2></h2>");
}, },
}); });
Deno.test({ Deno.test({
name: "should parse ATX header with text", name: "should parse ATX header with text",
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>");
@ -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")), "<h1>hello</h1>");
assertEquals(ren.render(par.parse(" # hello")), "<h1>hello</h1>");
assertEquals(ren.render(par.parse(" # hello")), "<h1>hello</h1>");
},
});
Deno.test({ Deno.test({
name: "should parse ATX header with closing sequence", name: "should parse ATX header with closing sequence",
fn: () => { fn: () => {

View file

@ -23,6 +23,8 @@ import { Parser } from "./types.ts";
const RE_EMPTY_LINE = /^[ ]*\r?\n/; 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_OPEN_ATX_HEADING = /^[ ]{0,3}(#{1,6})([ ]|$)/;
const RE_CLOSE_ATX_HEADING = /(^|[ ]+)#*[ ]*$/; const RE_CLOSE_ATX_HEADING = /(^|[ ]+)#*[ ]*$/;
@ -35,20 +37,93 @@ export class MarkdownParser implements Parser {
parse(input: string): AnyNode { parse(input: string): AnyNode {
const astDoc: AstDocument = { kind: AstKind.Document, content: [] }; const astDoc: AstDocument = { kind: AstKind.Document, content: [] };
let readStr = input; const segments = splitLines(input);
while (readStr.length) {
const newReadStr = skipEmptyLine(readStr) ?? console.log({ segments });
parseAtxHeading(astDoc, readStr) ??
parseList(astDoc, readStr) ?? const res = parseHeaderFromSegments(segments);
parseParagraph(astDoc, readStr); if (res != null) {
if (isNil(newReadStr)) break; astDoc.content.push(res.ast);
readStr = newReadStr;
} }
// 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)); return new Fragment(astDoc.content.map(DocChild));
} }
} }
function parseHeaderFromSegments(
lines: Lines,
): ParsedRes<AstAtxHeading> | 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<AstInlineContent[]> | 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<T> {
ast: T;
restLines: Lines;
}
function splitLines(input: string): Lines {
return input.split("\n");
}
type Lines = string[];
// ---- OLD
function List(ast: AstList): Elem { function List(ast: AstList): Elem {
// switch (ast.kind) // switch (ast.kind)
return BulletList(ast); return BulletList(ast);