@airplane/views
Version:
A React library for building Airplane views. Views components are optimized in style and functionality to produce internal apps that are easy to build and maintain.
189 lines (188 loc) • 4.96 kB
JavaScript
import { useState, useRef, useEffect } from "react";
import { EVALUATE_TEMPLATE } from "../../client/endpoints.js";
import { Fetcher } from "../../client/fetcher.js";
const newTemplate = (s) => {
if (s.length === 0) {
return [];
}
const fragments = [];
let next = "";
for (let i = 0; i < s.length; i++) {
const c = s[i];
const isLast = i + 1 == s.length;
if (isLast) {
next += c;
continue;
}
const nc = s[i + 1];
if (c == "{") {
if (nc != "{") {
next += c;
continue;
}
if (next.length > 0) {
fragments.push(next);
next = "";
}
const n = measureTemplateExpression(s.substring(i));
fragments.push(s.substring(i, i + n + 1));
i += n;
} else if (c == "\\") {
if (nc === "{" || nc === "}" || nc === "\\") {
next += nc;
i++;
} else {
next += c;
}
} else {
next += c;
}
}
if (next.length > 0) {
fragments.push(next);
}
return fragments;
};
const measureTemplateExpression = (s) => {
let depth = 0;
let qm = "none";
let pc = "";
let lastdci = -1;
for (let i = 0; i < s.length; i++) {
const c = s[i];
if (c === "\\") {
if (i + 1 < s.length) {
const nc = s[i + 1];
if (nc === '"' || nc === "'" || nc === "`") {
i++;
}
}
} else if (c === '"') {
if (qm === "none") {
qm = "double";
} else if (qm === "double") {
qm = "none";
}
} else if (c === "'") {
if (qm === "none") {
qm = "single";
} else if (qm === "single") {
qm = "none";
}
} else if (c === "`") {
if (qm === "none") {
qm = "backtick";
} else if (qm === "backtick") {
qm = "none";
}
} else if (c === "{") {
if (qm === "none") {
depth++;
}
} else if (c === "}") {
if (qm === "none") {
depth--;
}
if (pc === "}") {
lastdci = i;
if (depth === 0) {
return i;
}
}
}
pc = c;
}
if (lastdci > -1) {
return lastdci;
}
throw new Error("Invalid template");
};
const unpackTemplate = (v) => isTemplate(v) ? v.raw : v;
const useEvaluateTemplate = (template, args, opts = {}) => {
const {
results,
errors,
loading,
initialLoading
} = useEvaluateTemplates([template], args, opts);
return {
result: results[0],
error: errors[0],
loading,
initialLoading
};
};
const useEvaluateTemplates = (templates, args, opts = {}) => {
const [results, setResults] = useState([]);
const cacheRef = useRef({});
const numLoadingRef = useRef(0);
const addResult = (result, i) => {
setResults((r) => r ? [...r.slice(0, i), result, ...r.slice(i + 1)] : r);
};
const templatesStr = JSON.stringify(templates);
const argsStr = JSON.stringify(args);
useEffect(() => {
const evaluateServer = async (t, i, cacheKey) => {
let response = void 0;
let errString = "";
let raw = unpackTemplate(t);
if (opts.forceEvaluate && !raw.startsWith("{{")) {
raw = `{{${raw}}}`;
}
try {
const fetcher = new Fetcher();
response = await fetcher.post(EVALUATE_TEMPLATE, {
value: raw,
lookupMaps: args,
disableDefaultLookupMaps: true
});
} catch (e) {
if (e instanceof Error) {
errString = e.message;
} else {
errString = "Unknown error";
}
}
cacheRef.current[cacheKey] = {
result: response == null ? void 0 : response.value,
error: errString
};
numLoadingRef.current--;
addResult({
result: response == null ? void 0 : response.value,
error: errString
}, i);
};
templates == null ? void 0 : templates.forEach((t, i) => {
const cacheKey = JSON.stringify({
t,
args
});
if (!t) {
addResult(void 0, i);
} else if (cacheRef.current[cacheKey]) {
addResult(cacheRef.current[cacheKey], i);
} else if (!opts.forceEvaluate && !newTemplate(unpackTemplate(t)).some((f) => f.startsWith("{{"))) {
addResult({
result: unpackTemplate(t)
}, i);
} else {
numLoadingRef.current++;
evaluateServer(t, i, cacheKey);
}
});
}, [argsStr, templatesStr, opts.forceEvaluate]);
const initialLoading = (templates == null ? void 0 : templates.length) && results.length !== templates.length;
return {
results: results.map((r) => r == null ? void 0 : r.result),
errors: results.map((r) => (r == null ? void 0 : r.error) ?? ""),
initialLoading,
loading: initialLoading || numLoadingRef.current > 0
};
};
const isTemplate = (v) => v != null && typeof v === "object" && v["__airplaneType"] === "template";
export {
useEvaluateTemplate,
useEvaluateTemplates
};
//# sourceMappingURL=jst.js.map