core/loaders/diagram.loader.ts
core/loaders/diagram.loader.ts is a file in Bane's Lab Site. 61 lines of code and 15 definitions.
import { DIAGRAM_STYLESHEET, diagramLocation } from "#core/assets/diagram.assets";
import { DIAGRAM_STYLE_UNAVAILABLE, DIAGRAM_UNAVAILABLE } from "#configuration/strings/report.strings";
import { createElement } from "#core/factories/element.factory";
import { diagramDigest } from "#core/analyzers/diagram.analyzer";
import { isVector } from "#core/predicates/resource.predicate";
import { reportFailure } from "#core/reporters/failure.reporter";
const STYLESHEET_REL = "stylesheet";
const LOAD_EVENT = "load";
const ERROR_EVENT = "error";
const held = new Map<string, Promise<string | null>>();
let styled: Promise<void> | null = null;
const fetchMarkup = async function fetchMarkup(source: string): Promise<string | null> {
try {
const location = diagramLocation(await diagramDigest(source));
const response = await fetch(location);
if (!isVector(response)) {
reportFailure(DIAGRAM_UNAVAILABLE, location);
return null;
}
return await response.text();
} catch (error) {
reportFailure(DIAGRAM_UNAVAILABLE, error);
return null;
}
};
const attachStylesheet = async function attachStylesheet(): Promise<void> {
return new Promise((settle) => {
const link = createElement("link", { attributes: { href: DIAGRAM_STYLESHEET, rel: STYLESHEET_REL } });
link.addEventListener(LOAD_EVENT, () => {
settle();
});
link.addEventListener(ERROR_EVENT, (event) => {
reportFailure(DIAGRAM_STYLE_UNAVAILABLE, event);
settle();
});
document.head.append(link);
});
};
const styledMarkup = async function styledMarkup(source: string): Promise<string | null> {
const markup = await fetchMarkup(source);
if (markup === null) {
return null;
}
styled ??= attachStylesheet();
await styled;
return markup;
};
export const loadDiagram = async function loadDiagram(source: string): Promise<string | null> {
const pending = held.get(source);
if (pending !== undefined) {
return pending;
}
const loading = styledMarkup(source).then((markup) => {
if (markup === null) {
held.delete(source);
}
return markup;
});
held.set(source, loading);
return loading;
};