silverbullet/web/syscalls/decoration.ts

75 lines
2.4 KiB
TypeScript

import { PageDecoration, PageMeta } from "$sb/types.ts";
import { SysCallMapping } from "$lib/plugos/system.ts";
import { Client } from "../client.ts";
import { parseTreeToAST } from "$sb/lib/tree.ts";
import { lezerToParseTree } from "$common/markdown_parser/parse_tree.ts";
import { expressionLanguage } from "$common/template/template_parser.ts";
import { expressionToKvQueryExpression } from "$sb/lib/parse-query.ts";
import { evalQueryExpression } from "$sb/lib/query_expression.ts";
import { builtinFunctions } from "$lib/builtin_query_functions.ts";
export function decorationSyscalls(
client: Client,
): SysCallMapping {
return {
"decoration.applyDecorationsToPages": (
_ctx,
pages: PageMeta[],
): PageMeta[] => {
if (client.settings.pageDecorations) {
for (const pageMeta of pages) {
decoratePageMeta(pageMeta, client.settings.pageDecorations);
}
}
return pages;
},
};
}
/**
* Decorates (= attaches a pageDecoration field) to the pageMeta object when a matching decorator is found
*/
export function decoratePageMeta(
pageMeta: PageMeta,
decorations: PageDecoration[],
) {
if (!pageMeta) {
return;
}
for (const decoration of decorations) {
if (!decoration.where) {
continue;
}
// whereParsed is effectively a cached version of the parsed where expression
// Let's check if it's populated
if (!decoration.whereParsed) {
// If not, populate it
try {
const ast = parseTreeToAST(lezerToParseTree(
decoration.where,
expressionLanguage.parser.parse(decoration.where).topNode,
));
decoration.whereParsed = expressionToKvQueryExpression(
ast[1],
);
} catch (e: any) {
console.error(
"Failed to parse 'where' expression in decoration:",
e,
);
continue;
}
}
if (
evalQueryExpression(
decoration.whereParsed,
pageMeta,
{},
builtinFunctions,
)
) {
pageMeta.pageDecoration = decoration;
}
}
}