# core/coordinators/anatomy.coordinator.ts

> 132 lines of code and 27 definitions.

Tree: Bane's Lab Build Scripts
Language: typescript
Layer: application
Canonical: https://banes-lab.com/anatomy/build-scripts#file-build-scripts-core-coordinators-anatomy-coordinator-ts
Source text: https://banes-lab.com/source/build-scripts/core/coordinators/anatomy.coordinator.ts.txt

Listed in [core/coordinators](https://banes-lab.com/api/source/build-scripts/core/coordinators.md), before [core/coordinators/catalog.coordinator.ts](https://banes-lab.com/source/build-scripts/core/coordinators/catalog.coordinator.ts.md).

## Definitions

- `qualify` (lexical_declaration, line 71)
- `buildAnatomy` (lexical_declaration, line 78, exported)
- `deriveAnatomy` (lexical_declaration, line 123, exported)
- `deriveTree` (lexical_declaration, line 37)
- `moduleDir` (lexical_declaration, line 41)
- `report` (lexical_declaration, line 42)
- `{ built, entries }` (lexical_declaration, line 43)
- `tree` (lexical_declaration, line 44)
- `charts` (lexical_declaration, line 45)
- `documents` (lexical_declaration, line 46)
- `imports` (lexical_declaration, line 47)
- `{ repository, tab }` (lexical_declaration, line 63)
- `linked` (lexical_declaration, line 64)
- `pruned` (lexical_declaration, line 82, exported)
- `scope` (lexical_declaration, line 83, exported)
- `declarations` (lexical_declaration, line 90, exported)
- `derived` (lexical_declaration, line 92, exported)
- `done` (lexical_declaration, line 93, exported)
- `snapshot` (lexical_declaration, line 94, exported)
- `sites` (lexical_declaration, line 97, exported)
- `baselineFile` (lexical_declaration, line 99, exported)
- `lost` (lexical_declaration, line 100, exported)
- `lines` (lexical_declaration, line 102, exported)
- `labels` (lexical_declaration, line 109, exported)
- `measures` (lexical_declaration, line 110, exported)
- `label` (lexical_declaration, line 111, exported)
- `trees` (lexical_declaration, line 124, exported)

## Contained in

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

## Uses

- [configuration/strings/anatomy.strings.ts](https://banes-lab.com/source/build-scripts/configuration/strings/anatomy.strings.ts.md)
- [core/converters/anatomy.converter.ts](https://banes-lab.com/source/build-scripts/core/converters/anatomy.converter.ts.md)
- [core/converters/baseline.converter.ts](https://banes-lab.com/source/build-scripts/core/converters/baseline.converter.ts.md)
- [core/converters/snapshot.converter.ts](https://banes-lab.com/source/build-scripts/core/converters/snapshot.converter.ts.md)
- [core/converters/walk.converter.ts](https://banes-lab.com/source/build-scripts/core/converters/walk.converter.ts.md)
- [core/coordinators/config.coordinator.ts](https://banes-lab.com/source/build-scripts/core/coordinators/config.coordinator.ts.md)
- [core/formatters/anatomy.formatter.ts](https://banes-lab.com/source/build-scripts/core/formatters/anatomy.formatter.ts.md)
- [core/persistence/asset.persistence.ts](https://banes-lab.com/source/build-scripts/core/persistence/asset.persistence.ts.md)
- [core/persistence/baseline.persistence.ts](https://banes-lab.com/source/build-scripts/core/persistence/baseline.persistence.ts.md)
- [core/persistence/tree.persistence.ts](https://banes-lab.com/source/build-scripts/core/persistence/tree.persistence.ts.md)

## Used by

- [core/converters/snapshot.converter.ts](https://banes-lab.com/source/build-scripts/core/converters/snapshot.converter.ts.md)

## Linked from

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

## Source

```typescript
import {
    ANATOMY_TREE_LABEL,
    anatomyLine,
    lostReference,
    lostReferencesLine,
    treeSummaryLine,
    unlabeledTree,
} from "#configuration/strings/anatomy.strings";
import type { AnatomyScope, DerivedTree, ReferenceSite, TreeOptions } from "#types/anatomy.types";
import type { AnatomySnapshot, AnatomyTreeDeclaration } from "@banes-lab/web/types/anatomy.types.js";
import { ROOT, absolutePath, relativePath } from "@ssot/paths";
import { buildContext, buildModuleReport, discoverModules } from "@govlab/patterns";
import { convertAnatomy, countFolders, referencedTrees, withRepository } from "#core/converters/anatomy.converter";
import { currentCandidates, exactReferencesOf, lostReferences } from "#core/converters/baseline.converter";
import { documentsOf, filesOf } from "#core/converters/document.converter";
import { persistBaseline, readBaseline } from "#core/persistence/baseline.persistence";
import { readDeclaredTree, treeDeclarations } from "#core/loaders/tree.loader";
import { renderAnatomy, renderAnatomyMeasures } from "#core/formatters/anatomy.formatter";
import { TREE_TAB } from "@banes-lab/web/ids/anatomy.ids";
import { UNQUALIFIED } from "#configuration/constants/anatomy.constants";
import { anatomyMeasures } from "#core/converters/metric.converter";
import { chartsOf } from "#core/converters/figure.converter";
import { createWalkAssets } from "#core/factories/walk.factory";
import { docsHostFor } from "@govlab/docs";
import { excludeMatcher } from "@govlab/quality/config";
import { extractConfigs } from "#core/coordinators/config.coordinator";
import { importEdgesOf } from "#core/converters/specifier.converter";
import { join } from "node:path";
import { persistTreeDeclarations } from "#core/persistence/tree.persistence";
import process from "node:process";
import { qualifiedSnapshot } from "#core/converters/snapshot.converter";
import { qualifyWalks } from "#core/converters/walk.converter";
import { replaceFolderFiles } from "#core/persistence/asset.persistence";
import { withInherited } from "#core/loaders/heritage.loader";
import { writeCanonicalText } from "@govlab/canonical-write";

const deriveTree = async function deriveTree(
    source: AnatomyTreeDeclaration,
    scope: AnatomyScope,
): Promise<AnatomySnapshot> {
    const moduleDir = join(ROOT, source.folder);
    const report = { pruned: scope.pruned, root: ROOT };
    const { built, entries } = await buildModuleReport(moduleDir, scope.context, report);
    const tree = withInherited(moduleDir, readDeclaredTree(source, scope.pruned));
    const charts = await chartsOf(moduleDir, source.tab === TREE_TAB ? ANATOMY_TREE_LABEL : source.tab);
    const documents = documentsOf(tree, scope.host, moduleDir);
    const imports =
        scope.options.specifiers === null ? [] : await importEdgesOf(filesOf(tree), scope.options.specifiers);
    const snapshot = convertAnatomy(
        {
            cells: built.cells,
            charts,
            documents,
            entries,
            generatedSources: source.generatedSources,
            imports,
            report: built.report,
            tree,
            vectors: built.svgs,
        },
        scope.assets,
    );
    const { repository, tab } = source;
    const linked =
        repository === null
            ? snapshot
            : { ...snapshot, tree: withRepository(snapshot.tree, repository, source.generatedSources) };
    if (tab === TREE_TAB) {
        return linked;
    }
    const qualify = function qualify(path: string): string {
        return scope.options.qualifyPath(tab, path);
    };
    qualifyWalks(linked.tree, qualify, scope.assets);
    return qualifiedSnapshot(linked, qualify);
};

export const buildAnatomy = async function buildAnatomy(
    options: TreeOptions = UNQUALIFIED,
): Promise<readonly DerivedTree[]> {
    await extractConfigs();
    const pruned = await excludeMatcher(ROOT);
    const scope: AnatomyScope = {
        assets: createWalkAssets(),
        context: await buildContext(discoverModules(ROOT, pruned), { pruned, root: ROOT }),
        host: await docsHostFor(ROOT),
        options,
        pruned,
    };
    const declarations = treeDeclarations();
    await persistTreeDeclarations(declarations);
    const derived = await declarations.reduce<Promise<readonly DerivedTree[]>>(async (previous, source) => {
        const done = await previous;
        const snapshot = await deriveTree(source, scope);
        return [...done, { exportName: source.exportName, snapshot, tab: source.tab }];
    }, Promise.resolve([]));
    const sites = new Map<string, ReferenceSite>();
    const trees = referencedTrees(derived, options, scope.assets, sites);
    const baselineFile = absolutePath("app.baseline");
    const lost = lostReferences(readBaseline(baselineFile), sites);
    if (lost.length > 0) {
        const lines = lost.map((entry) =>
            lostReference(entry.path, entry.channel, entry.text, currentCandidates(entry, sites)),
        );
        throw new Error(lostReferencesLine(lines));
    }
    await persistBaseline(baselineFile, exactReferencesOf(sites));
    await writeCanonicalText(absolutePath("app.anatomy"), renderAnatomy(trees));
    const labels = new Map(declarations.map((declaration) => [declaration.tab, declaration.label]));
    const measures = anatomyMeasures(trees, (tab) => {
        const label = labels.get(tab);
        if (label === undefined) {
            throw new Error(unlabeledTree(tab));
        }
        return label;
    });
    await writeCanonicalText(absolutePath("app.anatomyMeasures"), renderAnatomyMeasures(measures));
    replaceFolderFiles(absolutePath("app.walks"), scope.assets.walks);
    replaceFolderFiles(absolutePath("app.sources"), scope.assets.sources);
    return trees;
};

export const deriveAnatomy = async function deriveAnatomy(options: TreeOptions = UNQUALIFIED): Promise<void> {
    const trees = await buildAnatomy(options);
    process.stdout.write(
        anatomyLine(
            trees.map((tree) => treeSummaryLine(tree, countFolders(tree.snapshot.tree))),
            {
                anatomy: relativePath("app.anatomy"),
                sources: relativePath("app.sources"),
                walks: relativePath("app.walks"),
            },
        ),
    );
};
```
