No longer index templates tagged as #template
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
import { handlebars, markdown, YAML } from "$sb/syscalls.ts";
|
||||
import type { PageMeta } from "$sb/types.ts";
|
||||
import { extractFrontmatter } from "$sb/lib/frontmatter.ts";
|
||||
import { TemplateObject } from "./types.ts";
|
||||
import { renderToText } from "$sb/lib/tree.ts";
|
||||
|
||||
/**
|
||||
* Strips the template from its frontmatter and renders it.
|
||||
* The assumption is that the frontmatter has already been parsed and should not appear in thhe rendered output.
|
||||
* @param templateText the template text
|
||||
* @param data data to be rendered by the template
|
||||
* @param globals a set of global variables
|
||||
* @returns
|
||||
*/
|
||||
export async function renderTemplate(
|
||||
templateText: string,
|
||||
pageMeta: PageMeta,
|
||||
data: any = {},
|
||||
): Promise<string> {
|
||||
const tree = await markdown.parseMarkdown(templateText);
|
||||
const frontmatter: Partial<TemplateObject> = await extractFrontmatter(tree, {
|
||||
removeFrontmatterSection: true,
|
||||
removeTags: ["template"],
|
||||
});
|
||||
templateText = renderToText(tree).trimStart();
|
||||
// console.log(`Trimmed template: |${templateText}|`);
|
||||
// If a 'frontmatter' key was specified in the frontmatter, use that as the frontmatter
|
||||
if (frontmatter.frontmatter) {
|
||||
if (typeof frontmatter.frontmatter === "string") {
|
||||
templateText = "---\n" + frontmatter.frontmatter + "---\n" + templateText;
|
||||
} else {
|
||||
templateText = "---\n" + (await YAML.stringify(frontmatter.frontmatter)) +
|
||||
"---\n" + templateText;
|
||||
}
|
||||
}
|
||||
return handlebars.renderTemplate(templateText, data, { page: pageMeta });
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips a template text from its frontmatter and #template tag
|
||||
*/
|
||||
export async function cleanTemplate(
|
||||
templateText: string,
|
||||
): Promise<string> {
|
||||
const tree = await markdown.parseMarkdown(templateText);
|
||||
await extractFrontmatter(tree, {
|
||||
removeFrontmatterSection: true,
|
||||
removeTags: ["template"],
|
||||
});
|
||||
return renderToText(tree).trimStart();
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import type { IndexTreeEvent } from "$sb/app_event.ts";
|
||||
import { system } from "$sb/syscalls.ts";
|
||||
|
||||
export async function indexTemplate({ name, tree }: IndexTreeEvent) {
|
||||
// Just delegate to the index plug
|
||||
await system.invokeFunction("index.indexPage", { name, tree });
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import type { PageMeta } from "$sb/types.ts";
|
||||
import { system } from "../../plug-api/syscalls.ts";
|
||||
|
||||
export function renderTemplate(
|
||||
templateText: string,
|
||||
pageMeta: PageMeta,
|
||||
data: any = {},
|
||||
): Promise<string> {
|
||||
return system.invokeFunction(
|
||||
"template.renderTemplate",
|
||||
templateText,
|
||||
pageMeta,
|
||||
data,
|
||||
);
|
||||
}
|
||||
|
||||
export function cleanTemplate(
|
||||
templateText: string,
|
||||
): Promise<string> {
|
||||
return system.invokeFunction(
|
||||
"template.cleanTemplate",
|
||||
templateText,
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,19 @@
|
||||
name: template
|
||||
functions:
|
||||
# API
|
||||
renderTemplate:
|
||||
path: api.ts:renderTemplate
|
||||
cleanTemplate:
|
||||
path: api.ts:cleanTemplate
|
||||
|
||||
insertTemplateText:
|
||||
path: template.ts:insertTemplateText
|
||||
|
||||
|
||||
indexTemplate:
|
||||
path: ./index.ts:indexTemplate
|
||||
events:
|
||||
- page:indexTemplate
|
||||
|
||||
templateSlashCommand:
|
||||
path: ./template.ts:templateSlashComplete
|
||||
@@ -10,8 +24,6 @@ functions:
|
||||
path: ./template.ts:insertSlashTemplate
|
||||
|
||||
# Template commands
|
||||
insertTemplateText:
|
||||
path: "./template.ts:insertTemplateText"
|
||||
applyLineReplace:
|
||||
path: ./template.ts:applyLineReplace
|
||||
insertFrontMatter:
|
||||
|
||||
+14
-20
@@ -4,20 +4,19 @@ import { renderToText } from "$sb/lib/tree.ts";
|
||||
import { niceDate, niceTime } from "$sb/lib/dates.ts";
|
||||
import { readSettings } from "$sb/lib/settings_page.ts";
|
||||
import { cleanPageRef } from "$sb/lib/resolve.ts";
|
||||
import { ObjectValue, PageMeta } from "$sb/types.ts";
|
||||
import { PageMeta } from "$sb/types.ts";
|
||||
import { CompleteEvent, SlashCompletion } from "$sb/app_event.ts";
|
||||
import { getObjectByRef, queryObjects } from "../index/plug_api.ts";
|
||||
|
||||
export type TemplateObject = ObjectValue<{
|
||||
trigger?: string; // has to start with # for now
|
||||
scope?: string;
|
||||
frontmatter?: Record<string, any> | string;
|
||||
}>;
|
||||
import { TemplateObject } from "./types.ts";
|
||||
import { renderTemplate } from "./api.ts";
|
||||
|
||||
export async function templateSlashComplete(
|
||||
completeEvent: CompleteEvent,
|
||||
): Promise<SlashCompletion[]> {
|
||||
const allTemplates = await queryObjects<TemplateObject>("template", {});
|
||||
const allTemplates = await queryObjects<TemplateObject>("template", {
|
||||
// Only return templates that have a trigger
|
||||
filter: ["!=", ["attr", "trigger"], ["null"]],
|
||||
});
|
||||
return allTemplates.map((template) => ({
|
||||
label: template.trigger!,
|
||||
detail: "template",
|
||||
@@ -31,14 +30,7 @@ export async function insertSlashTemplate(slashCompletion: SlashCompletion) {
|
||||
const pageObject = await loadPageObject(slashCompletion.pageName);
|
||||
|
||||
let templateText = await space.readPage(slashCompletion.templatePage);
|
||||
templateText = await replaceTemplateVars(templateText, pageObject);
|
||||
const parseTree = await markdown.parseMarkdown(templateText);
|
||||
const frontmatter = await extractFrontmatter(parseTree, [], true);
|
||||
templateText = renderToText(parseTree).trim();
|
||||
if (frontmatter.frontmatter) {
|
||||
templateText = "---\n" + (await YAML.stringify(frontmatter.frontmatter)) +
|
||||
"---\n" + templateText;
|
||||
}
|
||||
templateText = await renderTemplate(templateText, pageObject);
|
||||
|
||||
const cursorPos = await editor.getCursor();
|
||||
const carretPos = templateText.indexOf("|^|");
|
||||
@@ -76,10 +68,12 @@ export async function instantiateTemplateCommand() {
|
||||
);
|
||||
|
||||
const parseTree = await markdown.parseMarkdown(text);
|
||||
const additionalPageMeta = await extractFrontmatter(parseTree, [
|
||||
"$name",
|
||||
"$disableDirectives",
|
||||
]);
|
||||
const additionalPageMeta = await extractFrontmatter(parseTree, {
|
||||
removeKeys: [
|
||||
"$name",
|
||||
"$disableDirectives",
|
||||
],
|
||||
});
|
||||
|
||||
const tempPageMeta: PageMeta = {
|
||||
tags: ["page"],
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import { ObjectValue } from "$sb/types.ts";
|
||||
|
||||
export type TemplateFrontmatter = {
|
||||
trigger?: string; // slash command name
|
||||
scope?: string;
|
||||
// Frontmatter can be encoded as an object (in which case we'll serialize it) or as a string
|
||||
frontmatter?: Record<string, any> | string;
|
||||
};
|
||||
|
||||
export type TemplateObject = ObjectValue<TemplateFrontmatter>;
|
||||
@@ -0,0 +1,76 @@
|
||||
import { assertEquals } from "../../test_deps.ts";
|
||||
import { isTemplate } from "./util.ts";
|
||||
|
||||
Deno.test("Test template extraction", () => {
|
||||
assertEquals(
|
||||
isTemplate(`---
|
||||
name: bla
|
||||
tags: template
|
||||
---
|
||||
|
||||
Sup`),
|
||||
true,
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
isTemplate(`---
|
||||
tags: template, something else
|
||||
---
|
||||
`),
|
||||
true,
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
isTemplate(`---
|
||||
tags: something else, template
|
||||
---
|
||||
`),
|
||||
true,
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
isTemplate(`---
|
||||
tags:
|
||||
- bla
|
||||
- template
|
||||
---
|
||||
`),
|
||||
true,
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
isTemplate(`#template`),
|
||||
true,
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
isTemplate(` #template This is a template`),
|
||||
true,
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
isTemplate(`---
|
||||
tags:
|
||||
- bla
|
||||
somethingElse:
|
||||
- template
|
||||
---
|
||||
`),
|
||||
false,
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
isTemplate(`---
|
||||
name: bla
|
||||
tags: aefe
|
||||
---
|
||||
|
||||
Sup`),
|
||||
false,
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
isTemplate(`Sup`),
|
||||
false,
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,47 @@
|
||||
const frontMatterRegex = /^---\n(([^\n]|\n)*?)---\n/;
|
||||
const yamlKvRegex = /^\s*(\w+):\s*(.*)/;
|
||||
const yamlListItemRegex = /^\s*-\s+(.+)/;
|
||||
|
||||
/**
|
||||
* Quick and dirty way to check if a page is a template or not
|
||||
* @param pageText
|
||||
* @returns
|
||||
*/
|
||||
export function isTemplate(pageText: string): boolean {
|
||||
const frontmatter = frontMatterRegex.exec(pageText);
|
||||
// Poor man's YAML frontmatter parsing
|
||||
if (frontmatter) {
|
||||
pageText = pageText.slice(frontmatter[0].length);
|
||||
const frontmatterText = frontmatter[1];
|
||||
const lines = frontmatterText.split("\n");
|
||||
let inTagsSection = false;
|
||||
for (const line of lines) {
|
||||
const yamlKv = yamlKvRegex.exec(line);
|
||||
if (yamlKv) {
|
||||
const [key, value] = yamlKv.slice(1);
|
||||
// Looking for a 'tags' key
|
||||
if (key === "tags") {
|
||||
inTagsSection = true;
|
||||
// 'template' there? Yay!
|
||||
if (value.split(/,\s*/).includes("template")) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
inTagsSection = false;
|
||||
}
|
||||
}
|
||||
const yamlListem = yamlListItemRegex.exec(line);
|
||||
if (yamlListem && inTagsSection) {
|
||||
// List item is 'template'? Yay!
|
||||
if (yamlListem[1] === "template") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Or if the page text starts with a #template tag
|
||||
if (/^\s*#template(\W|$)/.test(pageText)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
Reference in New Issue
Block a user