core/converters/graph.code.converter.ts
core/converters/graph.code.converter.ts is a file in Bane's Lab Build Scripts. 95 lines of code and 23 definitions.
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;
};