Archify Diagram Viewer 0.1.0
VS Code extension that previews Archify diagrams from their JSON sources (live, as you type) and opens rendered Archify HTML in a viewer tab. Bundles the Archify 3.0.1 renderer and runs it on VS Code's Node runtime. Adds validation diagnostics, JSON schema help, source-link navigation, export saving, render-to-file and open-in-browser commands. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import path from 'node:path';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
const EXTENSION_ID = 'vscode-extensions.archify-vscode-ext';
|
||||
|
||||
function workspaceFile(name: string): vscode.Uri {
|
||||
const folder = vscode.workspace.workspaceFolders?.[0];
|
||||
assert.ok(folder, 'a workspace folder is open');
|
||||
return vscode.Uri.joinPath(folder.uri, name);
|
||||
}
|
||||
|
||||
async function waitFor<T>(what: string, probe: () => T | undefined | false, timeoutMs = 20_000): Promise<T> {
|
||||
const start = Date.now();
|
||||
for (;;) {
|
||||
const value = probe();
|
||||
if (value) return value;
|
||||
if (Date.now() - start > timeoutMs) throw new Error(`Timed out waiting for ${what}`);
|
||||
await new Promise((resolve) => setTimeout(resolve, 200));
|
||||
}
|
||||
}
|
||||
|
||||
function webviewTabs(viewTypeSuffix: string): vscode.Tab[] {
|
||||
return vscode.window.tabGroups.all
|
||||
.flatMap((group) => group.tabs)
|
||||
.filter((tab) =>
|
||||
(tab.input instanceof vscode.TabInputWebview && tab.input.viewType.endsWith(viewTypeSuffix)) ||
|
||||
(tab.input instanceof vscode.TabInputCustom && tab.input.viewType === viewTypeSuffix));
|
||||
}
|
||||
|
||||
async function check(name: string, body: () => Promise<void>): Promise<void> {
|
||||
try {
|
||||
await body();
|
||||
console.log(` ✔ ${name}`);
|
||||
} catch (error) {
|
||||
console.log(` ✖ ${name}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function run(): Promise<void> {
|
||||
console.log('Archify extension integration suite');
|
||||
|
||||
await check('activates on a diagram source and sets the context key', async () => {
|
||||
const doc = await vscode.workspace.openTextDocument(workspaceFile('production-deployment.architecture.json'));
|
||||
await vscode.window.showTextDocument(doc);
|
||||
const extension = vscode.extensions.getExtension(EXTENSION_ID);
|
||||
assert.ok(extension, 'extension is installed');
|
||||
await waitFor('activation', () => extension.isActive);
|
||||
});
|
||||
|
||||
await check('opens a live preview beside the source', async () => {
|
||||
await vscode.commands.executeCommand('archify.showPreviewToSide');
|
||||
const tabs = await waitFor('preview tab', () => {
|
||||
const found = webviewTabs('archify.preview');
|
||||
return found.length > 0 && found;
|
||||
});
|
||||
assert.equal(tabs.length, 1);
|
||||
assert.match(tabs[0].label, /Preview production-deployment\.architecture\.json/);
|
||||
});
|
||||
|
||||
await check('reports validation problems in the Problems panel with JSON ranges', async () => {
|
||||
const doc = await vscode.workspace.openTextDocument({
|
||||
language: 'json',
|
||||
content: JSON.stringify({ schema_version: 1, diagram_type: 'architecture', meta: { title: 'x' }, components: [{ id: 'a' }] }, null, 2),
|
||||
});
|
||||
await vscode.window.showTextDocument(doc);
|
||||
const diagnostics = await waitFor('archify diagnostics', () => {
|
||||
const found = vscode.languages.getDiagnostics(doc.uri).filter((d) => d.source === 'archify');
|
||||
return found.length > 0 && found;
|
||||
});
|
||||
const component = diagnostics.find((d) => /components\/0/.test(d.message));
|
||||
assert.ok(component, 'a diagnostic for /components/0');
|
||||
assert.equal(doc.getText(component.range), '{', 'range points at the component object');
|
||||
assert.equal(component.severity, vscode.DiagnosticSeverity.Error);
|
||||
});
|
||||
|
||||
await check('clears problems once the document is fixed', async () => {
|
||||
const good = await vscode.workspace.openTextDocument(workspaceFile('event-stream.dataflow.json'));
|
||||
const doc = await vscode.workspace.openTextDocument({ language: 'json', content: good.getText() });
|
||||
await vscode.window.showTextDocument(doc);
|
||||
await new Promise((resolve) => setTimeout(resolve, 3000));
|
||||
const errors = vscode.languages.getDiagnostics(doc.uri).filter((d) => d.source === 'archify' && d.severity === vscode.DiagnosticSeverity.Error);
|
||||
assert.deepEqual(errors.map((d) => d.message), []);
|
||||
});
|
||||
|
||||
await check('renders to an HTML file and opens it in the Archify viewer', async () => {
|
||||
const source = workspaceFile('cache-miss-request.sequence.json');
|
||||
const output = vscode.Uri.file(path.join(path.dirname(source.fsPath), 'cache-miss-request.sequence.html'));
|
||||
// Stub the save dialog and the follow-up notification.
|
||||
const window = vscode.window as unknown as Record<string, unknown>;
|
||||
const originalSave = window.showSaveDialog;
|
||||
const originalInfo = window.showInformationMessage;
|
||||
window.showSaveDialog = async () => output;
|
||||
window.showInformationMessage = async () => 'Open in Viewer';
|
||||
try {
|
||||
await vscode.commands.executeCommand('archify.renderToHtml', source);
|
||||
} finally {
|
||||
window.showSaveDialog = originalSave;
|
||||
window.showInformationMessage = originalInfo;
|
||||
}
|
||||
const html = new TextDecoder().decode(await vscode.workspace.fs.readFile(output));
|
||||
assert.match(html, /<meta name="generator" content="archify/);
|
||||
await waitFor('custom editor tab', () => webviewTabs('archify.htmlViewer').length > 0);
|
||||
});
|
||||
|
||||
await check('source-backed diagram previews with the evidence fallback', async () => {
|
||||
const uri = workspaceFile('mco-runtime.architecture.json');
|
||||
await vscode.commands.executeCommand('archify.showPreview', uri);
|
||||
await waitFor('second preview tab', () => webviewTabs('archify.preview').length >= 2);
|
||||
const doc = await vscode.workspace.openTextDocument(uri);
|
||||
const diagnostics = await waitFor('evidence diagnostics', () => {
|
||||
const found = vscode.languages.getDiagnostics(doc.uri).filter((d) => d.source === 'archify');
|
||||
return found.length > 0 && found;
|
||||
});
|
||||
assert.ok(
|
||||
diagnostics.every((d) => d.severity !== vscode.DiagnosticSeverity.Error),
|
||||
'unverifiable evidence is a warning in fallback mode',
|
||||
);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user