# core/coordinators/index.coordinator.ts

> 87 lines of code and 18 definitions.

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

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

## Definitions

- `runIndex` (lexical_declaration, line 81, exported)
- `renderIndex` (lexical_declaration, line 55)
- `payloadOf` (lexical_declaration, line 41)
- `POSIX_SEPARATOR` (lexical_declaration, line 16)
- `NAME_DOT` (lexical_declaration, line 17)
- `groupOf` (lexical_declaration, line 19)
- `cut` (lexical_declaration, line 20)
- `bare` (lexical_declaration, line 24)
- `byGroupOf` (lexical_declaration, line 28)
- `packages` (lexical_declaration, line 56)
- `info` (lexical_declaration, line 58)
- `byGroup` (lexical_declaration, line 66)
- `base` (lexical_declaration, line 67)
- `payload` (lexical_declaration, line 68)
- `rendered` (lexical_declaration, line 82, exported)
- `markdownHealed` (lexical_declaration, line 83, exported)
- `jsonHealed` (lexical_declaration, line 84, exported)
- `healed` (lexical_declaration, line 86, exported)

## Contained in

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

## Uses

- [configuration/strings/index.strings.ts](https://banes-lab.com/source/docs/configuration/strings/index.strings.ts.md)
- [core/formatters/index.formatter.ts](https://banes-lab.com/source/docs/core/formatters/index.formatter.ts.md)
- [core/loaders/base.loader.ts](https://banes-lab.com/source/docs/core/loaders/base.loader.ts.md)
- [core/reporters/base.reporter.ts](https://banes-lab.com/source/docs/core/reporters/base.reporter.ts.md)

## Linked from

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

## Source

```typescript
import type { ByGroup, PackageInfo, RenderedIndex } from "#types/index.types";
import { indexedCount, regeneratedIndex, upToDate, wroteFile } from "#configuration/strings/index.strings";
import { renderIndexMarkdown, roleOf } from "#core/formatters/index.formatter";
import type { IndexTargets } from "#types/document.output.types";
import { ROOT } from "@ssot/paths";
import { govlabPrettierConfig } from "@govlab/quality/config";
import { healFile } from "#core/persistence/document.persistence";
import { inspectPackage } from "#core/analyzers/package.analyzer";
import { join } from "node:path";
import prettier from "prettier";
import { print } from "#core/reporters/base.reporter";
import { readTextSafe } from "#core/loaders/base.loader";
import { stampGenerated } from "@govlab/canonical-write";
import { workspaceMembers } from "#core/loaders/package.loader";

const POSIX_SEPARATOR = "/";
const NAME_DOT = ".";

const groupOf = function groupOf(relPath: string): string {
    const cut = relPath.indexOf(POSIX_SEPARATOR);
    if (cut !== -1) {
        return relPath.slice(0, cut);
    }
    const bare = relPath.startsWith(NAME_DOT) ? relPath.slice(NAME_DOT.length) : relPath;
    return bare.split(NAME_DOT)[0] ?? bare;
};

const byGroupOf = function byGroupOf(packages: readonly PackageInfo[]): ByGroup {
    const byGroup: ByGroup = {};
    for (const pkg of packages) {
        byGroup[pkg.group] = [...(byGroup[pkg.group] ?? []), pkg];
    }
    return Object.fromEntries(
        Object.entries(byGroup).map(([group, list]) => [
            group,
            list.toSorted((left, right) => left.slug.localeCompare(right.slug)),
        ]),
    );
};

const payloadOf = function payloadOf(packages: readonly PackageInfo[], byGroup: ByGroup): Record<string, unknown> {
    return {
        generatedAt: null,
        groups: Object.fromEntries(
            Object.entries(byGroup).map(([group, list]) => [
                group,
                { packages: list.map((pkg) => pkg.name), role: roleOf(group) },
            ]),
        ),
        packages,
        totalPackages: packages.length,
    };
};

const renderIndex = async function renderIndex(targets: IndexTargets): Promise<RenderedIndex> {
    const packages = workspaceMembers(ROOT)
        .flatMap((relPath) => {
            const info = inspectPackage(join(ROOT, relPath), {
                group: groupOf(relPath),
                packageName: relPath,
                repoRoot: ROOT,
            });
            return info === null ? [] : [info];
        })
        .toSorted((left, right) => left.name.localeCompare(right.name));
    const byGroup = byGroupOf(packages);
    const base = await govlabPrettierConfig(ROOT);
    const payload = JSON.stringify(payloadOf(packages, byGroup));
    return {
        count: packages.length,
        groups: Object.keys(byGroup).length,
        json: await prettier.format(payload, { ...base, filepath: targets.json.path }),
        md: stampGenerated(
            renderIndexMarkdown(packages, byGroup),
            readTextSafe(targets.markdown.path) ?? "",
            new Date(),
        ),
    };
};

export const runIndex = async function runIndex(check: boolean, targets: IndexTargets): Promise<void> {
    const rendered = await renderIndex(targets);
    const markdownHealed = healFile(targets.markdown.path, rendered.md);
    const jsonHealed = healFile(targets.json.path, rendered.json);
    if (check) {
        const healed = markdownHealed || jsonHealed;
        print(healed ? regeneratedIndex(targets.markdown.rel, targets.json.rel) : upToDate(targets.markdown.rel));
        return;
    }
    print(wroteFile(targets.markdown.rel));
    print(wroteFile(targets.json.rel));
    print(indexedCount(rendered.count, rendered.groups));
};
```
