Fixes #92: implements frontmatter syntax
This commit is contained in:
@@ -27,6 +27,7 @@ export type {
|
||||
BlockContext,
|
||||
LeafBlock,
|
||||
LeafBlockParser,
|
||||
Line,
|
||||
MarkdownConfig,
|
||||
MarkdownExtension,
|
||||
} from "@lezer/markdown";
|
||||
|
||||
@@ -2,6 +2,7 @@ import { ParseTree } from "$sb/lib/tree.ts";
|
||||
|
||||
import type { SyntaxNode } from "./deps.ts";
|
||||
import type { Language } from "./deps.ts";
|
||||
|
||||
export function lezerToParseTree(
|
||||
text: string,
|
||||
n: SyntaxNode,
|
||||
@@ -24,10 +25,10 @@ export function lezerToParseTree(
|
||||
},
|
||||
];
|
||||
} else {
|
||||
let newChildren: ParseTree[] = [];
|
||||
const newChildren: ParseTree[] = [];
|
||||
let index = n.from;
|
||||
for (let child of children) {
|
||||
let s = text.substring(index, child.from);
|
||||
for (const child of children) {
|
||||
const s = text.substring(index, child.from);
|
||||
if (s) {
|
||||
newChildren.push({
|
||||
from: index + offset,
|
||||
@@ -38,14 +39,14 @@ export function lezerToParseTree(
|
||||
newChildren.push(child);
|
||||
index = child.to!;
|
||||
}
|
||||
let s = text.substring(index, n.to);
|
||||
const s = text.substring(index, n.to);
|
||||
if (s) {
|
||||
newChildren.push({ from: index + offset, to: n.to + offset, text: s });
|
||||
}
|
||||
children = newChildren;
|
||||
}
|
||||
|
||||
let result: ParseTree = {
|
||||
const result: ParseTree = {
|
||||
type: n.name,
|
||||
from: n.from + offset,
|
||||
to: n.to + offset,
|
||||
@@ -60,7 +61,7 @@ export function lezerToParseTree(
|
||||
}
|
||||
|
||||
export function parse(language: Language, text: string): ParseTree {
|
||||
let tree = lezerToParseTree(text, language.parser.parse(text).topNode);
|
||||
const tree = lezerToParseTree(text, language.parser.parse(text).topNode);
|
||||
// replaceNodesMatching(tree, (n): MarkdownTree | undefined | null => {
|
||||
// if (n.type === "FencedCode") {
|
||||
// let infoN = findNodeMatching(n, (n) => n.type === "CodeInfo");
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { parse } from "./parse_tree.ts";
|
||||
import buildMarkdown from "./parser.ts";
|
||||
import { findNodeOfType, renderToText } from "../plug-api/lib/tree.ts";
|
||||
import { assertEquals, assertNotEquals } from "../test_deps.ts";
|
||||
|
||||
const sample1 = `---
|
||||
type: page
|
||||
tags:
|
||||
- hello
|
||||
- world
|
||||
|
||||
---
|
||||
# This is a doc
|
||||
|
||||
Supper`;
|
||||
|
||||
const sampleInvalid1 = `---
|
||||
name: Zef
|
||||
# This is a doc
|
||||
|
||||
Supper`;
|
||||
|
||||
Deno.test("Test parser", () => {
|
||||
const lang = buildMarkdown([]);
|
||||
let tree = parse(
|
||||
lang,
|
||||
sample1,
|
||||
);
|
||||
// Check if rendering back to text works
|
||||
assertEquals(renderToText(tree), sample1);
|
||||
// console.log("tree", JSON.stringify(tree, null, 2));
|
||||
let node = findNodeOfType(tree, "FrontMatter");
|
||||
assertNotEquals(node, undefined);
|
||||
tree = parse(lang, sampleInvalid1);
|
||||
node = findNodeOfType(tree, "FrontMatter");
|
||||
// console.log("Invalid node", node);
|
||||
assertEquals(node, undefined);
|
||||
});
|
||||
+69
-23
@@ -1,17 +1,17 @@
|
||||
import {
|
||||
BlockContext,
|
||||
Language,
|
||||
LanguageDescription,
|
||||
LanguageSupport,
|
||||
LeafBlock,
|
||||
LeafBlockParser,
|
||||
Line,
|
||||
markdown,
|
||||
MarkdownConfig,
|
||||
parseCode,
|
||||
StreamLanguage,
|
||||
styleTags,
|
||||
Table,
|
||||
tags as t,
|
||||
TaskList,
|
||||
yamlLanguage,
|
||||
} from "./deps.ts";
|
||||
import * as ct from "./customtags.ts";
|
||||
import {
|
||||
@@ -92,7 +92,7 @@ export const Comment: MarkdownConfig = {
|
||||
parseBlock: [
|
||||
{
|
||||
name: "Comment",
|
||||
leaf(cx, leaf) {
|
||||
leaf(_cx, leaf) {
|
||||
return /^%%\s/.test(leaf.content) ? new CommentParser() : null;
|
||||
},
|
||||
after: "SetextHeading",
|
||||
@@ -100,34 +100,80 @@ export const Comment: MarkdownConfig = {
|
||||
],
|
||||
};
|
||||
|
||||
// FrontMatter parser
|
||||
|
||||
const lang = StreamLanguage.define(yamlLanguage);
|
||||
|
||||
export const FrontMatter: MarkdownConfig = {
|
||||
defineNodes: [
|
||||
{ name: "FrontMatter", block: true },
|
||||
{ name: "FrontMatterMarker" },
|
||||
{ name: "FrontMatterCode" },
|
||||
],
|
||||
parseBlock: [{
|
||||
name: "FrontMatter",
|
||||
parse: (cx, line: Line) => {
|
||||
if (cx.parsedPos !== 0) {
|
||||
return false;
|
||||
}
|
||||
if (line.text !== "---") {
|
||||
return false;
|
||||
}
|
||||
const frontStart = cx.parsedPos;
|
||||
const elts = [
|
||||
cx.elt(
|
||||
"FrontMatterMarker",
|
||||
cx.parsedPos,
|
||||
cx.parsedPos + line.text.length + 1,
|
||||
),
|
||||
];
|
||||
cx.nextLine();
|
||||
const startPos = cx.parsedPos;
|
||||
let endPos = startPos;
|
||||
let text = "";
|
||||
let lastPos = cx.parsedPos;
|
||||
do {
|
||||
text += line.text + "\n";
|
||||
endPos += line.text.length + 1;
|
||||
cx.nextLine();
|
||||
if (cx.parsedPos === lastPos) {
|
||||
// End of file, no progress made, there may be a better way to do this but :shrug:
|
||||
return false;
|
||||
}
|
||||
lastPos = cx.parsedPos;
|
||||
} while (line.text !== "---");
|
||||
const yamlTree = lang.parser.parse(text);
|
||||
|
||||
elts.push(
|
||||
cx.elt("FrontMatterCode", startPos, endPos, [
|
||||
cx.elt(yamlTree, startPos),
|
||||
]),
|
||||
);
|
||||
endPos = cx.parsedPos + line.text.length;
|
||||
elts.push(cx.elt(
|
||||
"FrontMatterMarker",
|
||||
cx.parsedPos,
|
||||
cx.parsedPos + line.text.length,
|
||||
));
|
||||
cx.nextLine();
|
||||
cx.addElement(cx.elt("FrontMatter", frontStart, endPos, elts));
|
||||
return true;
|
||||
},
|
||||
before: "HorizontalRule",
|
||||
}],
|
||||
};
|
||||
|
||||
export default function buildMarkdown(mdExtensions: MDExt[]): Language {
|
||||
return markdown({
|
||||
extensions: [
|
||||
WikiLink,
|
||||
FrontMatter,
|
||||
TaskList,
|
||||
Comment,
|
||||
Strikethrough,
|
||||
Table,
|
||||
...mdExtensions.map(mdExtensionSyntaxConfig),
|
||||
// parseCode({
|
||||
// codeParser: getCodeParser([
|
||||
// LanguageDescription.of({
|
||||
// name: "yaml",
|
||||
// alias: ["meta", "data"],
|
||||
// support: new LanguageSupport(StreamLanguage.define(yaml)),
|
||||
// }),
|
||||
// LanguageDescription.of({
|
||||
// name: "javascript",
|
||||
// alias: ["js"],
|
||||
// support: new LanguageSupport(javascriptLanguage),
|
||||
// }),
|
||||
// LanguageDescription.of({
|
||||
// name: "typescript",
|
||||
// alias: ["ts"],
|
||||
// support: new LanguageSupport(typescriptLanguage),
|
||||
// }),
|
||||
// ]),
|
||||
// }),
|
||||
|
||||
{
|
||||
props: [
|
||||
styleTags({
|
||||
|
||||
Reference in New Issue
Block a user