# core/converters/catalog.converter.ts

> 70 lines of code and 13 definitions.

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

Listed in [core/converters](https://banes-lab.com/api/source/docs/core/converters.md), before [core/converters/dependency.converter.ts](https://banes-lab.com/source/docs/core/converters/dependency.converter.ts.md).

## Definitions

- `indexBy` (lexical_declaration, line 40)
- `key` (lexical_declaration, line 73, exported)
- `nodeOf` (lexical_declaration, line 11)
- `catalogPayload` (lexical_declaration, line 51, exported)
- `catalogNodes` (lexical_declaration, line 20, exported)
- `NAME_FIELD` (lexical_declaration, line 9)
- `relDoc` (lexical_declaration, line 12)
- `{ fields }` (lexical_declaration, line 16)
- `entryOf` (lexical_declaration, line 24)
- `index` (lexical_declaration, line 44)
- `docs` (lexical_declaration, line 55, exported)
- `concernGroups` (lexical_declaration, line 70, exported)
- `groups` (lexical_declaration, line 71, exported)

## Contained in

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

## Uses

- [core/converters/document.converter.ts](https://banes-lab.com/source/docs/core/converters/document.converter.ts.md)

## Linked from

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

## Source

```typescript
import type { CatalogDocEntry, CatalogPayload } from "#types/index.types";
import type { DocGraph, DocNode } from "#types/document.types";
import type { CatalogContext } from "#types/environment.types";
import { MODULE_BARREL_KEY } from "#configuration/constants/document.constants";
import { docNodeOf } from "#core/converters/document.converter";
import { parseFrontmatter } from "#core/parsers/metadata.parser";
import { readTextSafe } from "#core/loaders/base.loader";

const NAME_FIELD = "name";

const nodeOf = function nodeOf(context: CatalogContext, doc: string): DocNode[] {
    const relDoc = context.relative(doc);
    if (!relDoc.startsWith(context.rootPrefix)) {
        return [];
    }
    const { fields } = parseFrontmatter(readTextSafe(doc) ?? "");
    return typeof fields[NAME_FIELD] === "string" ? [docNodeOf(relDoc, fields)] : [];
};

export const catalogNodes = function catalogNodes(context: CatalogContext): DocNode[] {
    return context.docs.flatMap((doc) => nodeOf(context, doc));
};

const entryOf = function entryOf(node: DocNode, superseded: ReadonlySet<string>): CatalogDocEntry {
    return {
        concern: node.concern,
        dependsOn: node.dependsOn,
        governs: node.governs,
        links: node.links,
        name: node.name,
        path: node.relPath,
        status: node.status ?? "",
        summary: node.summary,
        superseded: superseded.has(node.name),
        supersedes: node.supersedes,
        type: node.type,
    };
};

const indexBy = function indexBy(
    entries: readonly CatalogDocEntry[],
    key: (entry: CatalogDocEntry) => string,
): Record<string, string[]> {
    const index: Record<string, string[]> = {};
    for (const entry of entries) {
        index[key(entry)] = [...(index[key(entry)] ?? []), entry.name];
    }
    return index;
};

export const catalogPayload = function catalogPayload(
    graph: DocGraph,
    superseded: ReadonlySet<string>,
): CatalogPayload {
    const docs = graph.nodes
        .map((node) => entryOf(node, superseded))
        .toSorted((left, right) => left.name.localeCompare(right.name));
    return {
        byConcern: indexBy(docs, (entry) => entry.concern),
        byStatus: indexBy(docs, (entry) => entry.status),
        byType: indexBy(docs, (entry) => entry.type),
        cycles: graph.cycles,
        deadEdges: graph.deadEdges,
        docs,
        duplicateNames: graph.duplicateNames,
        superseded: graph.superseded,
    };
};

export const concernGroups = function concernGroups(graph: DocGraph): Map<string, DocNode[]> {
    const groups = new Map<string, DocNode[]>();
    for (const node of graph.nodes) {
        const key = node.concern.length > 0 ? node.concern : MODULE_BARREL_KEY;
        groups.set(key, [...(groups.get(key) ?? []), node]);
    }
    return groups;
};
```
