Archived
1
0
Fork 0
This repository has been archived on 2024-07-25. You can view files and clone it, but cannot push or open issues or pull requests.
paren/par/md.ts
Dmitriy Pleshevskiy 5bd148bf17
par(md): add closing sequence
refac: rename heading to atx heading
2022-06-11 22:41:15 +03:00

77 lines
1.9 KiB
TypeScript

import { AnyNode, Elem, Fragment, TextNode } from "../core/node.ts";
import { isNil } from "../core/utils.ts";
import { Parser } from "./types.ts";
const RE_OPEN_ATX_HEADING = /^\s{0,3}(#{1,6})(\s|$)/;
const RE_CLOSE_ATX_HEADING = /(^|\s+)#*\s*$/;
export class MarkdownParser implements Parser {
parse(input: string): AnyNode {
const ast: AstDocument = { kind: AstKind.Document, content: [] };
let readStr = input;
const match = RE_OPEN_ATX_HEADING.exec(readStr);
if (!isNil(match)) {
readStr = readStr.slice(match[0].length);
const atxHeading: AstAtxHeading = {
kind: AstKind.AtxHeading,
level: match[1].length as HeadingLevel,
content: [],
};
ast.content.push(atxHeading);
if (match[2].length > 0) {
const endMatch = RE_CLOSE_ATX_HEADING.exec(readStr);
const headingContent = isNil(endMatch)
? readStr.split("\n", 1)[0]
: readStr.slice(0, endMatch.index);
readStr = readStr.slice(headingContent.length);
if (headingContent.trim().length) {
const text: AstText = {
kind: AstKind.Text,
content: headingContent.trim(),
};
atxHeading.content.push(text);
}
}
}
return new Fragment(ast.content.map(Heading));
}
}
function Heading(ast: AstAtxHeading): Elem {
return new Elem(`h${ast.level}`, {}, ast.content.map(Text));
}
function Text(ast: AstText): TextNode {
return new TextNode(ast.content);
}
// AST
type AstDocument = BaseAstItem<AstKind.Document, AstDocumentChild[]>;
type AstDocumentChild = AstAtxHeading;
interface AstAtxHeading extends BaseAstItem<AstKind.AtxHeading, AstText[]> {
level: HeadingLevel;
}
type AstText = BaseAstItem<AstKind.Text, string>;
type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
interface BaseAstItem<K extends AstKind, Cont> {
kind: K;
content: Cont;
}
enum AstKind {
Document,
AtxHeading,
Text,
}