# core/persistence/chapter.persistence.ts

> 34 lines of code and 9 definitions.

Tree: Build tree
Language: typescript
Layer: infrastructure
Canonical: https://banes-lab.com/anatomy/build#file-build-core-persistence-chapter-persistence-ts
Source text: https://banes-lab.com/assets/sources/source.97b3106c98ce24b594c86c34e54d23aec61b3f6188c0b3529d966506d024ce48.generated.txt

## Definitions

- `markdownIn` (lexical_declaration, line 12)
- `staleChaptersOf` (lexical_declaration, line 22, exported)
- `persistChapters` (lexical_declaration, line 28, exported)
- `folderOf` (lexical_declaration, line 7)
- `slash` (lexical_declaration, line 8)
- `target` (lexical_declaration, line 13)
- `rendered` (lexical_declaration, line 23, exported)
- `folders` (lexical_declaration, line 24, exported)
- `stale` (lexical_declaration, line 32, exported)

## Uses

- [core/persistence/report.persistence.ts](https://banes-lab.com/source/build/core/persistence/report.persistence.ts.md)

## Source

```typescript
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;
};
```
