import { ANATOMY_CHAPTER, DATA_FLOW_TAG, FINDINGS_TAG, FLOW_TAG, IMPORTS_TAG, LAYERS_TAG, LEGEND_TAG, MEASUREMENTS_TAG, SAMPLE_WALK_TAG, STRUCTURE_TAG, } from "#configuration/strings/anatomy.strings"; import type { AnatomyFolder, AnatomyMetrics, AnatomySnapshot, AnatomyStats } from "#types/anatomy.types"; import { BLANK_LABEL, BYTES_LABEL, CALLABLE_LABEL, DEFINITIONS_LABEL, EDGES_LABEL, EXPORTED_LABEL, FILES_LABEL, FINDINGS_CLEAN, FINDINGS_LABEL, FINDING_SUFFIX, FLOWS_LABEL, FLOW_SUFFIX, LINES_LABEL, MAX_IN_LABEL, MAX_OUT_LABEL, NONE_FOUND, NO_ANOMALIES, RESOLUTION_LABEL, UNRESOLVED_LABEL, } from "#configuration/strings/folder.strings"; import type { Block, Metric } from "#types/block.types"; import { CHART_TAGS, KEY_SEPARATOR, STATS_SEPARATOR, WIDE_CHARTS } from "#configuration/constants/anatomy.constants"; import { DERIVED_SECTION_ID, DIAGNOSES_SECTION_ID, PARTS_SECTION_ID, SPINE_SECTION_ID, WALK_SECTION_ID, } from "#core/ids/anatomy.ids"; import { LINE_BREAK, TEXT_LANGUAGE } from "#configuration/constants/code.constants"; import { importsDiagram, structureDiagram } from "#domain/converters/graph.converter"; import { LABEL_SEPARATOR } from "#configuration/strings/ontology.strings"; import type { Section } from "#types/document.types"; import { codeOf } from "#domain/converters/ontology.converter"; const metric = function metric(label: string, value: number | string): Metric { return { label, value: String(value) }; }; const tallyMetrics = function tallyMetrics( counts: Readonly>, suffix: string, emptyLabel: string, emptyValue: string = NONE_FOUND, ): Metric[] { const sorted = Object.entries(counts).sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])); return sorted.length === 0 ? [metric(emptyLabel, emptyValue)] : sorted.map(([key, count]) => metric(key + suffix, count)); }; export const statsMetrics = function statsMetrics(stats: AnatomyStats): Metric[] { return [ metric(FILES_LABEL, stats.files), metric(LINES_LABEL, stats.lines.code), metric(BLANK_LABEL, stats.lines.blank), metric(BYTES_LABEL, stats.bytes), metric(DEFINITIONS_LABEL, stats.definitions), metric(EXPORTED_LABEL, stats.exported), metric(CALLABLE_LABEL, stats.callable), metric(EDGES_LABEL, stats.edges), ...tallyMetrics(stats.flows, FLOW_SUFFIX, FLOWS_LABEL), ...tallyMetrics(stats.findings, FINDING_SUFFIX, FINDINGS_LABEL, NO_ANOMALIES), ]; }; const moduleMetrics = function moduleMetrics(metrics: AnatomyMetrics, stats: AnatomyStats): Metric[] { return [ metric(FILES_LABEL, stats.files), metric(LINES_LABEL, stats.lines.code), metric(DEFINITIONS_LABEL, metrics.definitions), metric(EXPORTED_LABEL, metrics.exported), metric(CALLABLE_LABEL, metrics.callable), metric(EDGES_LABEL, metrics.edges), metric(UNRESOLVED_LABEL, metrics.unresolvedCalls), metric(RESOLUTION_LABEL, metrics.resolutionRate), metric(MAX_IN_LABEL, metrics.maxInDegree), metric(MAX_OUT_LABEL, metrics.maxOutDegree), ...tallyMetrics(metrics.flows, FLOW_SUFFIX, FLOWS_LABEL), ...tallyMetrics(metrics.findings, FINDING_SUFFIX, FINDINGS_LABEL, NO_ANOMALIES), ]; }; const chartBlocks = function chartBlocks(snapshot: AnatomySnapshot, ids: readonly string[]): Block[] { return ids.flatMap((id) => { const chart = snapshot.charts.find((candidate) => candidate.id === id); const [part] = chart?.parts ?? []; const caption = CHART_TAGS.get(id); return chart === undefined || part === undefined || caption === undefined ? [] : [{ caption, kind: "mermaid", text: part.text, wide: WIDE_CHARTS.has(id) }]; }); }; const INDENT = " "; const layersText = function layersText(folder: AnatomyFolder, depth = 0): string[] { const own = folder.path === "" ? [] : [INDENT.repeat(depth) + folder.name + (folder.layer === null ? "" : LABEL_SEPARATOR + folder.layer)]; return [...own, ...folder.folders.flatMap((child) => layersText(child, folder.path === "" ? depth : depth + 1))]; }; const findingsText = function findingsText(snapshot: AnatomySnapshot): string { if (snapshot.findings.length === 0) { return FINDINGS_CLEAN; } return snapshot.findings .map((finding) => [finding.kind, finding.severity, finding.file + KEY_SEPARATOR + finding.name, finding.detail].join( STATS_SEPARATOR, ), ) .join(LINE_BREAK); }; const legendText = function legendText(snapshot: AnatomySnapshot): string { return snapshot.states.map((state) => state.state + LABEL_SEPARATOR + state.text).join(LINE_BREAK); }; const walkFolders = function walkFolders(folder: AnatomyFolder): AnatomyFolder[] { return [ ...(folder.walk === null || folder.files.length === 0 ? [] : [folder]), ...folder.folders.flatMap(walkFolders), ]; }; const sampleWalk = function sampleWalk(snapshot: AnatomySnapshot): Block[] { const [smallest] = walkFolders(snapshot.tree).sort((a, b) => (a.walk?.steps ?? 0) - (b.walk?.steps ?? 0)); return smallest?.walk === null || smallest === undefined ? [] : [{ caption: SAMPLE_WALK_TAG, kind: "walk", walk: smallest.walk }]; }; const panelsOf = function panelsOf(snapshot: AnatomySnapshot): ReadonlyMap { return new Map([ [ DERIVED_SECTION_ID, [ { caption: MEASUREMENTS_TAG, kind: "metric", metrics: moduleMetrics(snapshot.metrics, snapshot.tree.stats), wide: true, }, { caption: IMPORTS_TAG, kind: "mermaid", text: importsDiagram(snapshot), wide: true }, ], ], [ PARTS_SECTION_ID, [ { caption: STRUCTURE_TAG, kind: "mermaid", text: structureDiagram(snapshot) }, ...chartBlocks( snapshot, [...CHART_TAGS.keys()].filter((id) => CHART_TAGS.get(id) === FLOW_TAG), ), ], ], [ SPINE_SECTION_ID, [ codeOf(LAYERS_TAG, layersText(snapshot.tree).join(LINE_BREAK), TEXT_LANGUAGE), ...chartBlocks( snapshot, [...CHART_TAGS.keys()].filter((id) => CHART_TAGS.get(id) === DATA_FLOW_TAG), ), ], ], [DIAGNOSES_SECTION_ID, [codeOf(FINDINGS_TAG, findingsText(snapshot), TEXT_LANGUAGE), ...sampleWalk(snapshot)]], [WALK_SECTION_ID, [codeOf(LEGEND_TAG, legendText(snapshot), TEXT_LANGUAGE)]], ]); }; const withPanels = function withPanels(section: Section, panels: readonly Block[]): Section { const last = section.subsections.at(-1); if (last === undefined) { return section; } return { ...section, subsections: [...section.subsections.slice(0, -1), { ...last, blocks: [...(last.blocks ?? []), ...panels] }], }; }; export const anatomyChapter = function anatomyChapter(snapshot: AnatomySnapshot): readonly Section[] { const panels = panelsOf(snapshot); return ANATOMY_CHAPTER.map((section) => withPanels(section, panels.get(section.id) ?? [])); };