import { DiagramSummary, RegistryElement } from './format'; import { ModelIndex } from './service'; /** A diagram an element is used in, as the pages show it. */ export interface UsedIn { path: string; title?: string; kind?: string; } /** A registry element as the model page and the registry page show it. */ export interface ElementCard { id: string; label?: string; sublabel?: string; type?: string; brand?: string; description?: string; /** Diagram that explains the element, relative to the model root. */ diagram?: string; /** Registry file (relative to the model root) and 0-based line of the element. */ file: string; line: number; usedIn: UsedIn[]; } /** What the model page shows; serialised into the webview. */ export interface ModelPanel { meta: { id?: string; name?: string; description?: string }; /** True when main.archify also carries a diagram, shown between metadata and the list. */ hasDiagram: boolean; groups: { group: string; diagrams: { path: string; title?: string; kind?: string; parseError?: string }[] }[]; registry: ElementCard[]; problems: string[]; nested: string[]; } /** What the registry page (one .archify-registry file) shows. */ export interface RegistryPanel { /** The registry file, relative to the model root (or its base name outside a model). */ file: string; inModel: boolean; model?: { id?: string; name?: string }; elements: ElementCard[]; problems: string[]; } function usedIn(id: string, usage: Map, diagrams: DiagramSummary[]): UsedIn[] { return (usage.get(id) ?? []).map((path) => { const summary = diagrams.find((d) => d.relativePath === path); return { path, title: summary?.title, kind: summary?.kind }; }); } export function elementCard(e: RegistryElement, usage: Map, diagrams: DiagramSummary[]): ElementCard { return { id: e.id, label: e.label, sublabel: e.sublabel, type: e.type, brand: e.brand, description: e.description, diagram: e.diagram, file: e.file, line: e.line, usedIn: usedIn(e.id, usage, diagrams), }; } const byId = (a: { id: string }, b: { id: string }) => a.id.localeCompare(b.id); export function panelFromIndex(index: ModelIndex): ModelPanel { const registry = [...index.registry.elements.values()].sort(byId).map((e) => elementCard(e, index.usage, index.diagrams)); return { meta: index.meta, hasDiagram: index.mainHasDiagram, groups: index.groups.map((g) => ({ group: g.group, diagrams: g.diagrams.map((d) => ({ path: d.relativePath, title: d.title, kind: d.kind, parseError: d.parseError })), })), registry, problems: index.registry.problems.map((p) => (p.file ? `${p.file}: ${p.message}` : p.message)), nested: index.nested, }; } /** The registry page of one file inside a model: its elements, in file order, with usage. */ export function registryPanelFromIndex(index: ModelIndex, file: string): RegistryPanel { const elements = [...index.registry.elements.values()] .filter((e) => e.file === file) .sort((a, b) => a.line - b.line) .map((e) => elementCard(e, index.usage, index.diagrams)); return { file, inModel: true, model: { id: index.meta.id, name: index.meta.name }, elements, problems: index.registry.problems.filter((p) => p.file === file).map((p) => p.message), }; } /** The registry page of a file outside a model: elements only, nothing is used anywhere. */ export function registryPanelStandalone(file: string, parsed: { elements: RegistryElement[]; problems: { message: string }[] }): RegistryPanel { return { file, inModel: false, elements: parsed.elements.map((e) => elementCard(e, new Map(), [])), problems: parsed.problems.map((p) => p.message), }; }