import type { DiagramContext, PackageShape } from "#types/figure.types"; import { LAYOUT_BY_SHAPE } from "#configuration/constants/figure.constants"; import type { ModuleDep } from "#types/diagram.types"; import { PACKAGE_FILE } from "#configuration/constants/document.constants"; import { deriveCodeGraph } from "#core/coordinators/code.coordinator"; import { deriveTypeGraph } from "#core/analyzers/definition.analyzer"; import { isPlainRecord } from "#core/predicates/record.predicate"; import { readJsonSafe } from "#core/loaders/base.loader"; import { resolve } from "node:path"; import { scopedDepNames } from "#core/converters/dependency.converter"; import { shapeOf } from "#core/classifiers/package.classifier"; export const loadPackage = function loadPackage(moduleDir: string): Record { const parsed = readJsonSafe(resolve(moduleDir, PACKAGE_FILE)); return isPlainRecord(parsed) ? parsed : {}; }; export const packageName = function packageName(pkg: Record, fallback: string): string { const { name } = pkg; return typeof name === "string" ? name : fallback; }; export const scriptsOf = function scriptsOf(pkg: Record): { scripts?: Record } { const declared = pkg["scripts"]; const entries = Object.entries(isPlainRecord(declared) ? declared : {}).filter( (entry): entry is [string, string] => typeof entry[1] === "string", ); return entries.length > 0 ? { scripts: Object.fromEntries(entries) } : {}; }; export const shapedContext = function shapedContext(shape: PackageShape): Pick { return { layout: LAYOUT_BY_SHAPE[shape], shape }; }; const moduleDepsFor = function moduleDepsFor(pkg: Record, name: string): ModuleDep[] { const deps = scopedDepNames(pkg["dependencies"]); return [{ deps, name }, ...deps.map((dep) => ({ deps: [], name: dep }))]; }; export const diagramContextFor = async function diagramContextFor( moduleDir: string, relPath: string, label?: string, ): Promise { const pkg = loadPackage(moduleDir); const name = label ?? packageName(pkg, relPath); const codeGraph = await deriveCodeGraph(moduleDir, pkg); const typeGraph = deriveTypeGraph(moduleDir, pkg); const scripts = scriptsOf(pkg); if (codeGraph === null && typeGraph.edges.length === 0 && scripts.scripts === undefined) { return null; } return { codeGraph, moduleDeps: moduleDepsFor(pkg, name), moduleName: name, typeGraph, ...shapedContext(shapeOf(moduleDir, pkg)), ...scripts, }; };