import { hash, fromCache, toCache } from './cache.js' // Tagged template literal helpers. Operates in the same fashion as un-tagged template literals. function tmpl(strings, ...values) { return strings .map((str, index) => values[index] ? str + values[index] : str) .join('').trim() } // Used for syntax highlighting in supported editors. export const html = tmpl export const css = tmpl export const javascript = tmpl // Stupid-simple "sanitization". Just enough for this demo, not for production. export function sanitize (str) { if (typeof str !== 'string') return str return str.split('<').join('<') } function contextFactory (parentCtx) { const head = new Set() const css = new Set() const js = new Set() let body = '' const addHead = str => { head.add(str) if (parentCtx) parentCtx.addHead(str) } const addCSS = str => { css.add(str) if (parentCtx) parentCtx.addCSS(str) } const addJS = str => { js.add(str) if (parentCtx) parentCtx.addJS(str) } const setBody = str => (body = str) const renderBody = async (component, ...params) => { debugger; (await render(parentCtx, component, ...params)).body } return { head, css, js, body, renderBody, addHead, addCSS, addJS, setBody } } /** * Render a component and return the head elements, css, js, and body contents of it and its children. * @param {Function: context} component A function * @param {...any} params Arguments to pass to the component being rendered * @returns {Object} * An object containing head elements, css, js, and body text returned by the rendered component. */ export async function render (parentCtx, component, ...params) { // Create a new context to pass to a component for each rendering. const ctx = contextFactory(parentCtx) // Attempt to load result from cache by component name and params. const key = hash([component.name, params]) const stored = fromCache(key) if (stored) { console.info(`READING COMPONENT "${component.name}" FROM CACHE`) } // Render component or load from cache. const result = stored || await component(ctx, ...params) // Store result to cache if it wasn't already present. if (!stored) toCache(key, result) // Return result context object to caller. return result }