@ea-lab/reactive-json
Version:
A REACT-based lib that transforms JSON (or YAML) into interactive HTML markup.
377 lines (376 loc) • 12 kB
JavaScript
import { jsx as C, jsxs as L, Fragment as pt } from "react/jsx-runtime";
import { a as _ } from "../httpRequestCommon-COBq6B-n.js";
import { l as ut } from "../lodash-CYNxjS-I.js";
import { useReducer as dt, useState as w, useRef as ft, useEffect as q } from "react";
import { r as mt } from "../dnd-kit-sortable-tree.esm-Cz1RJyIg.js";
import { coreComponentsPlugin as tt } from "../coreComponentsPlugin.js";
import { mergeComponentCollections as ht } from "./ComponentCollector.js";
import { EventDispatcherProvider as gt } from "./EventDispatcherProvider.js";
import { GlobalDataContextProvider as yt } from "./GlobalDataContextProvider.js";
import Dt from "./ParsingDebugDisplay/ParsingDebugDisplay.js";
import { TemplateContext as Pt } from "./TemplateContext.js";
import { dataLocationToPath as Ct } from "./TemplateSystem.js";
import { alterData as bt } from "./utility/alterData.js";
import { applyDataMapping as Et } from "./utility/dataMappingSystem.js";
import { parseRjBuild as vt } from "./utility/parseRjBuild.js";
import { stringToBoolean as wt } from "./utility/stringToBoolean.js";
import { View as St } from "./View.js";
const xt = ({
dataOverride: S,
dataFetchMethod: M,
dataUrl: z,
debugMode: et,
DebugModeContentWrapper: A,
DebugModeDataWrapper: K,
DebugModeRootWrapper: rt,
headersForData: X,
headersForRjBuild: c,
maybeRawAppData: $,
maybeRawAppRjBuild: d,
plugins: H,
rjBuildFetchMethod: b,
rjBuildUrl: f,
upstreamUpdateCallbacks: N
}) => {
const h = [];
M && (h.push({
deprecatedProperty: "dataFetchMethod",
newProperty: "rjBuildFetchMethod"
}), b = M), z && (h.push({
deprecatedProperty: "dataUrl",
newProperty: "rjBuildUrl"
}), f = z), X && (h.push({
deprecatedProperty: "headersForData",
newProperty: "headersForRjBuild"
}), c = X), $ && (h.push({
deprecatedProperty: "maybeRawAppData",
newProperty: "maybeRawAppRjBuild"
}), d = $), h.length > 0 && console.warn(
"A ReactiveJsonRoot component got the following deprecated properties that must be replaced: " + h.map((t) => t.deprecatedProperty + " -> " + t.newProperty).join(", ")
);
const [x, g] = dt(
(t, a) => {
switch (a.type) {
case "setData":
return { updateId: 0, realCurrentData: a.data };
case "updateData":
return it(t, a.path, a.value, a.updateMode);
default:
return t;
}
},
{ updateId: 0, realCurrentData: {} }
), [at, ot] = w({}), [nt, Q] = w({}), [st, Y] = w([]), [I, T] = w(() => {
if (d)
return typeof d == "string" ? d : JSON.stringify(d);
}), [V, Z] = w(null), n = ft(null);
q(() => () => {
typeof document < "u" && n.current && n.current.parentNode && (n.current.parentNode.removeChild(n.current), n.current = null);
}, []);
const E = H ? ht([tt, H]) : tt;
q(() => {
f && (typeof b == "string" && b.toLowerCase() === "post" ? _.post(f, {
headers: c
}).then((t) => {
T(t.data);
}) : _.get(f, {
headers: c
}).then((t) => {
T(t.data);
}));
}, [f, c]), q(() => {
if (!I)
return;
const t = vt(I);
if (!t.success) {
if (console.group(
`Tried to load the app's RjBuild but the ${t.format} content could not be parsed.`
), console.error(t.error.message), console.debug("Context:", {
rjBuildUrl: f,
rjBuildFetchMethod: b,
headersForRjBuild: c,
maybeRawAppRjBuild: d,
dataOverride: S
}), console.debug("Error details:", t.error), console.groupEnd(), typeof document < "u") {
let e = document.getElementById("rj-parsing-error-root");
if (e || (e = document.createElement("div"), e.id = "rj-parsing-error-root", document.body.appendChild(e)), !n.current) {
const p = document.createElement("div");
e.appendChild(p), n.current = p;
}
Z(
mt.createPortal(
/* @__PURE__ */ C(
Dt,
{
processedRjBuild: t,
errorContext: {
rjBuildUrl: f,
rjBuildFetchMethod: b,
headersForRjBuild: c,
maybeRawAppRjBuild: d
}
}
),
n.current,
() => {
n.current && (n.current.parentNode.removeChild(n.current), n.current = null);
}
)
);
}
return;
}
V && (Z(null), typeof document < "u" && n.current && n.current.parentNode && (n.current.parentNode.removeChild(n.current), n.current = null));
const a = t.data;
ot(a.templates ?? a.listForms), !a.templates && a.listForms && console.log(
"'listForms' needs to be renamed to 'templates'. The support for 'listForms' will be removed in the next releases of reactive-json."
);
let i = S === void 0 ? a.data : S;
const s = a.additionalDataSource;
if (!Array.isArray(s) || s.length === 0) {
g({ type: "setData", data: i }), Q(a.renderView), Y(Object.keys(a.renderView));
return;
}
const m = {
headersForRjBuild: c,
plugins: E,
templateData: i,
templatePath: "data",
setData: R,
updateData: W
}, r = {
templateData: i,
templatePath: "data"
}, l = s.filter((e) => e.blocking === !0), v = s.filter((e) => e.blocking !== !0), o = async (e, p) => {
var y;
try {
if (!e.src) {
console.warn("additionalDataSource item number " + p + " missing 'src' property.", e);
return;
}
const D = {
method: ((y = e.method) == null ? void 0 : y.toUpperCase()) || "GET",
url: e.src
};
c && Object.keys(c).length > 0 && (D.headers = c);
const k = await _(D), ct = {
url: D.url,
method: D.method,
headers: D.headers || {},
body: D.data
}, lt = {
headers: k.headers || {},
status: k.status,
data: k.data
}, P = bt({
requestContext: ct,
responseContext: lt,
responseBody: k.data,
// additionalDataSource always processes raw data, not RjBuild.
isRjBuild: !1,
dataProcessors: (E == null ? void 0 : E.dataProcessor) || {}
});
if (e.dataMapping)
try {
Et({
dataMapping: e.dataMapping,
responseData: P,
globalDataContext: m,
templateContext: r
});
return;
} catch (u) {
console.error("Error applying dataMapping for additionalDataSource:", u);
}
if (!e.path) {
if (typeof P != "object" || Array.isArray(P)) {
console.warn(
"additionalDataSource data cannot be merged at root - must be an object:",
P
);
return;
}
Object.entries(P).forEach(([u, G]) => {
g({
type: "updateData",
path: u,
value: G
});
});
return;
}
try {
const u = Ct({
dataLocation: e.path,
currentPath: "data",
globalDataContext: m,
templateContext: r
});
if (typeof u != "string") {
console.warn(
"additionalDataSource path evaluation did not result in a string:",
e.path,
"->",
u
);
return;
}
const G = u.substring(5);
g({
type: "updateData",
path: G,
value: P
});
} catch (u) {
console.error("Error evaluating additionalDataSource path:", e.path, u);
}
} catch (B) {
console.error("Error fetching additional data source:", e.src, B);
}
};
g({ type: "setData", data: i }), (async () => {
if (l.length > 0) {
const e = l.map((p, y) => o(p, y));
await Promise.allSettled(e).catch((p) => {
console.error("Error processing blocking additionalDataSource:", p);
});
}
if (Q(a.renderView), Y(Object.keys(a.renderView)), v.length > 0) {
const e = v.map(
(p, y) => o(p, l.length + y)
);
Promise.allSettled(e);
}
})();
}, [I, S, c]);
function j(t, a, i) {
if (!N || N.size === 0)
return !1;
for (const [s, m] of N)
if (t === s || t.startsWith(s + ".") || s === "") {
const r = s === "" ? t : t.substring(s.length + 1);
try {
return m(a, r, i), !0;
} catch (l) {
console.warn("Error during upstream update:", l);
break;
}
}
return !1;
}
function W(t, a, i = void 0) {
let s = a.replace("data.", "");
j(s, t, i) || g({
type: "updateData",
path: s,
value: t,
updateMode: i
});
}
function R(t) {
j("", t, void 0) || g({
type: "setData",
data: t
});
}
function it(t, a, i, s = void 0) {
const m = a.split(".");
(typeof t.realCurrentData != "object" || t.realCurrentData === null || Array.isArray(t.realCurrentData)) && (t.realCurrentData = {});
let r = t.realCurrentData;
for (let l = 0, v = m.length; l < v; l++) {
const o = m[l];
if (l === v - 1) {
if (s === "remove" && Array.isArray(r))
r.splice(o, 1);
else if (s === "move")
if (i.increment) {
if (!Array.isArray(r))
return t;
const J = Math.min(
r.length,
Math.max(0, parseInt(o) + parseInt(i.increment))
);
if (J === parseInt(o))
return t;
const e = r.splice(o, 1);
if (e.length < 1)
return t;
r.splice(J, 0, e[0]);
} else
return t;
else if (i === void 0)
delete r[o];
else {
if (ut.isEqual(i, r[o]))
return t;
s === "add" ? (r[o] === void 0 && (r[o] = []), r[o].push(i)) : r[o] = i;
}
return {
// Using modulo in case of massive update counts in long frontend sessions.
updateId: (t.updateId ?? 0) % (Number.MAX_SAFE_INTEGER - 1) + 1,
realCurrentData: t.realCurrentData
};
}
if (r.hasOwnProperty(o)) {
(typeof r[o] != "object" || r[o] === null) && (r[o] = {}), r = r[o];
continue;
}
r[o] = {}, r = r[o];
}
throw new Error("Could not update data.");
}
if (!I)
return null;
const U = st.map((t) => {
var a;
return /* @__PURE__ */ C(
St,
{
datafield: t,
props: nt[t],
path: "data." + t,
currentData: (a = x.realCurrentData) == null ? void 0 : a[t]
},
t
);
}), O = wt(et), F = /* @__PURE__ */ C(gt, { children: /* @__PURE__ */ L(
yt,
{
value: {
element: at,
headersForRjBuild: c,
plugins: E,
// Expose the root component to avoid import cycles in core plugins.
ReactiveJsonRoot: xt,
setData: R,
setRawAppRjBuild: T,
templateData: x.realCurrentData,
templatePath: "data",
updateData: W
},
children: [
/* @__PURE__ */ C(
Pt.Provider,
{
value: {
templateData: x.realCurrentData,
templatePath: "data"
},
children: O && A ? /* @__PURE__ */ C(A, { children: U }) : U
}
),
O ? K && /* @__PURE__ */ C(K, { children: JSON.stringify(x.realCurrentData, null, " ") }) : null
]
}
) });
return O && A ? /* @__PURE__ */ L(rt, { children: [
F,
V
] }) : /* @__PURE__ */ L(pt, { children: [
F,
V
] });
};
export {
xt as ReactiveJsonRoot
};