UNPKG

@rr0/cms

Version:

RR0 Content Management System (CMS)

131 lines (130 loc) 5.37 kB
import fs from "fs"; import path from "path"; import { FileContents } from "@javarome/fileutil"; import { DirectoryStep } from "ssg-api"; import { RR0FileUtil } from "../util/file/RR0FileUtil.js"; import { StringUtil } from "../util/string/StringUtil.js"; import { HtmlTag } from "../util/html/HtmlTag.js"; import { Chapter } from "./Chapters.js"; /** * Scan directories for book information, then populates a template with collected data. */ export class BookDirectoryStep extends DirectoryStep { constructor(rootDirs, templateFileName, outputFunc, config, name, bookMeta, bookLinks) { super({ rootDirs, excludedDirs: [], templateFileName, getOutputPath: config.getOutputPath }, name); this.outputFunc = outputFunc; this.bookMeta = bookMeta; this.bookLinks = bookLinks; } static async create(outputFunc, config, bookMeta, bookLinks) { const dirs = RR0FileUtil.findDirectoriesContaining("book*.json"); return new BookDirectoryStep(dirs, "book/index.html", outputFunc, config, "all books", bookMeta, bookLinks); } async processDirs(context, dirNames) { const books = this.scan(context, dirNames); await this.tocAll(context, books); const directoriesHtml = this.toList(books); context.file.contents = context.file.contents.replace(`<!--#echo var="directories" -->`, directoriesHtml); await this.outputFunc(context, context.file); } scan(context, dirNames) { const books = []; for (const dirName of dirNames) { const dirBook = { events: [], previousSourceRefs: [], type: "book", dirName, authors: [], publication: { publisher: "", time: undefined }, summary: "", title: "", variants: [] }; books.push(dirBook); try { const jsonFileInfo = FileContents.read(`${dirName}/book.json`); Object.assign(dirBook, JSON.parse(jsonFileInfo.contents)); } catch (e) { context.warn(`${dirName} has no book*.json description`); } } return books; } /** * Convert an array of Case[] to an <ul> HTML unordered list. * * @param books */ toList(books) { const listItems = books.map(dirBook => { if (!dirBook.title) { const lastSlash = dirBook.dirName.lastIndexOf("/"); const lastDir = dirBook.dirName.substring(lastSlash + 1); dirBook.title = StringUtil.camelToText(lastDir); } return this.toListItem(dirBook); }); return HtmlTag.toString("ul", listItems.join("\n"), { class: "links" }); } /** * Convert a Case object to an HTML list item. * * @param dirBook */ toListItem(dirBook) { const attrs = {}; const titles = []; const details = []; const authors = dirBook.authors; const authorStr = authors ? authors.join(" & ") + ": " : ""; const time = dirBook.publication.time; if (time) { const timeDetail = time.year.value; details.push(HtmlTag.toString("time", timeDetail.toString())); } const text = [authorStr, dirBook.title]; if (details.length > 0) { text.push(`(${details.join(", ")})`); } const innerHTML = text.join(" ").trim(); const a = fs.existsSync(path.join(dirBook.dirName, "index.html")) ? HtmlTag.toString("a", innerHTML, { href: "/" + dirBook.dirName + "/" }) : innerHTML; if (titles.length) { attrs.title = titles.join(", "); } return HtmlTag.toString("li", a, attrs); } async tocAll(context, books) { for (const book of books) { await this.toc(context, book); } } async toc(context, book) { const startFileName = path.join(book.dirName, "index.html"); try { context.read(startFileName); const startFileNames = [context.file.name]; const variants = context.file.lang.variants; for (const variant of variants) { const parsed = path.parse(startFileName); const variantFileName = path.join(parsed.dir, `${parsed.name}_${variant}${parsed.ext}`); startFileNames.push(variantFileName); } for (const startFileName of startFileNames) { const chapter = new Chapter(context, startFileName); await chapter.scan(); const chapterBefore = chapter.toString(); context.logger.debug("toc before:", chapterBefore); await chapter.update(); const chapterAfter = chapter.toString(); context.logger.debug("toc after:", chapterAfter); context.logger.log("Updated toc for", chapter.context.file.name); book.variants.push(chapter); this.bookMeta.set(startFileName, chapter.context.file.meta); this.bookLinks.set(startFileName, chapter.context.file.links); } } catch (e) { context.logger.error("Could not check TOC of " + startFileName, e.message); } } }