1
0
silverbullet/plugs/directive/template_directive.ts

102 lines
2.8 KiB
TypeScript
Raw Normal View History

import { queryRegex } from "$sb/lib/query.ts";
2023-08-28 15:12:15 +00:00
import { ParseTree, renderToText } from "$sb/lib/tree.ts";
import { handlebars, markdown, space } from "$sb/syscalls.ts";
2023-08-28 15:12:15 +00:00
import { replaceTemplateVars } from "../template/template.ts";
2022-11-24 11:04:00 +00:00
import { extractFrontmatter } from "$sb/lib/frontmatter.ts";
import { directiveRegex } from "./directives.ts";
import { updateDirectives } from "./command.ts";
2023-07-30 09:30:01 +00:00
import { resolvePath, rewritePageRefs } from "$sb/lib/resolve.ts";
import { PageMeta } from "$sb/types.ts";
const templateRegex = /\[\[([^\]]+)\]\]\s*(.*)\s*/;
export async function templateDirectiveRenderer(
directive: string,
pageMeta: PageMeta,
arg: string | ParseTree,
): Promise<string> {
if (typeof arg !== "string") {
throw new Error("Template directives must be a string");
}
const match = arg.match(templateRegex);
if (!match) {
throw new Error(`Invalid template directive: ${arg}`);
}
2023-07-30 06:56:44 +00:00
let templatePath = match[1];
const args = match[2];
let parsedArgs = {};
if (args) {
try {
parsedArgs = JSON.parse(await replaceTemplateVars(args, pageMeta));
} catch {
throw new Error(
`Failed to parse template instantiation arg: ${
replaceTemplateVars(args, pageMeta)
}`,
);
}
}
let templateText = "";
2023-07-30 06:56:44 +00:00
if (
templatePath.startsWith("http://") || templatePath.startsWith("https://")
) {
try {
2023-07-30 06:56:44 +00:00
const req = await fetch(templatePath);
templateText = await req.text();
} catch (e: any) {
templateText = `ERROR: ${e.message}`;
}
} else {
2023-07-30 06:56:44 +00:00
templatePath = resolvePath(pageMeta.name, templatePath);
templateText = await space.readPage(templatePath);
}
const tree = await markdown.parseMarkdown(templateText);
await extractFrontmatter(tree, [], true); // Remove entire frontmatter section, if any
2023-07-30 06:56:44 +00:00
// Resolve paths in the template
rewritePageRefs(tree, templatePath);
let newBody = renderToText(tree);
2023-07-30 06:56:44 +00:00
// console.log("Rewritten template:", newBody);
// if it's a template injection (not a literal "include")
if (directive === "use") {
newBody = await handlebars.renderTemplate(newBody, parsedArgs, {
page: pageMeta,
});
// Recursively render directives
const tree = await markdown.parseMarkdown(newBody);
newBody = await updateDirectives(pageMeta, tree, newBody);
}
return newBody.trim();
}
export function cleanTemplateInstantiations(text: string) {
return text.replaceAll(directiveRegex, (
_fullMatch,
startInst,
type,
_args,
body,
endInst,
): string => {
if (type === "use") {
body = body.replaceAll(
queryRegex,
(
_fullMatch: string,
_startQuery: string,
_query: string,
body: string,
) => {
return body.trim();
},
);
}
return `${startInst}${body}${endInst}`;
});
}