# presentation/renderers/folder.renderer.ts

> 137 lines of code and 26 definitions.

Tree: Site tree
Language: typescript
Layer: product
Canonical: https://banes-lab.com/anatomy/tree#file-presentation-renderers-folder-renderer-ts
Source text: https://banes-lab.com/assets/sources/source.c840017b457ac7e35c8a510ec70676ccfd2ed01174ed48fe4a30b44b49049609.generated.txt

## Definitions

- `renderChips` (lexical_declaration, line 48)
- `renderCrumbs` (lexical_declaration, line 75)
- `renderListing` (lexical_declaration, line 116)
- `renderFolderView` (lexical_declaration, line 126)
- `renderFileView` (lexical_declaration, line 141)
- `isList` (lexical_declaration, line 20)
- `isGlossary` (lexical_declaration, line 24)
- `isMetric` (lexical_declaration, line 28)
- `renderNodeBlock` (lexical_declaration, line 32)
- `renderFileCard` (lexical_declaration, line 96)
- `renderNode` (lexical_declaration, line 152, exported)
- `renderFolderCard` (lexical_declaration, line 105)
- `splitBlocks` (lexical_declaration, line 57)
- `pathOf` (lexical_declaration, line 68)
- `SPACE` (lexical_declaration, line 18)
- `list` (lexical_declaration, line 49)
- `[first]` (lexical_declaration, line 61)
- `crumbs` (lexical_declaration, line 76)
- `nav` (lexical_declaration, line 77)
- `CARD_METRICS` (lexical_declaration, line 85)
- `metricChips` (lexical_declaration, line 87)
- `metric` (lexical_declaration, line 88)
- `all` (lexical_declaration, line 98)
- `card` (lexical_declaration, line 106)
- `{ chips, rest }` (lexical_declaration, line 142)
- `view` (lexical_declaration, line 143)

## Uses

- [core/factories/element.factory.ts](https://banes-lab.com/source/tree/core/factories/element.factory.ts.md)
- [presentation/components/folder.component.ts](https://banes-lab.com/source/tree/presentation/components/folder.component.ts.md)
- [presentation/renderers/block.renderer.ts](https://banes-lab.com/source/tree/presentation/renderers/block.renderer.ts.md)
- [presentation/renderers/metric.renderer.ts](https://banes-lab.com/source/tree/presentation/renderers/metric.renderer.ts.md)
- [presentation/renderers/ontology.renderer.ts](https://banes-lab.com/source/tree/presentation/renderers/ontology.renderer.ts.md)
- [presentation/renderers/text.renderer.ts](https://banes-lab.com/source/tree/presentation/renderers/text.renderer.ts.md)

## Source

```typescript
import type { Block, GlossaryBlock, ListBlock, MetricBlock } from "#types/block.types";
import {
    DEFINITIONS_LABEL,
    EDGES_LABEL,
    FILES_LABEL,
    FOLDERS_LABEL,
    LINES_LABEL,
} from "#configuration/strings/folder.strings";
import type { FileNode, FolderNode, TreeNode } from "#types/folder.types";
import { ancestorsOf, isFolder, treeLink } from "#presentation/components/folder.component";
import { appendChildren, createElement } from "#core/factories/element.factory";
import { NODE_CLASS } from "#configuration/constants/anatomy.constants";
import { fillMarkup } from "#presentation/renderers/text.renderer";
import { renderBlock } from "#presentation/renderers/block.renderer";
import { renderFields } from "#presentation/renderers/ontology.renderer";
import { renderMetricGrid } from "#presentation/renderers/metric.renderer";

const SPACE = " ";

const isList = function isList(block: Block): block is ListBlock {
    return block.kind === "list";
};

const isGlossary = function isGlossary(block: Block): block is GlossaryBlock {
    return block.kind === "glossary";
};

const isMetric = function isMetric(block: Block): block is MetricBlock {
    return block.kind === "metric";
};

const renderNodeBlock = function renderNodeBlock(block: Block): Element {
    if (isGlossary(block)) {
        return renderFields(block);
    }
    if (isMetric(block)) {
        return createElement("div", {
            children: [
                createElement("h3", { className: "filesystem-listing-title", text: block.caption }),
                renderMetricGrid(block),
            ],
            className: "filesystem-metrics",
        });
    }
    return createElement("div", { children: [renderBlock(block)], className: "chapter-panel" });
};

const renderChips = function renderChips(items: readonly string[]): Element {
    const list = createElement("ul", { className: "record-chips" });
    appendChildren(
        list,
        items.map((item) => fillMarkup(createElement("li", { className: "record-chip" }), item)),
    );
    return list;
};

const splitBlocks = function splitBlocks(blocks: readonly Block[]): {
    readonly chips: readonly string[];
    readonly rest: readonly Block[];
} {
    const [first] = blocks;
    if (first !== undefined && isList(first)) {
        return { chips: first.items, rest: blocks.slice(1) };
    }
    return { chips: [], rest: blocks };
};

const pathOf = function pathOf(root: FolderNode, node: TreeNode): string {
    if (isFolder(node)) {
        return node.path;
    }
    return node.section.title === root.name ? "" : node.section.title;
};

const renderCrumbs = function renderCrumbs(root: FolderNode, node: TreeNode): Element {
    const crumbs = ancestorsOf(root, pathOf(root, node)).filter((folder) => folder !== node);
    const nav = createElement("nav", { className: "filesystem-crumbs" });
    appendChildren(
        nav,
        crumbs.map((folder) => treeLink(folder, "filesystem-crumb")),
    );
    return nav;
};

const CARD_METRICS: ReadonlySet<string> = new Set([LINES_LABEL, DEFINITIONS_LABEL, EDGES_LABEL]);

const metricChips = function metricChips(blocks: readonly Block[]): readonly string[] {
    const metric = blocks.find(isMetric);
    return metric === undefined
        ? []
        : metric.metrics
              .filter((entry) => CARD_METRICS.has(entry.label))
              .map((entry) => entry.value + SPACE + entry.label.toLowerCase());
};

const renderFileCard = function renderFileCard(file: FileNode): Element {
    const { chips, rest } = splitBlocks(file.sub.blocks ?? []);
    const all = [...chips, ...metricChips(rest)];
    return createElement("article", {
        children: [treeLink(file, "filesystem-card-title"), ...(all.length === 0 ? [] : [renderChips(all)])],
        className: "filesystem-card",
    });
};

const renderFolderCard = function renderFolderCard(folder: FolderNode): Element {
    const card = createElement("article", {
        children: [treeLink(folder, "filesystem-card-title")],
        className: "filesystem-card",
    });
    if (folder.section.intro !== undefined) {
        card.append(fillMarkup(createElement("p", { className: "filesystem-card-text" }), folder.section.intro));
    }
    return card;
};

const renderListing = function renderListing(label: string, cards: readonly Element[]): readonly Element[] {
    if (cards.length === 0) {
        return [];
    }
    return [
        createElement("h3", { className: "filesystem-listing-title", text: label }),
        createElement("div", { children: cards, className: "filesystem-listing" }),
    ];
};

const renderFolderView = function renderFolderView(root: FolderNode, folder: FolderNode): Element {
    const view = createElement("section", { attributes: { id: folder.id }, className: NODE_CLASS });
    view.append(
        renderCrumbs(root, folder),
        createElement("h2", { className: "filesystem-node-title", text: folder.name }),
    );
    if (folder.section.intro !== undefined) {
        view.append(fillMarkup(createElement("p", { className: "filesystem-intro" }), folder.section.intro));
    }
    appendChildren(view, (folder.section.blocks ?? []).map(renderNodeBlock));
    appendChildren(view, renderListing(FOLDERS_LABEL, folder.folders.map(renderFolderCard)));
    appendChildren(view, renderListing(FILES_LABEL, folder.files.map(renderFileCard)));
    return view;
};

const renderFileView = function renderFileView(root: FolderNode, file: FileNode): Element {
    const { chips, rest } = splitBlocks(file.sub.blocks ?? []);
    const view = createElement("article", { attributes: { id: file.id }, className: NODE_CLASS });
    view.append(renderCrumbs(root, file), createElement("h2", { className: "filesystem-node-title", text: file.name }));
    if (chips.length > 0) {
        view.append(renderChips(chips));
    }
    appendChildren(view, rest.map(renderNodeBlock));
    return view;
};

export const renderNode = function renderNode(root: FolderNode, node: TreeNode): Element {
    return isFolder(node) ? renderFolderView(root, node) : renderFileView(root, node);
};
```
