UNPKG

@paroicms/server

Version:
244 lines 8.74 kB
import { encodeLNodeId, isObj } from "@paroicms/public-anywhere-lib"; import { escapeHtml, extractLoadDescriptor } from "@paroicms/public-server-lib"; import { promiseSymbol, valuesFnSymbol } from "../../liquidjs-tools/liquid-constants.js"; const ignoreDeprecatedKeys = new Set([ "uid", "lang", "leafType", "leafId", "num", "flaggedWith", "flaggedWithOne", "labeling", "singleLabeling", "fields", "defaultImageId", "featuredImageId", "recaptchaKey", "routingIds", "googleRecaptchaSiteKey", ]); const compactJsonKeys = new Set(["jsonLd"]); export async function infoLiquidFilter(val) { return await valueToInfo(val, 0); } async function valueToInfo(rawVal, depth, options = {}) { if (depth > 100) throw new Error("Too deep object"); const childDepth = depth + 1; const val = rawVal && typeof rawVal === "object" && promiseSymbol in rawVal ? await rawVal[promiseSymbol] : rawVal; if (val === null) return "null"; if (val === undefined) return "-"; switch (typeof val) { case "string": return shortenStringAndEsc(val, { max: 100 }); case "number": return `${val}`; case "boolean": return `${val}`; case "bigint": return `${val}n`; case "symbol": return `${escapeHtml(val.toString())} (symbol)`; case "function": try { const result = await val(); return valueToInfo(result, childDepth, options); } catch { return "error calling function"; } } if (Array.isArray(val)) { if (val.length === 0) return `<i>empty array</i>${descTagOf(val, "inline")}`; const result = []; let shortenAll = false; for (const rawItem of val) { const item = await rawItem; const onDemand = typeof item === "function" ? getOnDemandTag() : ""; result.push(`${onDemand}${await valueToInfo(item, childDepth, { isNested: true, shortenAll })}`); shortenAll = true; } return `${descTagOf(val, "raw")}<table>${result.map((item) => `<tr><td>${item}</td></tr>`).join("")}</table>`; } if (typeof val !== "object") { return `<i>(${typeof val})</i>${descTagOf(val, "inline")}`; } if (val instanceof Date) { return `<i>${val.toISOString()}</i>${descTagOf(val, "inline")}`; } const obj = valuesFnSymbol in val && typeof val[valuesFnSymbol] === "function" ? await val[valuesFnSymbol]() : val; if (!isObj(obj)) { return `<i>invalid values "${typeof obj}"</i>${descTagOf(val, "inline")}`; } if (obj.kind && (options.shortenAll || (options.isNested && isBigPayload(obj)))) { return makeExtractFromObject(obj); } return await makeTableInfo(obj, childDepth, options); } async function makeTableInfo(obj, childDepth, options) { const hasTitle = isBigPayload(obj) || obj.kind === "part" || !options.isNested; const items = []; for (const name of Object.keys(obj)) { if (ignoreDeprecatedKeys.has(name)) continue; const value = obj[name]; items.push({ name, value: compactJsonKeys.has(name) ? await resolveToCompactJson(value) : await valueToInfo(value, childDepth, { isNested: true }), onDemand: typeof value === "function" ? getOnDemandTag() : "", }); } if (items.length === 0) { const descTag = descTagOf(obj, "raw"); return descTag ?? "<i>empty object</i>"; } const nestedTableCss = ["border: 1px solid #888", "margin: 5px 0"]; const tableCss = []; if (!options.isNested) { tableCss.push("background-color: #f8f8f8", "border: 3px dotted #888", "border-top: none", "color: #222"); } else if (!hasTitle) { tableCss.push(...nestedTableCss); } const trCss = ["border-bottom: 1px solid #888"]; const thCss = [ "background-color: #eee", "padding-left: 10px", "text-align: left", "width: 170px", ]; const tdCss = ["padding: 4px 6px"]; const tableTitle = hasTitle ? typeof obj.kind === "string" ? camelCaseToSpaced(obj.kind) : "🗃" : undefined; const table = `<table style="${tableCss.join("; ")}"> ${items .map(({ name, value, onDemand }) => `<tr style="${trCss.join("; ")}"><th style="${thCss.join("; ")}">${escapeHtml(name)}${onDemand}</th><td style="${tdCss.join("; ")}">${value}</td></tr>`) .join("")} </table>`; if (!tableTitle) return `${descTagOf(obj, "raw")}${table}`; const wrapperCss = [ "display: flex", "flex-direction: column", "line-height: 1.35", "max-width: fit-content", ]; if (options.isNested) wrapperCss.push(...nestedTableCss); else wrapperCss.push("margin: 20px auto"); const headCss = [ "background-color: #777", "border-bottom: 1px solid #888", "color: #fff", "font-weight: bold", "text-align: center", "text-transform: uppercase", ]; if (options.isNested) { headCss.push("font-size: 0.875em"); } else { headCss.push("padding: 2px"); } const classAttr = !options.isNested ? ` class="PaInfoFilter"` : ""; return `<div${classAttr} style="${wrapperCss.join("; ")}"> ${descTagOf(obj, "raw")}<div style="${headCss.join("; ")}">${tableTitle}</div> ${table}</div>`; } async function resolveToCompactJson(value) { let resolved = value; if (typeof resolved === "function") { try { resolved = await resolved(); } catch { return "error calling function"; } } let json; try { json = JSON.stringify(resolved); } catch { return "<i>error serializing to JSON</i>"; } const codeCss = ["font-size: 0.8em", "word-break: break-all"].join("; "); return `<code style="${codeCss}">${escapeHtml(json)}</code>`; } function makeExtractFromObject(obj) { const descTag = descTagOf(obj, "inline"); if (!obj.kind) { const keys = Object.keys(obj); if (keys.length === 0) return "-"; return `<i>object with properties: ${Object.keys(obj).join(", ")}</i>${descTag}`; } const title = (obj.title && typeof obj.title === "string" ? shortenStringAndEsc(obj.title) : obj.title) ?? "-"; switch (obj.kind) { case "site": return `<i>⇒ site ${obj.language}</i>${descTag}`; case "detached": return `<i>⇒ detached doc ${obj.id} (${obj.type}), ${title}</i>${descTag}`; case "routingDocument": case "regularDocument": return `<i>⇒ doc ${obj.id} (${obj.type}), ${title}</i>${descTag}`; case "term": return `<i>⇒ term ${obj.id} (${obj.type}), ${title}</i>${descTag}`; case "part": return `<i>⇒ part ${obj.id} (${obj.type})</i>${descTag}`; case "media": return `<i>⇒ media ${obj.mediaId} (${obj.mediaType})</i>${descTag}`; case "image": return `<i>⇒ image ${obj.mediaId} (${obj.mediaType})</i>${descTag}`; default: return `<i>/unknown kind '${obj.kind}'/</i>${descTag}`; } } const bigKinds = new Set(["site", "detached", "routingDocument", "regularDocument", "term"]); function isBigPayload(obj) { return typeof obj.kind === "string" && bigKinds.has(obj.kind); } function shortenStringAndEsc(s, { max = 60 } = {}) { return escapeHtml(s.length < max ? s : `${s.slice(0, max)}…`); } function getOnDemandTag() { const css = [ "background: #888", "border-radius: 20px", "color: #fff", "font-size: 10px", "padding: 1px 5px", "white-space: nowrap", ]; return ` <span style="${css.join("; ")}">on demand</span> `; } function descTagOf(obj, pos) { const loadDescriptor = extractLoadDescriptor(obj); if (!loadDescriptor) return ""; const css = ["background-color: #444", "color: #bbb", "font-size: 0.875em", "padding: 2px 4px"]; const prefix = pos === "inline" ? " " : ""; if (loadDescriptor.load === "one") { return `${prefix}<span style="${css.join("; ")}">↗ ${encodeLNodeId(loadDescriptor.documentId)}</span>`; } return `${prefix}<span style="${css.join("; ")}">↗ ${loadDescriptor.descriptorName}</span>`; } function camelCaseToSpaced(s) { return s.replace(/([A-Z])/g, " $1").trim(); } //# sourceMappingURL=info-filter.js.map