/* eslint-disable @typescript-eslint/no-explicit-any */ import mustache from 'mustache'; import { PluginContext } from '../types/PluginContext.js'; import { getArray } from './GetArray.js'; // disable html escaping mustache.escape = (v) => v; export function Render ( templateString: string, pluginContext: PluginContext, replacements: Record = {}): string { const repl = { plugin: pluginContext.plugin, pluginConfig: pluginContext.config.pluginConfig, ...replacements }; return mustache.render(templateString, repl) || ''; } export function referenceData ( ref: string, pluginContext: PluginContext, replacements: Record = {}): string { if (typeof ref !== 'string') { throw new Error('ref must be string'); } if (ref.startsWith('@')) { const re = new RegExp(/^@(?\w+)\[(?[^\[\]]+)\]\.(?.*)$/u, 'u'); const m = re.exec(ref); if (Array.isArray(m) && m.length === 4) { const [_, where, index, path] = m; if (!Object.prototype.hasOwnProperty.call(replacements, where)) { throw new Error(`Map indexing construct accesses non-existent object: "${where}"`); } if (replacements[where].constructor.name !== 'Map') { throw new Error(`Map indexing construct accesses non-map object: "${where}"`); } const indexValue = referenceData(index, pluginContext, replacements); const item = replacements[where].get(indexValue); const result = getArray(item, path); return result; } else { const path = ref.substring(1); return path ? getArray(replacements['object'], path) : replacements['object']; } } const tpl = ref.startsWith('\\@') ? ref.substring(1) : ref; return Render(tpl, pluginContext, replacements) ?? ''; } export function RenderObject( obj: any, pluginContext: PluginContext, replacements: Record = {}): Record | string { switch (typeof obj) { case 'string': { const re = /^\{{4}(?\w+)(?:\.(?\w+))?\}{4}$/u; const m = re.exec(obj); if (Array.isArray(m) && m.length >= 2) { const [_, where, fld] = m; if (!Object.prototype.hasOwnProperty.call(replacements, where)) { throw new Error(`Quad mustache construct accesses non-existent object: "${where}"`); } const replacementObj = replacements[where]; if (fld) { return replacementObj[fld]; } else { return replacementObj; } } else { const result = referenceData(obj, pluginContext, replacements); return result; } } case 'object': { if (obj === null) { return obj; } if (Array.isArray(obj)) { const result = obj.map( (el) => RenderObject(el as any, pluginContext, replacements) ); return result; } else { const result = Object.entries(obj).reduce( (acc, [key, value]) => { acc[key] = RenderObject(value as any, pluginContext, replacements); return acc; }, {} as Record ); return result; } } default: { return obj; } } }