UNPKG

@miyagi/core

Version:

miyagi is a component development tool for JavaScript template engines.

247 lines (206 loc) 4.53 kB
import fs from "fs"; import path from "node:path"; import * as helpers from "../../helpers.js"; import { t } from "../../i18n/index.js"; import { extendTemplateData } from "../../render/helpers.js"; import { overwriteRenderKey } from "../resolve.js"; /** * @param {object|Array|string|boolean} entry - a value from the mock data object * @returns {Promise<{ messages, data }>} the resolved value from the mock data object */ export const resolveTpls = async function (entry) { const messages = []; if (entry) { if ( typeof entry === "string" || typeof entry === "number" || typeof entry === "boolean" || entry instanceof Map || entry === null ) { return { messages, data: entry, }; } if (entry instanceof Array) { const o = []; for (const ent of entry) { const json = await resolve(ent); const result = await resolveTpls(json.data); o.push(result.data); for (const msg of [...json.messages, ...result.messages]) { if (msg) { messages.push(msg); } } } return { messages, data: o, }; } const o = { ...entry }; for (const key of Object.keys(o)) { const tpl = await resolve(o[key]); const tpls = await resolveTpls(tpl.data); for (const msg of [...tpl.messages, ...tpls.messages]) { if (msg) { messages.push(msg); } } o[key] = tpls.data; } return { messages, data: o, }; } return { messages, data: entry, }; }; /** * @param {object|Array|string|boolean} entry * @returns {Promise<{ messages, data }>} */ async function resolve(entry) { const messages = []; if (entry !== null) { if (Array.isArray(entry)) { const arr = []; for (const ent of entry) { const result = await resolve(ent); arr.push(result.data); for (const msg of messages) { if (msg) { messages.push(); } } } return { messages, data: arr, }; } if ( typeof entry === "string" || typeof entry === "number" || typeof entry === "boolean" || entry instanceof Map ) { return { messages, data: entry, }; } let entries = { ...entry }; for (const [key, val] of Object.entries(entries)) { if (key !== "$tpl") { const result = await resolve(val); entries[key] = result.data; } } const result = await render(entries); return { messages: [...messages, ...result.messages], data: result.data, }; } return { messages, data: entry, }; } /** * @param {object|Array|string|boolean} entry * @returns {Promise<{ messages, data }>} */ async function render(entry) { const messages = []; if (entry.$tpl) { let data = { ...entry }; delete data.$tpl; let filePath; let shortPath; let component; if (entry.$tpl.startsWith("@")) { const namespace = entry.$tpl.split("/")[0]; const resolvedNamespace = global.config.namespaces[namespace]; if (!resolvedNamespace) { return { messages: [ { type: "warn", text: `Could not resolve namespace ${namespace}`, }, ], data: null, }; } shortPath = helpers.getShortPathFromFullPath( path.join( process.cwd(), entry.$tpl.replace(namespace, resolvedNamespace), ), ); } else { shortPath = entry.$tpl; if (shortPath.startsWith("/")) { shortPath = shortPath.replace("/", ""); } } component = global.state.routes.find( ({ alias }) => alias === shortPath || `/${alias}` === shortPath, ); if (!component) { messages.push({ type: "error", text: t("templateDoesNotExist").replace("{{template}}", entry.$tpl), }); return { messages, data: null, }; } try { fs.statSync(component.paths.tpl.full); data = await extendTemplateData(global.config, data, component); return new Promise((resolve1) => { global.app.render(component.paths.tpl.full, data ?? {}, (err, html) => { if (err) { messages.push({ type: "warn", text: t("renderingTemplateFailed").replace( "{{filePath}}", component.paths.tpl.short, ), }); } resolve1({ messages, data: html, }); }); }); } catch (err) { if (err.code === "ENOENT") { messages.push({ type: "error", text: t("templateDoesNotExist").replace("{{template}}", filePath), verbose: err, }); return { messages, data: null, }; } } } else { return { messages, data: overwriteRenderKey(entry), }; } }