# core/formatters/index.formatter.ts

> 168 lines of code and 40 definitions.

Tree: GovLab Docs
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/docs#file-docs-core-formatters-index-formatter-ts
Source text: https://banes-lab.com/source/docs/core/formatters/index.formatter.ts.txt

Listed in [core/formatters](https://banes-lab.com/api/source/docs/core/formatters.md), after [core/formatters/finding.formatter.ts](https://banes-lab.com/source/docs/core/formatters/finding.formatter.ts.md) and before [core/formatters/markdown.formatter.ts](https://banes-lab.com/source/docs/core/formatters/markdown.formatter.ts.md).

## Definitions

- `branchAt` (lexical_declaration, line 42)
- `firstSentence` (lexical_declaration, line 46)
- `renderIndexMarkdown` (lexical_declaration, line 142, exported)
- `compositionLines` (lexical_declaration, line 124)
- `groupTree` (lexical_declaration, line 61)
- `renderConcerns` (lexical_declaration, line 105)
- `treeLine` (lexical_declaration, line 54)
- `renderTree` (lexical_declaration, line 69)
- `concernOf` (lexical_declaration, line 101)
- `summaryOf` (lexical_declaration, line 114)
- `roleOf` (lexical_declaration, line 35, exported)
- `renderDependencies` (lexical_declaration, line 82)
- `renderInventory` (lexical_declaration, line 87)
- `renderGroups` (lexical_declaration, line 109)
- `MIN_COMPOSER_DEPS` (lexical_declaration, line 19)
- `PURPOSE_TREE_MAX` (lexical_declaration, line 20)
- `CONCERN_MAX` (lexical_declaration, line 21)
- `LINE_BREAK` (lexical_declaration, line 22)
- `BLOCK_BREAK` (lexical_declaration, line 23)
- `FENCE` (lexical_declaration, line 24)
- `SENTENCE_END` (lexical_declaration, line 25)
- `PEER_JOIN` (lexical_declaration, line 26)
- `NO_SIBLINGS` (lexical_declaration, line 27)
- `BRANCH` (lexical_declaration, line 28)
- `LAST_BRANCH` (lexical_declaration, line 29)
- `PIPE_INDENT` (lexical_declaration, line 30)
- `BLANK_INDENT` (lexical_declaration, line 31)
- `FOLDER_MARK` (lexical_declaration, line 32)
- `PURPOSE_JOIN` (lexical_declaration, line 33)
- `sortedGroups` (lexical_declaration, line 50)
- `tag` (lexical_declaration, line 55)
- `purpose` (lexical_declaration, line 56)
- `prefix` (lexical_declaration, line 62)
- `groups` (lexical_declaration, line 70)
- `dependencyBlock` (lexical_declaration, line 77)
- `lines` (lexical_declaration, line 78)
- `rows` (lexical_declaration, line 110)
- `composers` (lexical_declaration, line 125)
- `leaves` (lexical_declaration, line 126)
- `entrypoint` (lexical_declaration, line 146, exported)

## Contained in

- [core/formatters](https://banes-lab.com/anatomy/docs/folder-docs-core-formatters.md)

## Uses

- [configuration/strings/index.strings.ts](https://banes-lab.com/source/docs/configuration/strings/index.strings.ts.md)

## Used by

- [core/coordinators/index.coordinator.ts](https://banes-lab.com/source/docs/core/coordinators/index.coordinator.ts.md)

## Linked from

- [configuration/strings](https://banes-lab.com/anatomy/docs/folder-docs-configuration-strings.md)
- [core/coordinators](https://banes-lab.com/anatomy/docs/folder-docs-core-coordinators.md)
- [core/formatters](https://banes-lab.com/anatomy/docs/folder-docs-core-formatters.md)

## Source

````typescript
import type { ByGroup, PackageInfo } from "#types/index.types";
import {
    GROUP_ROLES,
    INDEX_HEADINGS,
    INDEX_TABLES,
    INDEX_TEXT,
    composeLine,
    composesPeers,
    concernRow,
    groupRow,
    indexSummary,
    inventoryRow,
    reproduceNote,
    standaloneLine,
} from "#configuration/strings/index.strings";
import { ENTRYPOINT_FILES } from "#configuration/constants/invocation.constants";
import { relativePath } from "@ssot/paths";

const MIN_COMPOSER_DEPS = 2;
const PURPOSE_TREE_MAX = 80;
const CONCERN_MAX = 110;
const LINE_BREAK = "\n";
const BLOCK_BREAK = "\n\n";
const FENCE = "```";
const SENTENCE_END = ".";
const PEER_JOIN = "` + `";
const NO_SIBLINGS = "—";
const BRANCH = "├── ";
const LAST_BRANCH = "└── ";
const PIPE_INDENT = "│   ";
const BLANK_INDENT = "    ";
const FOLDER_MARK = "/";
const PURPOSE_JOIN = " — ";

export const roleOf = function roleOf(group: string): string {
    if (group === relativePath("app.root")) {
        return GROUP_ROLES.application;
    }
    return group === relativePath("govlab.root") ? GROUP_ROLES.tooling : GROUP_ROLES.unclassified;
};

const branchAt = function branchAt(isLast: boolean): string {
    return isLast ? LAST_BRANCH : BRANCH;
};

const firstSentence = function firstSentence(text: string): string {
    return text.split(SENTENCE_END)[0] ?? "";
};

const sortedGroups = function sortedGroups(byGroup: ByGroup): string[] {
    return Object.keys(byGroup).toSorted((left, right) => left.localeCompare(right));
};

const treeLine = function treeLine(prefix: string, pkg: PackageInfo, isLast: boolean): string {
    const tag = pkg.siblingDeps.length >= MIN_COMPOSER_DEPS ? composesPeers(pkg.siblingDeps.length) : "";
    const purpose =
        pkg.purpose === null ? "" : `${PURPOSE_JOIN}${firstSentence(pkg.purpose).slice(0, PURPOSE_TREE_MAX)}`;
    return `${prefix}${branchAt(isLast)}${pkg.slug}${tag}${purpose}`;
};

const groupTree = function groupTree(group: string, packages: readonly PackageInfo[], isLastGroup: boolean): string[] {
    const prefix = isLastGroup ? BLANK_INDENT : PIPE_INDENT;
    return [
        `${branchAt(isLastGroup)}${group}${FOLDER_MARK}`,
        ...packages.map((pkg, index) => treeLine(prefix, pkg, index === packages.length - 1)),
    ];
};

const renderTree = function renderTree(byGroup: ByGroup): string {
    const groups = sortedGroups(byGroup);
    return [
        INDEX_TEXT.treeRoot,
        ...groups.flatMap((group, index) => groupTree(group, byGroup[group] ?? [], index === groups.length - 1)),
    ].join(LINE_BREAK);
};

const dependencyBlock = function dependencyBlock(pkg: PackageInfo): string {
    const lines = pkg.siblingDeps.map((dep, index) => `${branchAt(index === pkg.siblingDeps.length - 1)}${dep}`);
    return [pkg.name, ...lines].join(LINE_BREAK);
};

const renderDependencies = function renderDependencies(packages: readonly PackageInfo[]): string {
    const composers = packages.filter((pkg) => pkg.siblingDeps.length > 0);
    return composers.length === 0 ? INDEX_TEXT.noComposers : composers.map(dependencyBlock).join(BLOCK_BREAK);
};

const renderInventory = function renderInventory(packages: readonly PackageInfo[]): string {
    const rows = packages.map((pkg) =>
        inventoryRow({
            exports: pkg.barrelExports,
            group: pkg.group,
            loc: pkg.sourceLoc,
            name: pkg.name,
            siblings: pkg.siblingDeps.length === 0 ? NO_SIBLINGS : String(pkg.siblingDeps.length),
            sources: pkg.sourceFiles,
        }),
    );
    return [...INDEX_TABLES.inventory, ...rows].join(LINE_BREAK);
};

const concernOf = function concernOf(pkg: PackageInfo): string {
    return (pkg.purpose === null ? pkg.description : firstSentence(pkg.purpose)).slice(0, CONCERN_MAX);
};

const renderConcerns = function renderConcerns(packages: readonly PackageInfo[]): string {
    return [...INDEX_TABLES.concerns, ...packages.map((pkg) => concernRow(concernOf(pkg), pkg.name))].join(LINE_BREAK);
};

const renderGroups = function renderGroups(byGroup: ByGroup): string {
    const rows = sortedGroups(byGroup).map((group) => groupRow(group, roleOf(group), (byGroup[group] ?? []).length));
    return [...INDEX_TABLES.groups, ...rows].join(LINE_BREAK);
};

const summaryOf = function summaryOf(packages: readonly PackageInfo[]): string {
    return indexSummary({
        composers: packages.filter((pkg) => pkg.siblingDeps.length >= MIN_COMPOSER_DEPS).length,
        exports: packages.reduce((sum, pkg) => sum + pkg.barrelExports, 0),
        leaves: packages.filter((pkg) => pkg.siblingDeps.length === 0).length,
        loc: packages.reduce((sum, pkg) => sum + pkg.sourceLoc, 0),
        packages: packages.length,
    });
};

const compositionLines = function compositionLines(packages: readonly PackageInfo[]): string[] {
    const composers = packages.filter((pkg) => pkg.siblingDeps.length >= MIN_COMPOSER_DEPS);
    const leaves = packages.filter((pkg) => pkg.siblingDeps.length === 0);
    return [
        INDEX_HEADINGS.composition,
        "",
        INDEX_TEXT.composeIntro,
        "",
        ...composers.map((pkg) => composeLine(pkg.name, pkg.siblingDeps.join(PEER_JOIN))),
        "",
        INDEX_TEXT.standaloneIntro,
        "",
        ...leaves.map((pkg) =>
            standaloneLine(pkg.name, pkg.purpose === null ? pkg.description : firstSentence(pkg.purpose)),
        ),
    ];
};

export const renderIndexMarkdown = function renderIndexMarkdown(
    packages: readonly PackageInfo[],
    byGroup: ByGroup,
): string {
    const entrypoint = [relativePath("govlab.docs.entrypoints"), ENTRYPOINT_FILES.index].join(FOLDER_MARK);
    return [
        INDEX_HEADINGS.title,
        "",
        summaryOf(packages),
        "",
        INDEX_HEADINGS.groups,
        "",
        renderGroups(byGroup),
        "",
        INDEX_HEADINGS.tree,
        "",
        FENCE,
        renderTree(byGroup),
        FENCE,
        "",
        INDEX_HEADINGS.dependencies,
        "",
        FENCE,
        renderDependencies(packages),
        FENCE,
        "",
        INDEX_HEADINGS.inventory,
        "",
        renderInventory(packages),
        "",
        INDEX_HEADINGS.concerns,
        "",
        INDEX_TEXT.concernsNote,
        "",
        renderConcerns(packages),
        "",
        ...compositionLines(packages),
        "",
        INDEX_HEADINGS.reproduce,
        "",
        reproduceNote(entrypoint),
        "",
    ].join(LINE_BREAK);
};
````
