@paroicms/server
Version:
The ParoiCMS server
206 lines • 7.06 kB
JavaScript
import { isObj } from "@paroicms/public-anywhere-lib";
import { escapeHtml } from "@paroicms/public-server-lib";
import { promiseSymbol, valuesFnSymbol } from "../../liquidjs-tools/liquidjs-drop.js";
const ignoreDeprecatedKeys = new Set([
"uid",
"lang",
"leafType",
"leafId",
"num",
"flaggedWith",
"flaggedWithOne",
"labeling",
"singleLabeling",
"fields",
"defaultImageId",
"featuredImageId",
"recaptchaKey",
"routingIds",
]);
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>";
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 `<table>${result.map((item) => `<tr><td>${item}</td></tr>`).join("")}</table>`;
}
if (typeof val !== "object") {
return `<i>(${typeof val})</i>`;
}
if (val instanceof Date) {
return `<i>${val.toISOString()}</i>`;
}
const obj = valuesFnSymbol in val && typeof val[valuesFnSymbol] === "function"
? await val[valuesFnSymbol]()
: val;
if (!isObj(obj)) {
return `<i>invalid values "${typeof obj}"</i>`;
}
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: await valueToInfo(value, childDepth, { isNested: true }),
onDemand: typeof value === "function" ? getOnDemandTag() : "",
});
}
if (items.length === 0)
return "<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 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("; ")}">
<div style="${headCss.join("; ")}">${tableTitle}</div>
${table}</div>`;
}
function makeExtractFromObject(obj) {
if (!obj.kind) {
const keys = Object.keys(obj);
if (keys.length === 0)
return "-";
return `<i>object with properties: ${Object.keys(obj).join(", ")}</i>`;
}
const title = (obj.title && typeof obj.title === "string" ? shortenStringAndEsc(obj.title) : obj.title) ??
"-";
switch (obj.kind) {
case "site":
return `<i>⇒ site ${obj.language}</i>`;
case "detached":
return `<i>⇒ detached doc ${obj.id} (${obj.type}), ${title}</i>`;
case "routingDocument":
case "regularDocument":
return `<i>⇒ doc ${obj.id} (${obj.type}), ${title}</i>`;
case "term":
return `<i>⇒ term ${obj.id} (${obj.type}), ${title}</i>`;
case "part":
return `<i>⇒ part ${obj.id} (${obj.type})</i>`;
case "media":
return `<i>⇒ media ${obj.mediaId} (${obj.mediaType})</i>`;
case "image":
return `<i>⇒ image ${obj.mediaId} (${obj.mediaType})</i>`;
default:
return `<i>/unknown kind '${obj.kind}'/</i>`;
}
}
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 camelCaseToSpaced(s) {
return s.replace(/([A-Z])/g, " $1").trim();
}
//# sourceMappingURL=info-filter.js.map