# core/converters/graph.code.converter.ts

> 95 lines of code and 23 definitions.

Tree: Bane's Lab Build Scripts
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/build-scripts#file-build-scripts-core-converters-graph-code-converter-ts
Source text: https://banes-lab.com/source/build-scripts/core/converters/graph.code.converter.ts.txt

Listed in [core/converters](https://banes-lab.com/api/source/build-scripts/core/converters.md), after [core/converters/grammar.reference.converter.ts](https://banes-lab.com/source/build-scripts/core/converters/grammar.reference.converter.ts.md) and before [core/converters/graph.concept.converter.ts](https://banes-lab.com/source/build-scripts/core/converters/graph.concept.converter.ts.md).

## Definitions

- `numbersIn` (lexical_declaration, line 11, exported)
- `citationOf` (lexical_declaration, line 93, exported)
- `tabOrder` (lexical_declaration, line 40)
- `siteCodes` (lexical_declaration, line 71, exported)
- `PAGE_LETTERS` (lexical_declaration, line 9)
- `graph` (lexical_declaration, line 12, exported)
- `nodes` (lexical_declaration, line 13, exported)
- `sectionNumbers` (lexical_declaration, line 23, exported)
- `onRoute` (lexical_declaration, line 27, exported)
- `numbers` (lexical_declaration, line 28, exported)
- `position` (lexical_declaration, line 31, exported)
- `tabOf` (lexical_declaration, line 45)
- `codes` (lexical_declaration, line 46)
- `tab` (lexical_declaration, line 48)
- `taken` (lexical_declaration, line 53)
- `next` (lexical_declaration, line 54, exported)
- `unrouted` (lexical_declaration, line 55)
- `tabs` (lexical_declaration, line 76, exported)
- `pageOfTab` (lexical_declaration, line 77, exported)
- `ordered` (lexical_declaration, line 81, exported)
- `page` (lexical_declaration, line 84, exported)
- `number` (lexical_declaration, line 98, exported)
- `code` (lexical_declaration, line 99, exported)

## Contained in

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

## Uses

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

## Used by

- [core/converters/graph.site.converter.ts](https://banes-lab.com/source/build-scripts/core/converters/graph.site.converter.ts.md)
- [core/coordinators/catalog.coordinator.ts](https://banes-lab.com/source/build-scripts/core/coordinators/catalog.coordinator.ts.md)

## Linked from

- [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)

## Source

```typescript
import { CHAPTER_PREFIX } from "#configuration/constants/graph.constants";
import type { DiscoveredRoute } from "#types/site.types";
import type { RouteStop } from "#types/learning.types";
import type { SectionPlan } from "#types/section.types";
import type { SiteCodes } from "#types/graph.types";
import { chunkCode } from "#core/converters/learning.converter";
import { isRecord } from "#core/selectors/base.selector";

const PAGE_LETTERS = "abcdefghijklmnopqrstuvwxyz";

export const numbersIn = function numbersIn(report: unknown): ReadonlyMap<string, string> {
    const graph = isRecord(report) ? report["graph"] : null;
    const nodes = isRecord(graph) && Array.isArray(graph["nodes"]) ? graph["nodes"] : [];
    return new Map(
        nodes.flatMap((node: unknown) =>
            isRecord(node) && typeof node["ref"] === "string" && typeof node["number"] === "string"
                ? [[node["ref"], node["number"]] as const]
                : [],
        ),
    );
};

export const sectionNumbers = function sectionNumbers(
    plans: readonly SectionPlan[],
    stops: readonly RouteStop[],
): ReadonlyMap<string, string> {
    const onRoute = new Map(stops.map((stop) => [CHAPTER_PREFIX + stop.path, stop.position]));
    const numbers = new Map<string, string>();
    let next = stops.length;
    for (const plan of plans) {
        const position = onRoute.get(plan.identity.ref);
        if (position === undefined) {
            next += 1;
        }
        numbers.set(plan.identity.ref, String(position ?? next));
    }
    return numbers;
};

const tabOrder = function tabOrder(
    routes: readonly DiscoveredRoute[],
    plans: readonly SectionPlan[],
    stops: readonly RouteStop[],
): ReadonlyMap<string, string> {
    const tabOf = new Map(plans.map((plan) => [plan.identity.ref, plan.tab.path]));
    const codes = new Map<string, string>();
    for (const stop of stops) {
        const tab = tabOf.get(CHAPTER_PREFIX + stop.path);
        if (tab !== undefined && !codes.has(tab)) {
            codes.set(tab, stop.code);
        }
    }
    const taken = new Set(codes.values());
    let next = 0;
    const unrouted = [
        ...new Set([
            ...routes.flatMap((route) => (route.tab === null ? [] : [route.path])),
            ...plans.map((plan) => plan.tab.path),
        ]),
    ].filter((tab) => !codes.has(tab));
    for (const tab of unrouted) {
        while (taken.has(chunkCode(next))) {
            next += 1;
        }
        codes.set(tab, chunkCode(next));
        taken.add(chunkCode(next));
    }
    return codes;
};

export const siteCodes = function siteCodes(
    routes: readonly DiscoveredRoute[],
    plans: readonly SectionPlan[],
    stops: readonly RouteStop[],
): SiteCodes {
    const tabs = tabOrder(routes, plans, stops);
    const pageOfTab = new Map([
        ...routes.flatMap((route) => (route.tab === null ? [] : [[route.path, route.page] as const])),
        ...plans.map((plan) => [plan.tab.path, plan.page.page] as const),
    ]);
    const ordered = [
        ...new Set([
            ...[...tabs.keys()].flatMap((tab) => {
                const page = pageOfTab.get(tab);
                return page === undefined ? [] : [page];
            }),
            ...routes.map((route) => route.page),
        ]),
    ];
    return { pages: new Map(ordered.map((page, at) => [page, PAGE_LETTERS.charAt(at) || chunkCode(at)])), tabs };
};

export const citationOf = function citationOf(
    plan: SectionPlan,
    numbers: ReadonlyMap<string, string>,
    codes: SiteCodes,
): string | null {
    const number = numbers.get(plan.identity.ref);
    const code = codes.tabs.get(plan.tab.path);
    return number === undefined || code === undefined ? null : code + number;
};
```
