core/validators/catalog.walk.validator.ts

core/validators/catalog.walk.validator.ts is a file in Bane's Lab Build Scripts. 42 lines of code and 12 definitions.

import { fileOfAddress, queryIndex } from "#core/resolvers/catalog.resolver";
import type { Finding } from "#types/validation.types";
import { isRecord } from "#core/selectors/base.selector";
import { join } from "node:path";
import { readFileSync } from "node:fs";
import { undeclaredRelation } from "#configuration/strings/catalog.strings";

const RELATIONS_KEY = "relations";
const RELATION_KEY = "relation";

const jsonAt = function jsonAt(outDir: string, file: string): unknown {
    return JSON.parse(readFileSync(join(outDir, file), "utf8"));
};

const relationNamesIn = function relationNamesIn(value: unknown): readonly string[] {
    const groups = isRecord(value) ? value[RELATIONS_KEY] : undefined;
    if (!Array.isArray(groups)) {
        return [];
    }
    return groups.flatMap((group: unknown) => {
        const name = isRecord(group) ? group[RELATION_KEY] : undefined;
        return typeof name === "string" ? [name] : [];
    });
};

const declaredRelations = function declaredRelations(
    outDir: string,
    present: ReadonlySet<string>,
): ReadonlySet<string> {
    const queryFile = fileOfAddress(queryIndex().json);
    const contract: unknown = present.has(queryFile) ? jsonAt(outDir, queryFile) : null;
    const listed = isRecord(contract) ? contract[RELATIONS_KEY] : undefined;
    return new Set(Array.isArray(listed) ? listed.filter((name) => typeof name === "string") : []);
};

export const walkFindings = function walkFindings(
    outDir: string,
    files: readonly string[],
    present: ReadonlySet<string>,
): Finding[] {
    const declared = declaredRelations(outDir, present);
    return files.flatMap((file) =>
        [...new Set(relationNamesIn(jsonAt(outDir, file)))]
            .filter((name) => !declared.has(name))
            .map((name) => ({ file, message: undeclaredRelation(name) })),
    );
};