core/persistence/chapter.persistence.ts

core/persistence/chapter.persistence.ts is a file in Bane's Lab Content. 34 lines of code and 9 definitions.

import { FOLDER_SEPARATOR, MARKDOWN_EXTENSION } from "#configuration/constants/chapter.constants";
import { existsSync, readdirSync, rmSync } from "node:fs";
import type { Chapter } from "#types/chapter.types";
import { join } from "node:path";
import { persistText } from "#core/persistence/report.persistence";

const folderOf = function folderOf(file: string): string {
    const slash = file.lastIndexOf(FOLDER_SEPARATOR);
    return slash === -1 ? "" : file.slice(0, slash);
};

const markdownIn = function markdownIn(out: string, folder: string): string[] {
    const target = join(out, folder);
    if (!existsSync(target)) {
        return [];
    }
    return readdirSync(target, { withFileTypes: true })
        .filter((entry) => entry.isFile() && entry.name.endsWith(MARKDOWN_EXTENSION))
        .map((entry) => (folder.length === 0 ? entry.name : folder + FOLDER_SEPARATOR + entry.name));
};

export const staleChaptersOf = function staleChaptersOf(out: string, chapters: readonly Chapter[]): string[] {
    const rendered = new Set(chapters.map((chapter) => chapter.file));
    const folders = [...new Set(chapters.map((chapter) => folderOf(chapter.file)))];
    return folders.flatMap((folder) => markdownIn(out, folder)).filter((file) => !rendered.has(file));
};

export const persistChapters = async function persistChapters(
    out: string,
    chapters: readonly Chapter[],
): Promise<string[]> {
    const stale = staleChaptersOf(out, chapters);
    for (const file of stale) {
        rmSync(join(out, file));
    }
    await Promise.all(chapters.map(async (chapter) => persistText(join(out, chapter.file), chapter.body)));
    return stale;
};