@rr0/cms
Version:
RR0 Content Management System (CMS)
138 lines (137 loc) • 4.96 kB
JavaScript
import path from "path";
import { Level2Date as EdtfDate } from "@rr0/time";
import { JSDOM } from "jsdom";
import { FileContents } from "@javarome/fileutil";
/**
* Create Source objects.
*/
export class SourceFactory {
constructor(dataService, http, baseUrl, options, time) {
this.dataService = dataService;
this.http = http;
this.baseUrl = baseUrl;
this.options = options;
this.time = time;
}
/**
* Create a Source object from an anchor's URL.
*
* @param context
* @param href The anchor's URL string.
*/
async create(context, href) {
return href.startsWith("http") ? await this.createExternal(context, href) : await this.createInternal(context, href);
}
/**
* Create a Source object from a link referencing an internal page of the site.
*
* @param context
* @param href
*/
async createInternal(context, href) {
var _a;
if (path.dirname(href).startsWith("/")) {
href = href.substring(1);
}
const hashPos = href.lastIndexOf("#");
let hash;
if (hashPos > 0) {
hash = href.substring(hashPos + 1);
href = href.substring(0, hashPos);
}
else {
hash = undefined;
}
const ext = path.extname(href);
let source;
const sourceTypes = ["article", "book", "website",
undefined // TODO: Remove undefined when type is set in all .json files
];
switch (ext) {
case ".htm":
case ".html":
source = await this.fromPage(href, hash);
break;
case ".json":
const sources = await this.dataService.getFromDir(path.dirname(href), sourceTypes, [path.basename(href)]);
source = sources === null || sources === void 0 ? void 0 : sources[0];
break;
default: {
const sources = await this.dataService.getFromDir(ext ? path.dirname(href) : href, sourceTypes, ["index.json", "people.json"]);
source = sources === null || sources === void 0 ? void 0 : sources[0];
if (!source) {
source = await this.fromPage(path.join(href, "index.html"), hash);
}
}
}
const publication = source.publication;
if (publication && !publication.time) {
publication.time = (_a = this.time.contextFromFileName(context, href)) === null || _a === void 0 ? void 0 : _a.date;
}
if (hash) {
source.index = hash;
}
return source;
}
/**
* Create a Source object from a link referencing a page outside the site.
*
* @param context
* @param href
*/
async createExternal(context, href) {
const resOut = {};
let title;
let lastModif;
let publisher;
try {
const doc = await this.http.get(new URL(href), {}, resOut);
href = resOut.url || href;
title = doc.querySelector("title").textContent;
lastModif = resOut.headers.get("last-modified");
}
catch (e) {
context.error("Could not fetch source from " + href, e.message);
title = href;
}
publisher = resOut.headers.get("host");
const time = lastModif ? EdtfDate.fromDate(new Date(lastModif)) : context.time.date;
const publication = { publisher, time };
return {
title,
url: href,
events: [],
previousSourceRefs: [],
publication
};
}
async fromPage(href, hash = "") {
var _a;
const filePath = path.extname(href) ? href : path.join(href, "index.html");
const fileContents = FileContents.read(filePath);
const doc = new JSDOM(fileContents.contents).window.document.documentElement;
const url = new URL(href, this.baseUrl);
if (hash) {
url.hash = hash;
}
const values = Array.from(this.dataService.pathToData.values());
const data = values.find(value => { var _a; return filePath.startsWith((_a = value[0]) === null || _a === void 0 ? void 0 : _a.dirName); });
let title;
if (data) {
title = data[0].title;
}
else {
title = doc.querySelector("title").textContent;
}
const publisher = (_a = doc.querySelector("meta[name='copyright']")) === null || _a === void 0 ? void 0 : _a.getAttribute("content");
const authors = Array.from(doc.querySelectorAll("meta[name='author']")).map(meta => meta.getAttribute("content"));
return {
title,
url: url.href,
events: [],
previousSourceRefs: [],
authors,
publication: { publisher, time: undefined }
};
}
}