0.3.0: .archify files are YAML and open straight into the diagram
- .archify content is YAML (JSON still accepted); converted to JSON for the renderer - Archify Diagram custom editor is the default for *.archify; Show Source opens the YAML beside it - YAML syntax errors and validation problems mapped to YAML lines - yamlValidation for schema completion with redhat.vscode-yaml - scripts/to-yaml.mjs converts existing .archify files
This commit is contained in:
+30
-9
@@ -1,4 +1,5 @@
|
||||
import { parse, ParseError } from 'jsonc-parser';
|
||||
import { parse as parseYaml } from 'yaml';
|
||||
|
||||
export const DIAGRAM_TYPES = ['architecture', 'workflow', 'sequence', 'dataflow', 'lifecycle'] as const;
|
||||
export type DiagramType = (typeof DIAGRAM_TYPES)[number];
|
||||
@@ -44,24 +45,44 @@ export function diagramBaseName(fileName: string): string {
|
||||
export interface DiagramSource {
|
||||
type: DiagramType;
|
||||
diagram: Record<string, unknown>;
|
||||
/** Source syntax: `.archify` files are YAML, Archify's own sources JSON. */
|
||||
format: 'yaml' | 'json';
|
||||
/** JSON text for the Archify renderer, which only reads JSON. */
|
||||
json: string;
|
||||
}
|
||||
|
||||
/** Parses `.archify` (YAML) or JSON text; undefined when it does not parse. */
|
||||
export function parseDiagramText(text: string, fileName = ''): unknown {
|
||||
if (isArchifyFile(fileName)) {
|
||||
try {
|
||||
// YAML 1.2 also accepts the JSON form of older .archify files.
|
||||
return parseYaml(text, { prettyErrors: false, uniqueKeys: false });
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
const errors: ParseError[] = [];
|
||||
return parse(text, errors, { allowTrailingComma: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses JSON text and returns the diagram when it declares an Archify
|
||||
* `diagram_type`. Falls back to the file name for documents that do not
|
||||
* parse yet, so a half-typed source still counts as a diagram.
|
||||
* Returns the diagram when the text declares an Archify `diagram_type`.
|
||||
* Falls back to the file name for documents that do not parse yet, so a
|
||||
* half-typed source still counts as a diagram.
|
||||
*/
|
||||
export function readDiagramSource(text: string, fileName = ''): DiagramSource | undefined {
|
||||
if (text.length > MAX_SNIFF_BYTES) return undefined;
|
||||
const errors: ParseError[] = [];
|
||||
const value = parse(text, errors, { allowTrailingComma: true });
|
||||
if (value && typeof value === 'object' && !Array.isArray(value) && isDiagramType(value.diagram_type)) {
|
||||
return { type: value.diagram_type, diagram: value };
|
||||
const format = isArchifyFile(fileName) ? 'yaml' : 'json';
|
||||
const value = parseDiagramText(text, fileName) as Record<string, unknown> | undefined;
|
||||
const isObject = value !== null && typeof value === 'object' && !Array.isArray(value);
|
||||
const json = (diagram: unknown) => (format === 'json' ? text : JSON.stringify(diagram ?? {}, null, 2));
|
||||
if (isObject && isDiagramType(value.diagram_type)) {
|
||||
return { type: value.diagram_type, diagram: value, format, json: json(value) };
|
||||
}
|
||||
const byName = typeFromFilename(fileName);
|
||||
if (byName) {
|
||||
const diagram = value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
||||
return { type: byName, diagram };
|
||||
const diagram = isObject ? value : {};
|
||||
return { type: byName, diagram, format, json: json(diagram) };
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
+37
-11
@@ -1,7 +1,7 @@
|
||||
import { parse, ParseError } from 'jsonc-parser';
|
||||
import * as vscode from 'vscode';
|
||||
import { readDiagramSource } from './detect';
|
||||
import { rangeForPointer } from './jsonPointer';
|
||||
import { isArchifyFile, readDiagramSource } from './detect';
|
||||
import { rangeForPointer, rangeForPointerYaml, yamlSyntaxProblems } from './jsonPointer';
|
||||
import { ArchifyDiagnostic, isEvidenceError, validate } from './renderer';
|
||||
import { evidenceMode, log, runtimeFor } from './runtime';
|
||||
|
||||
@@ -61,7 +61,7 @@ export class DiagnosticsController implements vscode.Disposable {
|
||||
}
|
||||
|
||||
private schedule(doc: vscode.TextDocument, delay: number): void {
|
||||
if (!JSON_LANGUAGES.has(doc.languageId)) return;
|
||||
if (!JSON_LANGUAGES.has(doc.languageId) && !isArchifyFile(doc.fileName)) return;
|
||||
const key = doc.uri.toString();
|
||||
clearTimeout(this.timers.get(key));
|
||||
this.timers.set(key, setTimeout(() => void this.validate(doc), delay));
|
||||
@@ -74,22 +74,48 @@ export class DiagnosticsController implements vscode.Disposable {
|
||||
this.sequence.set(key, seq);
|
||||
|
||||
const text = doc.getText();
|
||||
const source = readDiagramSource(text, doc.fileName);
|
||||
if (!source || !this.enabled(doc.uri) || doc.isClosed) {
|
||||
if (!this.enabled(doc.uri) || doc.isClosed) {
|
||||
this.collection.delete(doc.uri);
|
||||
return;
|
||||
}
|
||||
// Leave syntax errors to the JSON language service.
|
||||
const syntax: ParseError[] = [];
|
||||
parse(text, syntax, { allowTrailingComma: false });
|
||||
if (syntax.length) {
|
||||
if (isArchifyFile(doc.fileName)) {
|
||||
// Nothing else reports YAML syntax errors in .archify files, and a file
|
||||
// that does not parse has no diagram to validate yet.
|
||||
const problems = yamlSyntaxProblems(text);
|
||||
if (problems.length) {
|
||||
this.collection.set(
|
||||
doc.uri,
|
||||
problems.map((problem) => {
|
||||
const diagnostic = new vscode.Diagnostic(
|
||||
new vscode.Range(doc.positionAt(problem.start), doc.positionAt(problem.end)),
|
||||
`YAML: ${problem.message}`,
|
||||
vscode.DiagnosticSeverity.Error,
|
||||
);
|
||||
diagnostic.source = 'archify';
|
||||
return diagnostic;
|
||||
}),
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
const source = readDiagramSource(text, doc.fileName);
|
||||
if (!source) {
|
||||
this.collection.delete(doc.uri);
|
||||
return;
|
||||
}
|
||||
if (source.format === 'json') {
|
||||
// Leave JSON syntax errors to the JSON language service.
|
||||
const syntax: ParseError[] = [];
|
||||
parse(text, syntax, { allowTrailingComma: false });
|
||||
if (syntax.length) {
|
||||
this.collection.delete(doc.uri);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const runtime = await runtimeFor(this.context, doc.uri);
|
||||
const result = await validate(runtime, source.type, text);
|
||||
const result = await validate(runtime, source.type, source.json);
|
||||
if (seq !== this.sequence.get(key) || doc.isClosed) return;
|
||||
|
||||
if (result.crash) {
|
||||
@@ -107,7 +133,7 @@ export class DiagnosticsController implements vscode.Disposable {
|
||||
this.collection.set(
|
||||
doc.uri,
|
||||
result.diagnostics.map((item) => {
|
||||
const offsets = rangeForPointer(text, item.subject?.path);
|
||||
const offsets = source.format === 'yaml' ? rangeForPointerYaml(text, item.subject?.path) : rangeForPointer(text, item.subject?.path);
|
||||
const range = new vscode.Range(doc.positionAt(offsets.start), doc.positionAt(offsets.end));
|
||||
const fix = item.supportedFixes?.[0];
|
||||
const diagnostic = new vscode.Diagnostic(
|
||||
|
||||
+20
-6
@@ -1,10 +1,10 @@
|
||||
import fs from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import * as vscode from 'vscode';
|
||||
import { diagramBaseName, isArchifyHtml, isDiagramFileName, readDiagramSource } from './detect';
|
||||
import { diagramBaseName, isArchifyFile, isArchifyHtml, isDiagramFileName, readDiagramSource } from './detect';
|
||||
import { DiagnosticsController } from './diagnostics';
|
||||
import { HTML_VIEW_TYPE, HtmlViewerProvider } from './htmlViewer';
|
||||
import { PreviewManager } from './preview';
|
||||
import { DIAGRAM_EDITOR_VIEW_TYPE, PreviewManager } from './preview';
|
||||
import { isEvidenceError, renderDiagram, renderToFile } from './renderer';
|
||||
import { clearGitRootCache, evidenceMode, log, readText, runtimeFor } from './runtime';
|
||||
|
||||
@@ -36,7 +36,9 @@ export function activate(context: vscode.ExtensionContext): void {
|
||||
const updateContext = () => {
|
||||
const doc = vscode.window.activeTextEditor?.document;
|
||||
const diagram = Boolean(
|
||||
doc && JSON_LANGUAGES.has(doc.languageId) && (isDiagramFileName(doc.fileName) || readDiagramSource(doc.getText(), doc.fileName)),
|
||||
doc &&
|
||||
(isArchifyFile(doc.fileName) ||
|
||||
(JSON_LANGUAGES.has(doc.languageId) && (isDiagramFileName(doc.fileName) || readDiagramSource(doc.getText(), doc.fileName)))),
|
||||
);
|
||||
const html = Boolean(doc && doc.languageId === 'html' && isArchifyHtml(doc.getText()));
|
||||
void vscode.commands.executeCommand('setContext', 'archify.isDiagramSource', diagram);
|
||||
@@ -64,6 +66,7 @@ export function activate(context: vscode.ExtensionContext): void {
|
||||
const uri = sourceUri(arg);
|
||||
if (!uri) return;
|
||||
if (isHtmlUri(uri)) return openHtmlViewer(uri);
|
||||
if (isArchifyFile(uri.path)) return vscode.commands.executeCommand('vscode.openWith', uri, DIAGRAM_EDITOR_VIEW_TYPE);
|
||||
previews.show(uri, vscode.window.activeTextEditor?.viewColumn ?? vscode.ViewColumn.Active);
|
||||
}),
|
||||
|
||||
@@ -71,6 +74,12 @@ export function activate(context: vscode.ExtensionContext): void {
|
||||
const uri = sourceUri(arg);
|
||||
if (!uri) return;
|
||||
if (isHtmlUri(uri)) return openHtmlViewer(uri, vscode.ViewColumn.Beside);
|
||||
if (isArchifyFile(uri.path)) {
|
||||
return vscode.commands.executeCommand('vscode.openWith', uri, DIAGRAM_EDITOR_VIEW_TYPE, {
|
||||
viewColumn: vscode.ViewColumn.Beside,
|
||||
preserveFocus: true,
|
||||
});
|
||||
}
|
||||
previews.show(uri, vscode.ViewColumn.Beside, true);
|
||||
}),
|
||||
|
||||
@@ -83,6 +92,11 @@ export function activate(context: vscode.ExtensionContext): void {
|
||||
|
||||
vscode.commands.registerCommand('archify.showSource', async () => {
|
||||
const preview = previews.activePreview;
|
||||
if (preview?.isEditor) {
|
||||
// The diagram is the editor; open the YAML text beside it.
|
||||
await vscode.commands.executeCommand('vscode.openWith', preview.uri, 'default', vscode.ViewColumn.Beside);
|
||||
return;
|
||||
}
|
||||
if (preview) {
|
||||
const column = preview.panel.viewColumn === vscode.ViewColumn.One ? vscode.ViewColumn.Two : vscode.ViewColumn.One;
|
||||
await vscode.window.showTextDocument(preview.uri, { viewColumn: column });
|
||||
@@ -115,7 +129,7 @@ export function activate(context: vscode.ExtensionContext): void {
|
||||
const runtime = await runtimeFor(context, uri);
|
||||
let result = await vscode.window.withProgress(
|
||||
{ location: vscode.ProgressLocation.Notification, title: 'Archify: rendering…' },
|
||||
() => renderToFile(runtime, { ...source, text }, target.fsPath),
|
||||
() => renderToFile(runtime, source, target.fsPath),
|
||||
);
|
||||
if (!result.ok && isEvidenceError(result.error)) {
|
||||
const choice = await vscode.window.showWarningMessage(
|
||||
@@ -123,7 +137,7 @@ export function activate(context: vscode.ExtensionContext): void {
|
||||
{ modal: true, detail: result.error },
|
||||
'Render Without Source Links',
|
||||
);
|
||||
if (choice) result = await renderToFile(runtime, { ...source, text }, target.fsPath, true);
|
||||
if (choice) result = await renderToFile(runtime, source, target.fsPath, true);
|
||||
else return;
|
||||
}
|
||||
if (!result.ok) {
|
||||
@@ -156,7 +170,7 @@ export function activate(context: vscode.ExtensionContext): void {
|
||||
const runtime = await runtimeFor(context, uri);
|
||||
const result = await vscode.window.withProgress(
|
||||
{ location: vscode.ProgressLocation.Notification, title: 'Archify: rendering…' },
|
||||
() => renderDiagram(runtime, { ...source, text }, evidenceMode(uri)),
|
||||
() => renderDiagram(runtime, source, evidenceMode(uri)),
|
||||
);
|
||||
if (!result.ok || !result.html) {
|
||||
vscode.window.showErrorMessage('Archify: render failed.', { modal: true, detail: result.error });
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { findNodeAtLocation, Node, parseTree } from 'jsonc-parser';
|
||||
import { isMap, isScalar, isSeq, parseDocument } from 'yaml';
|
||||
|
||||
export interface OffsetRange {
|
||||
start: number;
|
||||
@@ -37,3 +38,42 @@ export function rangeForPointer(text: string, pointer: string | undefined): Offs
|
||||
}
|
||||
return { start: node.offset, end: node.offset + node.length };
|
||||
}
|
||||
|
||||
/** The same mapping for YAML text (`.archify` files). */
|
||||
export function rangeForPointerYaml(text: string, pointer: string | undefined): OffsetRange {
|
||||
const doc = parseDocument(text, { keepSourceTokens: false, uniqueKeys: false });
|
||||
let node: unknown = doc.contents;
|
||||
let keyRange: [number, number] | undefined;
|
||||
for (const segment of pointerSegments(pointer ?? '')) {
|
||||
if (isMap(node)) {
|
||||
const pair = node.items.find((item) => isScalar(item.key) && String(item.key.value) === String(segment));
|
||||
if (!pair) break;
|
||||
keyRange = isScalar(pair.key) && pair.key.range ? [pair.key.range[0], pair.key.range[1]] : undefined;
|
||||
node = pair.value;
|
||||
} else if (isSeq(node) && typeof segment === 'number' && segment < node.items.length) {
|
||||
keyRange = undefined;
|
||||
node = node.items[segment];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((isMap(node) || isSeq(node)) && keyRange) return { start: keyRange[0], end: keyRange[1] };
|
||||
const range = (node as { range?: [number, number, number] } | null)?.range;
|
||||
if (!range) return { start: 0, end: 0 };
|
||||
if (isMap(node) || isSeq(node)) return { start: range[0], end: Math.min(range[0] + 1, range[1]) };
|
||||
return { start: range[0], end: range[1] };
|
||||
}
|
||||
|
||||
export interface SyntaxProblem extends OffsetRange {
|
||||
message: string;
|
||||
}
|
||||
|
||||
/** YAML syntax errors with their offsets (none for valid YAML). */
|
||||
export function yamlSyntaxProblems(text: string): SyntaxProblem[] {
|
||||
const doc = parseDocument(text, { uniqueKeys: false });
|
||||
return doc.errors.map((error) => ({
|
||||
start: error.pos[0],
|
||||
end: Math.max(error.pos[1], error.pos[0] + 1),
|
||||
message: error.message.split('\n')[0],
|
||||
}));
|
||||
}
|
||||
|
||||
+43
-10
@@ -7,6 +7,8 @@ import { handleWebviewMessage, WebviewMessage } from './webviewMessages';
|
||||
import { makeNonce, messagePage, prepareDiagramHtml } from './webviewHtml';
|
||||
|
||||
export const PREVIEW_VIEW_TYPE = 'archify.preview';
|
||||
/** Default editor for .archify files: the rendered diagram. */
|
||||
export const DIAGRAM_EDITOR_VIEW_TYPE = 'archify.diagram';
|
||||
|
||||
interface PreviewState {
|
||||
uri: string;
|
||||
@@ -28,11 +30,15 @@ class DiagramPreview implements vscode.Disposable {
|
||||
readonly panel: vscode.WebviewPanel,
|
||||
readonly uri: vscode.Uri,
|
||||
state?: PreviewState,
|
||||
/** True when this is the custom editor of the file, not a side preview. */
|
||||
readonly isEditor = false,
|
||||
) {
|
||||
this.hash = state?.hash;
|
||||
panel.webview.options = { enableScripts: true, localResourceRoots: [] };
|
||||
panel.iconPath = vscode.Uri.joinPath(context.extensionUri, 'media', 'preview.svg');
|
||||
panel.title = `Preview ${path.basename(uri.path)}`;
|
||||
if (!isEditor) {
|
||||
panel.iconPath = vscode.Uri.joinPath(context.extensionUri, 'media', 'preview.svg');
|
||||
panel.title = `Preview ${path.basename(uri.path)}`;
|
||||
}
|
||||
|
||||
this.disposables.push(
|
||||
panel.onDidDispose(() => this.dispose()),
|
||||
@@ -102,7 +108,7 @@ class DiagramPreview implements vscode.Disposable {
|
||||
let result;
|
||||
try {
|
||||
const runtime = await runtimeFor(this.context, this.uri);
|
||||
result = await renderDiagram(runtime, { ...source, text }, evidenceMode(this.uri));
|
||||
result = await renderDiagram(runtime, source, evidenceMode(this.uri));
|
||||
} catch (error) {
|
||||
result = { ok: false, error: error instanceof Error ? error.message : String(error) };
|
||||
}
|
||||
@@ -152,19 +158,30 @@ function firstLines(text: string | undefined, count = 6): string {
|
||||
return (text ?? '').split('\n').slice(0, count).join('\n');
|
||||
}
|
||||
|
||||
export class PreviewManager implements vscode.Disposable, vscode.WebviewPanelSerializer<PreviewState> {
|
||||
export class PreviewManager
|
||||
implements vscode.Disposable, vscode.WebviewPanelSerializer<PreviewState>, vscode.CustomTextEditorProvider
|
||||
{
|
||||
/** Side previews, one per source file. */
|
||||
private readonly previews = new Map<string, DiagramPreview>();
|
||||
/** Custom-editor tabs of .archify files (several per file are allowed). */
|
||||
private readonly editors = new Set<DiagramPreview>();
|
||||
private active: DiagramPreview | undefined;
|
||||
private readonly disposables: vscode.Disposable[] = [];
|
||||
|
||||
constructor(private readonly context: vscode.ExtensionContext) {
|
||||
this.disposables.push(
|
||||
vscode.window.registerWebviewPanelSerializer(PREVIEW_VIEW_TYPE, this),
|
||||
vscode.window.registerCustomEditorProvider(DIAGRAM_EDITOR_VIEW_TYPE, this, {
|
||||
webviewOptions: { retainContextWhenHidden: true, enableFindWidget: true },
|
||||
supportsMultipleEditorsPerDocument: true,
|
||||
}),
|
||||
vscode.workspace.onDidChangeTextDocument((event) => {
|
||||
const preview = this.previews.get(event.document.uri.toString());
|
||||
if (preview && event.contentChanges.length && this.liveUpdate(preview.uri)) preview.scheduleUpdate();
|
||||
if (!event.contentChanges.length || !this.liveUpdate(event.document.uri)) return;
|
||||
for (const preview of this.forUri(event.document.uri)) preview.scheduleUpdate();
|
||||
}),
|
||||
vscode.workspace.onDidSaveTextDocument((doc) => {
|
||||
for (const preview of this.forUri(doc.uri)) void preview.update();
|
||||
}),
|
||||
vscode.workspace.onDidSaveTextDocument((doc) => void this.previews.get(doc.uri.toString())?.update()),
|
||||
vscode.workspace.onDidChangeConfiguration((event) => {
|
||||
if (event.affectsConfiguration('archify')) this.refreshAll();
|
||||
}),
|
||||
@@ -180,6 +197,17 @@ export class PreviewManager implements vscode.Disposable, vscode.WebviewPanelSer
|
||||
return this.active;
|
||||
}
|
||||
|
||||
private forUri(uri: vscode.Uri): DiagramPreview[] {
|
||||
const key = uri.toString();
|
||||
return [...this.previews.values(), ...this.editors].filter((preview) => preview.uri.toString() === key);
|
||||
}
|
||||
|
||||
/** Opening a .archify file lands here: the diagram is the editor. */
|
||||
async resolveCustomTextEditor(document: vscode.TextDocument, panel: vscode.WebviewPanel): Promise<void> {
|
||||
panel.webview.options = { enableScripts: true, localResourceRoots: [] };
|
||||
this.track(new DiagramPreview(this.context, panel, document.uri, undefined, true));
|
||||
}
|
||||
|
||||
show(uri: vscode.Uri, viewColumn: vscode.ViewColumn, preserveFocus = false): void {
|
||||
const existing = this.previews.get(uri.toString());
|
||||
if (existing) {
|
||||
@@ -205,8 +233,11 @@ export class PreviewManager implements vscode.Disposable, vscode.WebviewPanelSer
|
||||
|
||||
private track(preview: DiagramPreview): void {
|
||||
const key = preview.uri.toString();
|
||||
this.previews.get(key)?.panel.dispose();
|
||||
this.previews.set(key, preview);
|
||||
if (preview.isEditor) this.editors.add(preview);
|
||||
else {
|
||||
this.previews.get(key)?.panel.dispose();
|
||||
this.previews.set(key, preview);
|
||||
}
|
||||
const onViewState = () => {
|
||||
if (preview.panel.active) this.active = preview;
|
||||
else if (this.active === preview) this.active = undefined;
|
||||
@@ -215,6 +246,7 @@ export class PreviewManager implements vscode.Disposable, vscode.WebviewPanelSer
|
||||
preview.panel.onDidChangeViewState(onViewState);
|
||||
onViewState();
|
||||
preview.onDidDispose(() => {
|
||||
this.editors.delete(preview);
|
||||
if (this.previews.get(key) === preview) this.previews.delete(key);
|
||||
if (this.active === preview) {
|
||||
this.active = undefined;
|
||||
@@ -224,12 +256,13 @@ export class PreviewManager implements vscode.Disposable, vscode.WebviewPanelSer
|
||||
}
|
||||
|
||||
refreshAll(force = false): void {
|
||||
for (const preview of this.previews.values()) void preview.update(force);
|
||||
for (const preview of [...this.previews.values(), ...this.editors]) void preview.update(force);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
for (const preview of this.previews.values()) preview.panel.dispose();
|
||||
this.previews.clear();
|
||||
this.editors.clear();
|
||||
for (const disposable of this.disposables.splice(0)) disposable.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -144,7 +144,7 @@ async function renderOnce(
|
||||
*/
|
||||
export async function renderDiagram(
|
||||
options: RuntimeOptions,
|
||||
source: DiagramSource & { text: string },
|
||||
source: DiagramSource,
|
||||
evidence: 'fallback' | 'strict',
|
||||
): Promise<RenderResult> {
|
||||
const withEvidence = hasSourceEvidence(source.type, source.diagram);
|
||||
@@ -156,7 +156,7 @@ export async function renderDiagram(
|
||||
evidenceNotice: 'Source links are hidden: the diagram is not inside a Git checkout, so its source evidence cannot be verified. Set "archify.repoRoot" to the matching checkout.',
|
||||
};
|
||||
}
|
||||
const first = await renderOnce(options, source.type, source.text, withEvidence);
|
||||
const first = await renderOnce(options, source.type, source.json, withEvidence);
|
||||
if (first.ok || !withEvidence || evidence !== 'fallback' || !isEvidenceError(first.error)) {
|
||||
return first;
|
||||
}
|
||||
@@ -173,13 +173,13 @@ export async function renderDiagram(
|
||||
*/
|
||||
export async function renderToFile(
|
||||
options: RuntimeOptions,
|
||||
source: DiagramSource & { text: string },
|
||||
source: DiagramSource,
|
||||
outputPath: string,
|
||||
stripEvidence = false,
|
||||
): Promise<RenderResult> {
|
||||
const text = stripEvidence
|
||||
? JSON.stringify(stripSourceEvidence(source.type, source.diagram), null, 2)
|
||||
: source.text;
|
||||
: source.json;
|
||||
const withEvidence = !stripEvidence && hasSourceEvidence(source.type, source.diagram);
|
||||
return withScratch(options, async (dir) => {
|
||||
const input = path.join(dir, `diagram.${source.type}.json`);
|
||||
|
||||
Reference in New Issue
Block a user