// This is some shocking stuff. My profession would kill me for this. import { YAML } from "$sb/syscalls.ts"; import { ParseTree } from "$sb/lib/tree.ts"; import { jsonToMDTable, renderTemplate } from "./util.ts"; import type { PageMeta } from "../../web/types.ts"; import { replaceTemplateVars } from "../template/template.ts"; // Enables plugName.functionName(arg1, arg2) syntax in JS expressions function translateJs(js: string): string { return js.replaceAll( /(\w+\.\w+)\s*\(/g, 'await invokeFunction("$1", ', ); } // Syntaxes to support: // - random JS expression // - random JS expression render [[some/template]] const expressionRegex = /(.+?)(\s+render\s+\[\[([^\]]+)\]\])?$/; // This is rather scary and fragile stuff, but it works. export async function evalDirectiveRenderer( _directive: string, pageMeta: PageMeta, expression: string | ParseTree, ): Promise { if (typeof expression !== "string") { throw new Error("Expected a string"); } // console.log("Got JS expression", expression); const match = expressionRegex.exec(expression); if (!match) { throw new Error(`Invalid eval directive: ${expression}`); } let template = ""; if (match[3]) { // This is the template reference expression = match[1]; template = match[3]; } try { // Why the weird "eval" call? https://esbuild.github.io/content-types/#direct-eval const result = await (0, eval)( `(async () => { function invokeFunction(name, ...args) { return syscall("system.invokeFunction", name, ...args); } return ${replaceTemplateVars(translateJs(expression), pageMeta)}; })()`, ); if (template) { return await renderTemplate(pageMeta, template, result); } if (typeof result === "string") { return result; } else if (typeof result === "number") { return "" + result; } else if (Array.isArray(result)) { return jsonToMDTable(result); } return await YAML.stringify(result); } catch (e: any) { return `**ERROR:** ${e.message}`; } }