core/converters/specifier.converter.ts
core/converters/specifier.converter.ts is a file in Bane's Lab Build Scripts. 37 lines of code and 14 definitions.
import type { DiskFile } from "#types/structure.types";
import type { ImportEdge } from "@banes-lab/web/types/anatomy.types.js";
import type { SpecifierResolver } from "#types/anatomy.types";
import { ingestImports } from "@govlab/patterns";
const KEY_SEPARATOR = "::";
const PATH_SEPARATOR = "/";
const containerOfPath = function containerOfPath(path: string): string {
const cut = path.indexOf(PATH_SEPARATOR);
return cut === -1 ? "" : path.slice(0, cut);
};
const fileEdges = async function fileEdges(file: DiskFile, resolve: SpecifierResolver): Promise<string[]> {
const from = containerOfPath(file.path);
const bindings = await ingestImports(file.text, file.path);
return bindings.flatMap((binding) => {
const target = resolve(binding.source, file.path);
const to = target === null ? "" : containerOfPath(target);
return from !== "" && to !== "" && to !== from ? [from + KEY_SEPARATOR + to] : [];
});
};
const edgeOf = function edgeOf(key: string, count: number): ImportEdge {
const cut = key.indexOf(KEY_SEPARATOR);
return { count, from: key.slice(0, cut), to: key.slice(cut + KEY_SEPARATOR.length) };
};
export const importEdgesOf = async function importEdgesOf(
files: readonly DiskFile[],
resolverOf: (files: ReadonlySet<string>) => SpecifierResolver,
): Promise<ImportEdge[]> {
const resolve = resolverOf(new Set(files.map((file) => file.path)));
const counts = new Map<string, number>();
const keys = await Promise.all(files.map(async (file) => fileEdges(file, resolve)));
for (const key of keys.flat()) {
counts.set(key, (counts.get(key) ?? 0) + 1);
}
return [...counts.entries()]
.map(([key, count]) => edgeOf(key, count))
.sort((a, b) => a.from.localeCompare(b.from) || a.to.localeCompare(b.to));
};