@rr0/cms
Version:
RR0 Content Management System (CMS)
116 lines (115 loc) • 4.74 kB
JavaScript
import { RR0HttpDatasource } from "./rr0/RR0HttpDatasource.js";
import { HttpSource } from "./HttpSource.js";
/**
* Replaces a (ul) tag from (chronology) files with case summaries from external datasources.
*/
export class ChronologyReplacer {
constructor(mappings, renderer) {
this.mappings = mappings;
this.renderer = renderer;
/**
* Remember already processed datasources.
*
* @protected
*/
this.done = new Set();
}
async replacement(context, element) {
element.classList.add("indexed"); // Make sure the user can share an anchor to a list item.
await this.aggregate(context, element);
return element;
}
async aggregate(context, element) {
const existingCases = [];
const casesToAdd = [];
for (const mapping of this.mappings) {
const datasource = mapping.datasource;
if (datasource instanceof RR0HttpDatasource) {
datasource.http = new class extends HttpSource {
async get(queryUrl, init = {}, resOut = {}) {
return context.file.document.documentElement;
}
}();
datasource.findRows = (_doc) => {
return Array.from(element.children); // Use local RR0 rows instead of remote ones
};
}
const datasourceKey = context.file.name + "$" + datasource.copyright;
if (!this.done.has(datasourceKey)) {
await this.aggregateDatasource(context, mapping, existingCases, casesToAdd);
this.done.add(datasourceKey);
const merge = mapping.actions.write.includes("pages");
if (merge) {
const allCases = existingCases.concat(casesToAdd);
for (const c of allCases) {
const outDoc = context.file.document;
const eventEl = outDoc.createElement("li");
await this.renderer.render(context, c, eventEl, { url: true, contentOnly: true });
element.append(eventEl);
}
}
}
}
}
async aggregateDatasource(context, mapping, existingCases, casesToAdd) {
let fetched;
const datasource = mapping.datasource;
const backupDatasource = mapping.backupDatasource;
if (!backupDatasource) {
context.warn(`${mapping.constructor.name} has no backupDatasource`);
return;
}
for (const readMethod of mapping.actions.read) {
if (fetched) {
break;
}
switch (readMethod) {
case "backup":
try {
fetched = await backupDatasource.fetch(context);
}
catch (e) {
if (e.code !== "ENOENT") {
throw e;
}
else {
context.debug("No backup file to read for" + context.time);
}
}
break;
case "fetch":
fetched = await datasource.fetch(context);
break;
default:
throw new Error(`Unsupported "${(mapping.actions.read)}" read method`);
}
}
const fetchTime = new Date();
for (const writeMethod of mapping.actions.write) {
switch (writeMethod) {
case "backup":
backupDatasource.save(context, fetched, fetchTime);
break;
case "pages":
const toAddFromThisDatasource = this.merge(context, fetched, fetchTime, mapping, existingCases);
casesToAdd.concat(toAddFromThisDatasource);
break;
}
}
}
merge(context, sourceCases, fetchTime, mapping, existingCases) {
const casesToMerge = sourceCases.map(sourceCase => mapping.mapper.map(context, sourceCase, fetchTime));
const casesToAdd = [];
for (const caseToMerge of casesToMerge) {
const foundExisting = existingCases.find(existingCase => existingCase.time.isEqual(caseToMerge.time)
&& existingCase.place === caseToMerge.place);
if (foundExisting) {
context.logger.debug("Merging ", caseToMerge, " into ", foundExisting);
}
else {
casesToAdd.push(caseToMerge);
}
}
return casesToAdd;
}
}