- *.archify-decision files: id (unique, words), title, status, date, elements, diagrams, supersedes, and prose; parsed, merged and link-checked in the model index; diagnostics on the file - diagrams point at decisions with decisions: [...] on the diagram, nodes and edges; stripped before Archify, unknown ids reported, completion, hover and go-to-definition for the ids and for elements/diagrams/ supersedes in decision files - Decisions panel on the main.archify page; Decisions rail panel under a diagram (hover lights up the node or connection); decisions on element cards and in the element dialog; decision view for the file, with a lost-model note outside a model - Archify | New Decision… command and template; editor schemas; the three New Model examples carry decisions; docs, changelog, 0.8.0
72 lines
3.4 KiB
TypeScript
72 lines
3.4 KiB
TypeScript
import path from 'node:path';
|
|
import * as vscode from 'vscode';
|
|
import { DiagramSource, readDiagramSource } from '../sources/detect';
|
|
import { DecisionAttachment, ModelProblem, Registry, resolveRefs } from './format';
|
|
import { effectiveStatus } from './decisions';
|
|
import { ModelService } from './service';
|
|
|
|
/**
|
|
* A diagram ready for Archify: the source as written, plus the resolved JSON
|
|
* with registry references expanded, the model problems found on the way,
|
|
* and the diagram links the viewer should offer.
|
|
*/
|
|
export interface PreparedDiagram {
|
|
source: DiagramSource;
|
|
/** Model root when the file is inside a model. */
|
|
root?: vscode.Uri;
|
|
registry?: Registry;
|
|
problems: ModelProblem[];
|
|
/** Node id → diagram path relative to the model root. */
|
|
links: Map<string, string>;
|
|
/** Node id → registry description. */
|
|
descriptions: Map<string, string>;
|
|
/** Decisions of this diagram for the Decisions rail panel: pointed at by the diagram, or naming it. */
|
|
decisions: DiagramDecision[];
|
|
}
|
|
|
|
export interface DiagramDecision {
|
|
id: string;
|
|
title?: string;
|
|
status: string;
|
|
file: string;
|
|
attachedTo: DecisionAttachment[];
|
|
}
|
|
|
|
/**
|
|
* Reads a diagram and resolves it against its model, if any. Every place
|
|
* that hands a diagram to Archify (preview, Problems, render, browser) goes
|
|
* through here, so they all see the same resolved diagram.
|
|
*/
|
|
export async function prepareDiagram(models: ModelService, uri: vscode.Uri, text: string): Promise<PreparedDiagram | undefined> {
|
|
const source = readDiagramSource(text, uri.path);
|
|
if (!source) return undefined;
|
|
const index = await models.indexFor(uri);
|
|
const found = index ? { root: index.root, registry: index.registry } : undefined;
|
|
const resolved = resolveRefs(source.diagram, { registry: found?.registry, decisions: index ? new Set(index.decisions.decisions.keys()) : undefined, fileName: uri.path });
|
|
// Only diagrams that use refs (or carry a model block) need the resolved form.
|
|
const changed = resolved.refs.size > 0 || resolved.problems.length > 0 || 'model' in source.diagram || resolved.links.size > 0 || resolved.decisionRefs.length > 0;
|
|
const prepared: DiagramSource = changed
|
|
? { ...source, diagram: resolved.diagram, json: JSON.stringify(resolved.diagram, null, 2) }
|
|
: source;
|
|
// Decisions for the rail: the ones this diagram points at, plus the ones that name this diagram.
|
|
const decisions: DiagramDecision[] = [];
|
|
if (index) {
|
|
const rel = path.relative(index.root.fsPath, uri.fsPath).split(path.sep).join('/');
|
|
const byId = new Map<string, DiagramDecision>();
|
|
const add = (id: string, attachedTo?: DecisionAttachment) => {
|
|
const d = index.decisions.decisions.get(id);
|
|
if (!d) return;
|
|
let row = byId.get(id);
|
|
if (!row) {
|
|
row = { id, title: d.title, status: effectiveStatus(d, index.decisions.decisions).status, file: d.file, attachedTo: [] };
|
|
byId.set(id, row);
|
|
decisions.push(row);
|
|
}
|
|
if (attachedTo && !row.attachedTo.some((a) => JSON.stringify(a) === JSON.stringify(attachedTo))) row.attachedTo.push(attachedTo);
|
|
};
|
|
for (const ref of resolved.decisionRefs) add(ref.id, ref.attachedTo);
|
|
for (const d of index.decisions.decisions.values()) if (d.diagrams.includes(rel)) add(d.id, { kind: 'diagram' });
|
|
}
|
|
return { source: prepared, root: found?.root, registry: found?.registry, problems: resolved.problems, links: resolved.links, descriptions: resolved.descriptions, decisions };
|
|
}
|