import { substituteParamsExtended } from "../../../../script.js"; import jsyaml from "./vendor/js-yaml.mjs"; function getTemplateRuntime() { return globalThis.window?.EjsTemplate || globalThis.EjsTemplate || null; } function safeStringify(value) { if (value == null) return ""; if (typeof value === "string") return value; try { return JSON.stringify(value, null, 2); } catch { return String(value); } } function deepGet(target, path) { if (!target || !path) return undefined; const parts = String(path || "") .split(".") .filter(Boolean); let current = target; for (const part of parts) { if (current == null) return undefined; current = current[part]; } return current; } export function getLatestMessageVarTable() { try { if (globalThis.window?.Mvu?.getMvuData) { return ( globalThis.window.Mvu.getMvuData({ type: "message", message_id: "latest", }) || {} ); } } catch { // ignore } try { const getVars = globalThis.window?.TavernHelper?.getVariables || globalThis.window?.Mvu?.getMvuData || globalThis.TavernHelper?.getVariables || globalThis.Mvu?.getMvuData; if (typeof getVars === "function") { return getVars({ type: "message", message_id: "latest" }) || {}; } } catch { // ignore } return {}; } export async function prepareStNativeEjsEnv() { try { const runtime = getTemplateRuntime(); const prepare = runtime?.prepareContext || runtime?.preparecontext || null; if (typeof prepare !== "function") { return null; } return (await prepare.call(runtime, {})) || null; } catch { return null; } } function substituteMacrosViaST(text) { try { if (typeof substituteParamsExtended === "function") { return substituteParamsExtended(text); } } catch { // ignore } return text; } function resolveGetMessageVariableMacros(text, messageVars) { return String(text || "").replace( /\{\{\s*get_message_variable::([^}]+)\s*}}/g, (_, rawPath) => { const path = String(rawPath || "").trim(); if (!path) return ""; return safeStringify(deepGet(messageVars, path)); }, ); } function resolveFormatMessageVariableMacros(text, messageVars) { return String(text || "").replace( /\{\{\s*format_message_variable::([^}]+)\s*}}/g, (_, rawPath) => { const path = String(rawPath || "").trim(); if (!path) return ""; const value = deepGet(messageVars, path); if (value == null) return ""; if (typeof value === "string") return value; try { return jsyaml.dump(value, { lineWidth: -1, noRefs: true, }); } catch { return safeStringify(value); } }, ); } export async function renderTemplateWithStSupport( text, { env = null, messageVars = null, evaluateEjs = true } = {}, ) { const originalText = String(text ?? ""); const runtime = getTemplateRuntime(); const effectiveEnv = env || null; const effectiveMessageVars = messageVars && typeof messageVars === "object" ? messageVars : getLatestMessageVarTable(); let output = originalText; let ejsEvaluated = false; let ejsError = null; if (evaluateEjs && originalText.includes("<%")) { try { const evalTemplate = runtime?.evalTemplate || runtime?.evaltemplate || null; if (runtime && effectiveEnv && typeof evalTemplate === "function") { output = await evalTemplate.call(runtime, output, effectiveEnv); ejsEvaluated = true; } } catch (error) { ejsError = error; } } const afterMacroSubstitute = substituteMacrosViaST(output); const afterMessageVariableResolve = resolveFormatMessageVariableMacros( resolveGetMessageVariableMacros(afterMacroSubstitute, effectiveMessageVars), effectiveMessageVars, ); return { text: afterMessageVariableResolve, stNativeRuntimeAvailable: Boolean(runtime), envPrepared: Boolean(effectiveEnv), ejsEvaluated, ejsError, macroApplied: afterMacroSubstitute !== output, messageVariableMacrosApplied: afterMessageVariableResolve !== afterMacroSubstitute, }; }