core/loaders/source.loader.ts
core/loaders/source.loader.ts is a file in GovLab Patterns. 42 lines of code and 15 definitions.
import type { FileEntry, Pruned } from "#types/package.types";
import { existsSync, readFileSync } from "node:fs";
import { relative, sep } from "node:path";
import { sourceFiles, testFilesOf } from "#core/loaders/package.loader";
import type { IngestFile } from "#types/code.types";
import { MEANINGFUL_STATES } from "#configuration/constants/walk.constants";
import { identifierNames } from "#core/analyzers/syntax.analyzer";
import { ingestFile } from "#core/parsers/code.parser";
import { namedWalk } from "#core/converters/walk.converter";
import { stateOf } from "#core/classifiers/syntax.classifier";
const PATH_SEP = "/";
const queue: { tail: Promise<unknown> } = { tail: Promise.resolve() };
export const readSourceOrEmpty = function readSourceOrEmpty(file: string): string {
return existsSync(file) ? readFileSync(file, "utf8") : "";
};
export const parseFile = async function parseFile(file: string): Promise<IngestFile> {
const run = queue.tail.then(async () => ingestFile(readSourceOrEmpty(file), file));
queue.tail = Promise.allSettled([run]);
return run;
};
export const settleParses = async function settleParses(): Promise<void> {
await queue.tail;
};
const isMeaningful = function isMeaningful(record: Record<string, unknown>): boolean {
const { nodeType } = record;
return MEANINGFUL_STATES.has(stateOf(typeof nodeType === "string" ? nodeType : ""));
};
const entryFor = function entryFor(file: string, moduleDir: string, parsed: IngestFile): FileEntry {
const rel = relative(moduleDir, file).split(sep).join(PATH_SEP);
const records = parsed.records.map((record) => ({ ...record, file: rel }));
const symbols = parsed.symbols.map((symbol) => ({ ...symbol, file: rel }));
return { records, rel, symbols, walk: namedWalk(records.filter(isMeaningful), symbols) };
};
export const entriesFor = async function entriesFor(moduleDir: string, pruned: Pruned): Promise<FileEntry[]> {
return Promise.all(
sourceFiles(moduleDir, pruned).map(async (file) => entryFor(file, moduleDir, await parseFile(file))),
);
};
export const testUsesOf = async function testUsesOf(moduleDir: string, pruned: Pruned): Promise<Set<string>> {
const parsed = await Promise.all(testFilesOf(moduleDir, pruned).map(async (file) => parseFile(file)));
return new Set(parsed.flatMap((entry) => identifierNames(entry.records)));
};