import { ANATOMY_CONTAINER_ICON, FOLDER_SECTION_ICON } from "#configuration/icons/anatomy.icons";
import type { AnatomyFile, AnatomyFolder, AnatomySnapshot, DefinitionRef, DefinitionView } from "#types/anatomy.types";
import {
CALLED_BY_LABEL,
CALLS_LABEL,
CONCERN_LABEL,
DOCUMENT_TITLE,
FILE_WALK_CAPTION,
FOLDER_INTRO_DEFINITIONS,
FOLDER_INTRO_EDGES,
FOLDER_INTRO_FILES,
FOLDER_INTRO_HOLDING,
FOLDER_INTRO_LAYER_TAIL,
FOLDER_INTRO_LEAD,
FOLDER_INTRO_LINES,
FOLDER_INTRO_ON_LAYER,
FOLDER_WALK_CAPTION,
GENERATED_LABEL,
INHERITED_LABEL,
IN_LABEL,
LAYER_LABEL,
LINE_MARK,
OUT_LABEL,
RARE_SYNTAX_LABEL,
ROOT_LABEL,
SOURCE_TITLE,
STATS_LABEL,
SUBJECT_LABEL,
SYNTAX_LABEL,
TREE_LABEL,
UNPARSED_LABEL,
VARIANT_LABEL,
} from "#configuration/strings/folder.strings";
import { LABEL_SEPARATOR, LIST_SEPARATOR, NONE_LABEL } from "#configuration/strings/ontology.strings";
import type { Section, Subsection, Tab } from "#types/document.types";
import { chips, glossary, labelled, row } from "#domain/converters/ontology.converter";
import { documentBlocks, documentChips } from "#domain/converters/document.converter";
import { fileId, folderId, languageOf, nodeHref } from "#domain/converters/source.converter";
import type { Block } from "#types/block.types";
import { STATS_SEPARATOR } from "#configuration/constants/anatomy.constants";
import { TREE_TAB } from "#core/ids/anatomy.ids";
import { statsMetrics } from "#domain/converters/anatomy.fragment.converter";
const BREAK = "
";
const refLink = function refLink(ref: DefinitionRef): string {
return `${ref.name}`;
};
const refList = function refList(refs: readonly DefinitionRef[]): string {
return refs.length === 0 ? NONE_LABEL : refs.map(refLink).join(LIST_SEPARATOR);
};
const mark = function mark(label: string, value: string): string {
return `${label} ${value}`;
};
const definitionRow = function definitionRow(definition: DefinitionView): ReturnType {
const head = [
`${definition.flow}`,
mark(IN_LABEL, String(definition.inDegree)),
mark(OUT_LABEL, String(definition.outDegree)),
].join(STATS_SEPARATOR);
const description = [
head,
CALLS_LABEL + LABEL_SEPARATOR + refList(definition.callees),
CALLED_BY_LABEL + LABEL_SEPARATOR + refList(definition.callers),
].join(BREAK);
return row(definition.name + LINE_MARK + String(definition.line), description);
};
const fileChips = function fileChips(file: AnatomyFile): Block {
return chips([
file.slots === null ? UNPARSED_LABEL : labelled(SUBJECT_LABEL, file.slots.subject),
file.slots === null ? null : labelled(CONCERN_LABEL, file.slots.concern),
file.slots === null ? null : labelled(VARIANT_LABEL, file.slots.variant),
labelled(LAYER_LABEL, file.layer),
file.generated ? GENERATED_LABEL : null,
file.inherited ? INHERITED_LABEL : null,
...documentChips(file.document),
]);
};
const distributionBlocks = function distributionBlocks(file: AnatomyFile): Block[] {
const kinds = file.distribution.invariants.map((stat) => ({ label: stat.type, value: String(stat.count) }));
const rare = file.distribution.variants.map((stat) => ({ label: stat.type, value: String(stat.count) }));
return [
...(kinds.length === 0 ? [] : [{ caption: SYNTAX_LABEL, kind: "metric" as const, metrics: kinds }]),
...(rare.length === 0 ? [] : [{ caption: RARE_SYNTAX_LABEL, kind: "metric" as const, metrics: rare }]),
];
};
const fileBlocks = function fileBlocks(file: AnatomyFile): Block[] {
return [
fileChips(file),
{ caption: STATS_LABEL, kind: "metric" as const, metrics: statsMetrics(file.stats) },
...(file.definitions.length === 0 ? [] : [glossary(file.definitions.map(definitionRow))]),
...(file.document === null ? [] : documentBlocks(file.document)),
...(file.walk === null ? [] : [{ caption: FILE_WALK_CAPTION, kind: "walk" as const, walk: file.walk }]),
...distributionBlocks(file),
...(file.source === null || file.document === null
? []
: [{ kind: "markdown" as const, path: file.path, source: file.source, title: DOCUMENT_TITLE }]),
...(file.source === null
? []
: [
{
kind: "source" as const,
language: languageOf(file.name),
path: file.path,
source: file.source,
title: SOURCE_TITLE,
},
]),
];
};
const fileRecord = function fileRecord(file: AnatomyFile): Subsection {
return { blocks: fileBlocks(file), id: fileId(file.path), title: file.name };
};
const count = function count(value: number): string {
return `${String(value)}`;
};
const folderIntro = function folderIntro(folder: AnatomyFolder): string {
const layer =
folder.layer === null
? ""
: `${FOLDER_INTRO_ON_LAYER}${folder.layer}${FOLDER_INTRO_LAYER_TAIL}`;
const counts = [
count(folder.stats.files) + FOLDER_INTRO_FILES,
count(folder.stats.lines.code) + FOLDER_INTRO_LINES,
count(folder.stats.definitions) + FOLDER_INTRO_DEFINITIONS,
count(folder.stats.edges) + FOLDER_INTRO_EDGES,
].join("");
return `${FOLDER_INTRO_LEAD}${folder.role}${layer}${FOLDER_INTRO_HOLDING}${counts}`;
};
const folderSection = function folderSection(folder: AnatomyFolder): Section {
return {
blocks: [
{ caption: STATS_LABEL, kind: "metric" as const, metrics: statsMetrics(folder.stats) },
...(folder.walk === null
? []
: [{ caption: FOLDER_WALK_CAPTION, kind: "walk" as const, walk: folder.walk }]),
],
icon: FOLDER_SECTION_ICON,
id: folderId(folder.path),
intro: folderIntro(folder),
subsections: folder.files.map(fileRecord),
title: folder.path === "" ? ROOT_LABEL : folder.path,
};
};
const folderSections = function folderSections(folder: AnatomyFolder): Section[] {
return [folderSection(folder), ...folder.folders.flatMap(folderSections)];
};
export const treeTab = function treeTab(snapshot: AnatomySnapshot): Tab {
return {
icon: ANATOMY_CONTAINER_ICON,
id: TREE_TAB,
label: TREE_LABEL,
layout: "tree",
sections: folderSections(snapshot.tree),
};
};