core/coordinators/catalog.coordinator.ts

core/coordinators/catalog.coordinator.ts is a file in GovLab Quality. 62 lines of code and 15 definitions.

import type { CatalogProducer, CatalogRequest, CatalogWriter, KnobEntry } from "#types/catalog.types";
import { REGENERATED, productLine, unknownProducer } from "#configuration/strings/catalog.strings";
import { catalogWriter, writeKnobs, writeProduct } from "#core/persistence/catalog.persistence";
import { discoverSteps, runSteps } from "#core/pipelines/catalog.pipeline";
import { loadProducers } from "#core/loaders/producer.loader";

const EVERY_PRODUCER = "all";
const SUMMARY_INDENT = 2;

const select = function select(producers: readonly CatalogProducer[], names: readonly string[]): CatalogProducer[] {
    if (names.includes(EVERY_PRODUCER)) {
        return [...producers];
    }
    const known = new Map(producers.map((producer) => [producer.name, producer]));
    return names.map((name) => {
        const producer = known.get(name);
        if (!producer) {
            throw new Error(unknownProducer(name, [...known.keys()].join(", ")));
        }
        return producer;
    });
};

const refreshRules = async function refreshRules(
    producers: readonly CatalogProducer[],
    writer: CatalogWriter,
    write: (line: string) => void,
): Promise<void> {
    const [producer, ...rest] = producers;
    if (producer === undefined) {
        return;
    }
    const products = await producer.produce();
    await Promise.all(products.map(async (product) => writeProduct(writer, product)));
    for (const product of products) {
        write(productLine(product.source, JSON.stringify(product.summary, null, SUMMARY_INDENT)));
    }
    await refreshRules(rest, writer, write);
};

const refreshKnobs = async function refreshKnobs(
    producers: readonly CatalogProducer[],
    writer: CatalogWriter,
): Promise<void> {
    const entries = await Promise.all(
        producers.flatMap((producer) =>
            producer.knobs ? [producer.knobs().then((knobs): [string, KnobEntry[]] => [producer.name, knobs])] : [],
        ),
    );
    if (entries.length > 0) {
        await writeKnobs(writer, new Map(entries));
    }
};

export const regenerateCatalog = async function regenerateCatalog(
    request: CatalogRequest,
    write: (line: string) => void,
): Promise<void> {
    const producers = await loadProducers();
    const writer = await catalogWriter();
    const requested = select(producers, request.rules);
    const builds = producers.filter((producer) => producer.refresh === "build" && !requested.includes(producer));
    await refreshRules([...builds, ...requested], writer, write);
    await refreshKnobs(select(producers, request.knobs), writer);
    await runSteps(await discoverSteps(), writer, write);
    write(REGENERATED);
};