Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
josephinoo committed Feb 21, 2024
1 parent 4f4b035 commit 925d245
Show file tree
Hide file tree
Showing 3 changed files with 271 additions and 16 deletions.
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@
"title": "AsyncAPI: Paste as Schema"
},
{
"command": "asyncapi.hello",
"title": "Hello AsyncAPI"
"command": "asyncapi.md",
"title": "AsyncAPI: Convert to Markdown"
}
],
"snippets": [
Expand Down Expand Up @@ -125,6 +125,7 @@
"ts-loader": "^9.2.8",
"typescript": "^4.6.4",
"webpack": "^5.70.0",
"webpack-cli": "^4.9.2"
"webpack-cli": "^4.9.2",
"mermaid": "^10.8.0"
}
}
276 changes: 265 additions & 11 deletions src/PreviewWebPanel.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,216 @@
import * as vscode from 'vscode';
import * as path from 'path';

import * as fs from 'fs';
import * as yaml from 'js-yaml';

interface AsyncAPIDocument {
asyncapi: string;
info: {
title: string;
version: string;
description: string;
};
servers: {
[key: string]: {
host: string;
protocol: string;
description: string;
};
};
channels: {
[key: string]: {
address: string;
description: string;
messages: {
[key: string]: {
$ref: string;
};
};
parameters?: {
[key: string]: {
$ref: string;
};
};
};
};
operations: {
[key: string]: {
action: string;
channel: {
$ref: string;
};
summary: string;
traits?: {
[key: string]: {
$ref: string;
};
};
messages?: {
[key: string]: {
$ref: string;
};
};
};
};
components?: {
messages?: {
[key: string]: {
name: string;
title: string;
summary: string;
contentType: string;
traits?: {
[key: string]: {
$ref: string;
};
};
payload?: {
$ref: string;
};
};
};
schemas?: {
[key: string]: {
type: string;
properties: {
[key: string]: {
type: string;
minimum?: number;
maximum?: number;
description?: string;
enum?: string[];
format?: string;
items?: {
type: string;
};
$ref?: string;
};
};
description?: string;
};
};
securitySchemes?: {
[key: string]: {
type: string;
description: string;
};
};
parameters?: {
[key: string]: {
description: string;
schema: {
type: string;
format?: string;
minimum?: number;
maximum?: number;
};
};
};
messageTraits?: {
[key: string]: {
headers: {
type: string;
properties: {
[key: string]: {
type: string;
minimum?: number;
maximum?: number;
};
};
};
};
};
operationTraits?: {
[key: string]: {
bindings: {
kafka: {
clientId: {
type: string;
enum: string[];
};
};
};
};
};
};
}
function convertAsyncAPIToMermaid(asyncAPIDocument: AsyncAPIDocument): string {
let mermaidCode = `flowchart TD\n`;

// Add Streetlights Kafka API node
mermaidCode += ` subgraph "${asyncAPIDocument.info.title}"\n`;

// Add Servers subgraph
mermaidCode += ` subgraph "Servers"\n`;
Object.entries(asyncAPIDocument.servers).forEach(([serverName, serverInfo]) => {
mermaidCode += ` ${serverName}["${serverName}"]\n`;
});
mermaidCode += ` end\n`;

// Add Channels subgraph
mermaidCode += ` subgraph "Channels"\n`;
Object.entries(asyncAPIDocument.channels).forEach(([channelName, channelInfo]) => {
mermaidCode += ` ${channelName}["${channelName}"]\n`;
});
mermaidCode += ` end\n`;

// Add Operations subgraph
mermaidCode += ` subgraph "Operations"\n`;
Object.entries(asyncAPIDocument.operations).forEach(([operationName, operationInfo]) => {
mermaidCode += ` ${operationName}["${operationName}"]\n`;
});
mermaidCode += ` end\n`;

// Add Messages subgraph
mermaidCode += ` subgraph "Messages"\n`;
Object.entries(asyncAPIDocument.components.messages).forEach(([messageName, messageInfo]) => {
mermaidCode += ` ${messageName}["${messageName}"]\n`;
});
mermaidCode += ` end\n`;

mermaidCode += ` end\n`;

// Add connections between servers and channels
Object.entries(asyncAPIDocument.servers).forEach(([serverName]) => {
Object.entries(asyncAPIDocument.channels).forEach(([channelName]) => {
mermaidCode += ` ${serverName} --> ${channelName}\n`;
});
});

// Add connections between channels and operations
Object.entries(asyncAPIDocument.channels).forEach(([channelName, channelInfo]) => {
Object.entries(asyncAPIDocument.operations).forEach(([operationName]) => {
if (channelInfo.messages && channelInfo.messages[operationName]) {
mermaidCode += ` ${channelName} --> ${operationName}\n`;
}
});
});

// Add connections between channels and messages
Object.entries(asyncAPIDocument.channels).forEach(([channelName, channelInfo]) => {
Object.entries(asyncAPIDocument.components.messages).forEach(([messageName]) => {
if (channelInfo.messages && channelInfo.messages[messageName]) {
mermaidCode += ` ${channelName} --> ${messageName}\n`;
}
});
});

// Add connections between operations and messages
Object.entries(asyncAPIDocument.operations).forEach(([operationName, operationInfo]) => {
Object.entries(asyncAPIDocument.components.messages).forEach(([messageName]) => {
if (operationInfo.messages && operationInfo.messages[messageName]) {
mermaidCode += ` ${operationName} --> ${messageName}\n`;
}
});
});

return mermaidCode;
}




let position : {x:0,y:0} = {
x: 0,
y: 0
Expand All @@ -16,6 +226,7 @@ export function previewAsyncAPI(context: vscode.ExtensionContext) {
};
}


export const openAsyncapiFiles: { [id: string]: vscode.WebviewPanel } = {}; // vscode.Uri.fsPath => vscode.WebviewPanel

export function isAsyncAPIFile(document?: vscode.TextDocument) {
Expand Down Expand Up @@ -56,6 +267,8 @@ export function openAsyncAPI(context: vscode.ExtensionContext, uri: vscode.Uri)
});

panel.title = path.basename(uri.fsPath);
console.log('Opening HTML');
console.log(getWebviewContent(context, panel.webview, uri, position));
panel.webview.html = getWebviewContent(context, panel.webview, uri, position);

panel.webview.onDidReceiveMessage(
Expand All @@ -66,7 +279,6 @@ export function openAsyncAPI(context: vscode.ExtensionContext, uri: vscode.Uri)
x: message.scrollX,
y: message.scrollY
};

}
}
},
Expand Down Expand Up @@ -95,10 +307,48 @@ async function promptForAsyncapiFile() {
});
return uris?.[0];
}
export function printHello() {
console.log('Hello');
}

export function previewMarkdown(context: vscode.ExtensionContext) {
return async (uri: vscode.Uri) => {
uri = uri || (await promptForAsyncapiFile()) as vscode.Uri;
if (uri) {
console.log('Opening asyncapi file', uri.fsPath);
convertAsyncAPItoMD(context, uri);
}
};

}

async function convertAsyncAPItoMD(context: vscode.ExtensionContext, uri: vscode.Uri) {
const localResourceRoots = [
vscode.Uri.file(path.dirname(uri.fsPath)),
vscode.Uri.joinPath(context.extensionUri, 'dist/node_modules/@asyncapi/react-component/browser/standalone'),
vscode.Uri.joinPath(context.extensionUri, 'dist/node_modules/@asyncapi/react-component/styles'),
];
if (vscode.workspace.workspaceFolders) {
vscode.workspace.workspaceFolders.forEach(folder => {
localResourceRoots.push(folder.uri);
});
}
const panel: vscode.WebviewPanel =
openAsyncapiFiles[uri.fsPath] ||
vscode.window.createWebviewPanel('asyncapi-preview', '', vscode.ViewColumn.Two, {
enableScripts: true,
retainContextWhenHidden: true,
localResourceRoots,
});
console.log(vscode.Uri);
panel.title = path.basename(uri.fsPath);
panel.webview.html = convertToMD(context, panel.webview, uri, position);

}

function convertToMD(context: vscode.ExtensionContext, webview: vscode.Webview, asyncapiFile: vscode.Uri, position: {x:0,y:0}){
console.log('Converting to MD');
const asyncapiWebviewUri = webview.asWebviewUri(asyncapiFile);
console.log(asyncapiWebviewUri);
return "Hello";
}

function getWebviewContent(context: vscode.ExtensionContext, webview: vscode.Webview, asyncapiFile: vscode.Uri, position: {x:0,y:0}) {
const asyncapiComponentJs = webview.asWebviewUri(
Expand All @@ -108,13 +358,16 @@ function getWebviewContent(context: vscode.ExtensionContext, webview: vscode.Web
vscode.Uri.joinPath(context.extensionUri, 'dist/node_modules/@asyncapi/react-component/styles/default.min.css')
);
const asyncapiWebviewUri = webview.asWebviewUri(asyncapiFile);
const yamlFile = fs.readFileSync(asyncapiFile.fsPath, 'utf8');
const asyncAPIDocument: AsyncAPIDocument = yaml.load(yamlFile) as AsyncAPIDocument;
const mermaidCode = convertAsyncAPIToMermaid(asyncAPIDocument);
const asyncapiBasePath = asyncapiWebviewUri.toString().replace('%2B', '+'); // this is loaded by a different library so it requires unescaping the + character
const html = `
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="${asyncapiComponentCss}">
<style>
<style>
html{
scroll-behavior: smooth;
}
Expand All @@ -128,10 +381,12 @@ function getWebviewContent(context: vscode.ExtensionContext, webview: vscode.Web
}
</style>
</head>
<body x-timestamp="${Date.now()}">
<div id="asyncapi"></div>
<pre class="mermaid">
${mermaidCode};
</pre>
<script src="${asyncapiComponentJs}"></script>
<script>
const vscode = acquireVsCodeApi();
Expand All @@ -148,21 +403,20 @@ function getWebviewContent(context: vscode.ExtensionContext, webview: vscode.Web
parserOptions: { path: '${asyncapiBasePath}' }
},
}, document.getElementById('asyncapi'));
window.addEventListener('scrollend', event => {
vscode.postMessage({
type: 'position',
scrollX: window.scrollX || 0,
scrollY: window.scrollY || 0
});
});
window.addEventListener("load", (event) => {
setTimeout(()=>{window.scrollBy('${position.x}','${position.y}')},1000)
});
</script>
<script type="module">
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
</script>
</body>
</html>
`;
Expand Down
4 changes: 2 additions & 2 deletions src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as vscode from 'vscode';
import { isAsyncAPIFile, openAsyncAPI, openAsyncapiFiles, previewAsyncAPI, printHello } from './PreviewWebPanel';
import { isAsyncAPIFile, openAsyncAPI, openAsyncapiFiles, previewAsyncAPI, previewMarkdown} from './PreviewWebPanel';
import { asyncapiSmartPaste } from './SmartPasteCommand';


Expand Down Expand Up @@ -38,7 +38,7 @@ export function activate(context: vscode.ExtensionContext) {

context.subscriptions.push(vscode.commands.registerCommand("asyncapi.paste", asyncapiSmartPaste));

context.subscriptions.push(vscode.commands.registerCommand('asyncapi.hello', printHello ));
context.subscriptions.push(vscode.commands.registerCommand('asyncapi.md', previewMarkdown(context)));
}

export function deactivate() {}

0 comments on commit 925d245

Please sign in to comment.