# core/reporters/report.reporter.ts

> 168 lines of code and 15 definitions.

Tree: GovLab Stats
Language: typescript
Layer: operations
Canonical: https://banes-lab.com/anatomy/stats#file-stats-core-reporters-report-reporter-ts
Source text: https://banes-lab.com/source/stats/core/reporters/report.reporter.ts.txt

Listed in [core/reporters](https://banes-lab.com/api/source/stats/core/reporters.md), after [core/reporters/metric.reporter.ts](https://banes-lab.com/source/stats/core/reporters/metric.reporter.ts.md) and before [core/reporters/site.reporter.ts](https://banes-lab.com/source/stats/core/reporters/site.reporter.ts.md).

## Definitions

- `existenceSection` (lexical_declaration, line 63)
- `arrangementSection` (lexical_declaration, line 107)
- `authoredRows` (lexical_declaration, line 35)
- `dynamicsSection` (lexical_declaration, line 142)
- `excludedRows` (lexical_declaration, line 42)
- `unclassifiedRows` (lexical_declaration, line 50)
- `headerSection` (lexical_declaration, line 15)
- `renderReport` (lexical_declaration, line 162, exported)
- `gate` (lexical_declaration, line 16)
- `taxonomy` (lexical_declaration, line 19)
- `bucket` (lexical_declaration, line 44)
- `lines` (lexical_declaration, line 45)
- `rows` (lexical_declaration, line 51)
- `{ state, workspace, docs, git, memory, graph }` (lexical_declaration, line 64)
- `derived` (lexical_declaration, line 163, exported)

## Contained in

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

## Uses

- [core/formatters/metric.formatter.ts](https://banes-lab.com/source/stats/core/formatters/metric.formatter.ts.md)
- [core/reporters/dependency.reporter.ts](https://banes-lab.com/source/stats/core/reporters/dependency.reporter.ts.md)
- [core/reporters/metric.reporter.ts](https://banes-lab.com/source/stats/core/reporters/metric.reporter.ts.md)
- [core/reporters/site.reporter.ts](https://banes-lab.com/source/stats/core/reporters/site.reporter.ts.md)
- [core/reporters/taxonomy.reporter.ts](https://banes-lab.com/source/stats/core/reporters/taxonomy.reporter.ts.md)
- [core/reporters/validation.reporter.ts](https://banes-lab.com/source/stats/core/reporters/validation.reporter.ts.md)

## Linked from

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

## Source

```typescript
import { AUTHORED_ROLES, EXCLUDED_ORDER } from "#configuration/constants/source.constants";
import type { Derived, ReportInput } from "#types/report.types";
import { bucketOf, deriveMetrics } from "#core/converters/metric.converter";
import { humanBytes, num } from "#core/formatters/metric.formatter";
import type { AppStats } from "#types/site.types";
import type { GitStats } from "#types/vcs.types";
import type { State } from "#types/source.types";
import { abstractionSection } from "#core/reporters/metric.reporter";
import { appSection } from "#core/reporters/site.reporter";
import { interactionSection } from "#core/reporters/dependency.reporter";
import path from "node:path";
import { taxonomySection } from "#core/reporters/taxonomy.reporter";
import { verificationSubsections } from "#core/reporters/validation.reporter";

const headerSection = function headerSection(input: ReportInput): string[] {
    const gate = input.verify.available
        ? `gate \`${input.verify.label}\` ${input.verify.ok ? "passing" : "failing"} (${num(input.verify.totals.failed)}/${num(input.verify.totals.steps)})`
        : "gate not recorded";
    const taxonomy = `taxonomy over ${num(input.taxonomy.roots.length)} governed roots`;
    return [
        "---",
        "type: reference",
        "name: codebase-stats",
        "summary: The generated codebase census — authored source, taxonomy conformance, workspace members, governed modules, git history and the derived ratios behind them.",
        "concern: workspace",
        "---",
        "",
        "# Codebase Statistics",
        "",
        `> ${taxonomy} · ${gate}`,
        "",
    ];
};

const authoredRows = function authoredRows(state: State): string[] {
    return AUTHORED_ROLES.map((role) => {
        const bucket = bucketOf(state.authored, role);
        return `| ${role} | ${num(bucket.files)} | ${num(bucket.code)} | ${num(bucket.blank)} | ${humanBytes(bucket.bytes)} |`;
    });
};

const excludedRows = function excludedRows(state: State): string[] {
    return EXCLUDED_ORDER.map((kind) => {
        const bucket = bucketOf(state.excluded, kind);
        const lines = kind === "binary" ? "—" : num(bucket.code);
        return `| ${kind} | ${num(bucket.files)} | ${lines} | ${humanBytes(bucket.bytes)} |`;
    });
};

const unclassifiedRows = function unclassifiedRows(state: State): string[] {
    const rows = [...state.unclassified.entries()].toSorted((a, b) => b[1].files - a[1].files);
    if (rows.length === 0) {
        return [];
    }
    return [
        "| Unclassified extension | Files | Lines |",
        "| --- | ---: | ---: |",
        ...rows.map(([ext, bucket]) => `| \`${ext}\` | ${num(bucket.files)} | ${num(bucket.code)} |`),
        "",
    ];
};

const existenceSection = function existenceSection(input: ReportInput, derived: Derived): string[] {
    const { state, workspace, docs, git, memory, graph } = input;
    return [
        "## I. Existence",
        "",
        "### Authored",
        "",
        "| Role | Files | Lines | Blank | Size |",
        "| --- | ---: | ---: | ---: | ---: |",
        ...authoredRows(state),
        `| **total** | **${num(derived.authoredFiles)}** | **${num(derived.authoredLines)}** | **${num(state.lines.blank)}** | |`,
        "",
        "### Excluded",
        "",
        "| Excluded | Files | Lines | Size |",
        "| --- | ---: | ---: | ---: |",
        ...excludedRows(state),
        "",
        ...unclassifiedRows(state),
        "### Entities",
        "",
        "| Entity | Count |",
        "| --- | ---: |",
        `| workspace members | ${num(input.packages.length)} |`,
        `| governed modules | ${num(workspace.total)} |`,
        `| taxonomy-governed roots | ${num(input.taxonomy.roots.length)} |`,
        `| internal packages | ${num(graph.nodeCount)} |`,
        `| test files | ${num(state.testFiles)} |`,
        `| doc-arch documents | ${num(docs.total)} |`,
        `| memory files | ${memory.present ? num(memory.files) : "n/a"} |`,
        `| commits on \`${git?.branch ?? "(no repo)"}\` | ${git ? num(git.commits) : "0"} |`,
        "",
        "### Derived inventories",
        "",
        "| Inventory | Count | Producer |",
        "| --- | ---: | --- |",
        `| code definitions | ${num(input.analysis.definitions)} | \`${input.analysis.producer}\` |`,
        `| call-graph edges | ${num(input.analysis.edges)} | \`${input.analysis.producer}\` |`,
        `| lint rules catalogued | ${num(input.quality.totalRules)} | \`${input.quality.producer}\` |`,
        `| canonical concepts | ${num(input.quality.concepts)} | \`${input.quality.producer}\` |`,
        "",
    ];
};

const arrangementSection = function arrangementSection(state: State, derived: Derived, app: AppStats): string[] {
    return [
        "## II. Arrangement",
        "",
        "### Areas",
        "",
        "| Area | Files | Lines | Size |",
        "| --- | ---: | ---: | ---: |",
        ...derived.areaRows.map(
            ([area, bucket]) =>
                `| \`${area}\` | ${num(bucket.files)} | ${num(bucket.code)} | ${humanBytes(bucket.bytes)} |`,
        ),
        "",
        "### Shape",
        "",
        "| Measure | Lines |",
        "| --- | ---: |",
        `| mean | ${num(derived.avgLines)} |`,
        `| median | ${num(derived.medianLines)} |`,
        `| 90th percentile | ${num(derived.p90Lines)} |`,
        `| largest | ${num(derived.largestLines)} |`,
        `| max directory depth | ${num(state.maxDepth)} |`,
        "",
        "### Largest source files",
        "",
        "| # | File | Lines |",
        "| ---: | --- | ---: |",
        ...derived.topLargest.map(
            (entry, index) => `| ${index + 1} | \`${entry.path.split(path.sep).join("/")}\` | ${num(entry.lines)} |`,
        ),
        "",
        ...appSection(app),
    ];
};

const dynamicsSection = function dynamicsSection(git: GitStats | null): string[] {
    if (git === null) {
        return ["## III. Dynamics", "", "| Metric | Value |", "| --- | --- |", "| repository | none |", ""];
    }
    return [
        "## III. Dynamics",
        "",
        "| Metric | Value |",
        "| --- | --- |",
        `| branch | \`${git.branch ?? "?"}\` |`,
        `| HEAD | \`${git.head ?? "?"}\` |`,
        `| commits | ${num(git.commits)} |`,
        `| tracked files | ${num(git.tracked)} |`,
        `| first commit | ${git.firstDate ?? "?"} |`,
        `| latest commit | ${git.lastDate ?? "?"} |`,
        `| contributors | ${num(git.contributors.length)} |`,
        "",
    ];
};

export const renderReport = function renderReport(input: ReportInput): string {
    const derived = deriveMetrics(input.state);
    return [
        ...headerSection(input),
        ...existenceSection(input, derived),
        ...arrangementSection(input.state, derived, input.app),
        ...dynamicsSection(input.git),
        ...interactionSection(input.graph, input.analysis),
        "## V. Abstraction",
        "",
        ...taxonomySection(input.taxonomy),
        ...abstractionSection(input, derived),
        ...verificationSubsections(input.verify, input.activeRules, input.typescript),
    ].join("\n");
};
```
