UNPKG

@rr0/cms

Version:

RR0 Content Management System (CMS)

138 lines (137 loc) 4.96 kB
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 } }; } }