core/converters/anatomy.converter.ts

core/converters/anatomy.converter.ts is a file in Bane's Lab Build Scripts. 155 lines of code and 25 definitions.

import type { AnatomyFile, AnatomyFolder, AnatomySnapshot, DocumentView } from "@banes-lab/web/types/anatomy.types.js";
import type {
    AnatomyInputs,
    AnatomyLookups,
    DerivedTree,
    RecordReader,
    ReferenceReader,
    ReferenceSite,
    TreeOptions,
    WalkAssets,
} from "#types/anatomy.types";
import type { DiskFile, DiskFolder } from "#types/structure.types";
import { STATE_LEGEND, syntaxDistribution } from "@govlab/patterns";
import { fileLayerOf, folderLayerOf, slotsOf, sumStats } from "#core/converters/structure.converter";
import { fileStatsOf, findingView } from "#core/converters/report.converter";
import { fileWalkOf, folderWalkOf, recordsAssetOf, referencesAssetOf, sourceOf } from "#core/converters/walk.converter";
import { lookupsOf, parsedPartsOf } from "#core/converters/anatomy.index.converter";
import { isPublished } from "#core/predicates/exclusion.predicate";

const PATH_SEPARATOR = "/";

const isHiddenSource = function isHiddenSource(
    file: DiskFile,
    document: DocumentView | null,
    generatedSources: boolean,
): boolean {
    return file.excluded !== undefined || (file.generated && document === null && !generatedSources);
};

const fileOf = function fileOf(lookups: AnatomyLookups, file: DiskFile, root?: string): AnatomyFile {
    const { definitions, entry, findings } = parsedPartsOf(lookups, file);
    const slots = slotsOf(file.name, root);
    const document = lookups.documents.get(file.path) ?? null;
    const hidden = isHiddenSource(file, document, lookups.inputs.generatedSources === true);
    return {
        definitions,
        distribution: syntaxDistribution(entry?.records ?? []),
        document,
        ...(file.excluded === undefined ? {} : { excluded: file.excluded }),
        findings,
        generated: file.generated,
        id: file.path,
        inherited: file.inherited,
        layer: fileLayerOf(slots, root),
        name: file.name,
        path: file.path,
        slots,
        source: hidden ? null : sourceOf(lookups.assets, file.text),
        stats: fileStatsOf(file, definitions, lookups.edgesByFile.get(file.path) ?? 0, findings),
        walk: fileWalkOf(lookups.assets, entry, lookups.flagged),
    };
};

const folderOf = function folderOf(lookups: AnatomyLookups, folder: DiskFolder): AnatomyFolder {
    const folders = folder.folders.map((child) => folderOf(lookups, child));
    const files = folder.files.map((file) => fileOf(lookups, file, folder.governedBy));
    return {
        files,
        findings: [...folders.flatMap((child) => child.findings), ...files.flatMap((file) => file.findings)],
        folders,
        id: folder.path,
        layer: folderLayerOf(folder),
        name: folder.name,
        path: folder.path,
        role: folder.role,
        stats: sumStats([...folders.map((child) => child.stats), ...files.map((file) => file.stats)]),
        walk: folderWalkOf(lookups.assets, folder.path, lookups.inputs.vectors, lookups.inputs.cells),
    };
};

export const convertAnatomy = function convertAnatomy(inputs: AnatomyInputs, assets: WalkAssets): AnatomySnapshot {
    const lookups = lookupsOf(inputs, assets);
    return {
        charts: inputs.charts,
        findings: inputs.report.findings.map(findingView),
        imports: inputs.imports,
        metrics: inputs.report.metrics,
        states: STATE_LEGEND.map((item) => ({ state: item.state, text: item.text })),
        tree: folderOf(lookups, inputs.tree),
        unresolvedCalls: inputs.report.unresolvedCalls,
    };
};

const repositoryPath = function repositoryPath(base: string, path: string): string {
    return path.length === 0 ? base : base + PATH_SEPARATOR + path;
};

export const withRepository = function withRepository(
    folder: AnatomyFolder,
    base: string,
    generatedSources: boolean,
): AnatomyFolder {
    return {
        ...folder,
        files: folder.files.map((file) =>
            isPublished(file, generatedSources) ? { ...file, repository: repositoryPath(base, file.path) } : file,
        ),
        folders: folder.folders.map((child) => withRepository(child, base, generatedSources)),
        repository: repositoryPath(base, folder.path),
    };
};

interface ReferenceScope {
    readonly assets: WalkAssets;
    readonly read: ReferenceReader;
    readonly sites: Map<string, ReferenceSite>;
}

const withReferences = function withReferences(folder: AnatomyFolder, scope: ReferenceScope): AnatomyFolder {
    return {
        ...folder,
        files: folder.files.map((file) => {
            const text = file.source === null ? undefined : scope.assets.sources.get(file.source);
            if (text === undefined) {
                return file;
            }
            const references = scope.read(file.path, text, file.document !== null);
            scope.sites.set(file.path, { references, source: text });
            return { ...file, references: referencesAssetOf(scope.assets, references) };
        }),
        folders: folder.folders.map((child) => withReferences(child, scope)),
    };
};

const withRecords = function withRecords(folder: AnatomyFolder, read: RecordReader, assets: WalkAssets): AnatomyFolder {
    return {
        ...folder,
        files: folder.files.map((file) => ({ ...file, records: recordsAssetOf(assets, read.file(file)) })),
        folders: folder.folders.map((child) => withRecords(child, read, assets)),
        records: recordsAssetOf(assets, read.folder(folder)),
    };
};

const recordedTrees = function recordedTrees(
    trees: readonly DerivedTree[],
    options: TreeOptions,
    assets: WalkAssets,
): readonly DerivedTree[] {
    if (options.record === null) {
        return trees;
    }
    const read = options.record(trees.map((tree) => tree.snapshot.tree));
    return trees.map((tree) => ({
        ...tree,
        snapshot: { ...tree.snapshot, tree: withRecords(tree.snapshot.tree, read, assets) },
    }));
};

export const referencedTrees = function referencedTrees(
    trees: readonly DerivedTree[],
    options: TreeOptions,
    assets: WalkAssets,
    sites: Map<string, ReferenceSite>,
): readonly DerivedTree[] {
    if (options.refer === null) {
        return recordedTrees(trees, options, assets);
    }
    const scope = { assets, read: options.refer(trees.map((tree) => tree.snapshot.tree)), sites };
    const referenced = trees.map((tree) => ({
        ...tree,
        snapshot: { ...tree.snapshot, tree: withReferences(tree.snapshot.tree, scope) },
    }));
    return recordedTrees(referenced, options, assets);
};

export const countFolders = function countFolders(folder: AnatomySnapshot["tree"]): number {
    return folder.folders.reduce((sum, child) => sum + 1 + countFolders(child), 0);
};