From 5b90fcb609ca3f975bc3c40155aa3c95fe6aea3c Mon Sep 17 00:00:00 2001 From: Waiting Date: Tue, 14 Mar 2023 23:55:12 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A2=BC=E5=A2=9E=E5=8A=A0=E5=88=86?= =?UTF-8?q?=E8=99=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintrc | 52 +++++++++++++++------------ src/ClassShape.ts | 38 ++++++++++---------- src/CodeBlockShape.ts | 30 ++++++++-------- src/Edge.ts | 18 +++++----- src/Graph.ts | 84 +++++++++++++++++++++---------------------- src/SourceCodeView.ts | 4 +-- src/Utils.ts | 80 ++++++++++++++++++++--------------------- src/main.ts | 18 +++++----- 8 files changed, 166 insertions(+), 158 deletions(-) diff --git a/.eslintrc b/.eslintrc index 0807290..f9939df 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,23 +1,31 @@ { - "root": true, - "parser": "@typescript-eslint/parser", - "env": { "node": true }, - "plugins": [ - "@typescript-eslint" - ], - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended" - ], - "parserOptions": { - "sourceType": "module" - }, - "rules": { - "no-unused-vars": "off", - "@typescript-eslint/no-unused-vars": ["error", { "args": "none" }], - "@typescript-eslint/ban-ts-comment": "off", - "no-prototype-builtins": "off", - "@typescript-eslint/no-empty-function": "off" - } - } \ No newline at end of file + "root": true, + "parser": "@typescript-eslint/parser", + "env": { + "node": true + }, + "plugins": [ + "@typescript-eslint" + ], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended" + ], + "parserOptions": { + "sourceType": "module" + }, + "rules": { + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": [ + "error", + { + "args": "none" + } + ], + "@typescript-eslint/ban-ts-comment": "off", + "no-prototype-builtins": "off", + "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/semi": ["error", "always"] + } +} diff --git a/src/ClassShape.ts b/src/ClassShape.ts index 5db0f79..a73a457 100644 --- a/src/ClassShape.ts +++ b/src/ClassShape.ts @@ -1,7 +1,7 @@ import {Graph} from '@antv/x6'; -import {Utils} from './Utils' +import {Utils} from './Utils'; -const myUtils = new Utils() +const myUtils = new Utils(); // 類名稱區塊高度 const classNameBoxHeight = 30; @@ -21,11 +21,11 @@ Graph.registerPortLayout( y: classNameBoxHeight + index * funcNameBoxHeight, }, angle: 0, - } - }) + }; + }); }, //true, -) +); /** * 類聲明 圖形定義 @@ -135,7 +135,7 @@ Graph.registerNode( }, }, true, -) +); class ClassShape { @@ -148,14 +148,14 @@ class ClassShape { public createClassShape(className: string, funcNames: string[]) { // 計算 類聲明 圖形寬度 - let maxWidth = 100 - maxWidth = Math.max(maxWidth, myUtils.getTextWidth(className, "14px bold") + 60) + let maxWidth = 100; + maxWidth = Math.max(maxWidth, myUtils.getTextWidth(className, "14px bold") + 60); funcNames.forEach((funcName: string) => { - maxWidth = Math.max(maxWidth, myUtils.getTextWidth(funcName, "13px") + 20) - }) + maxWidth = Math.max(maxWidth, myUtils.getTextWidth(funcName, "13px") + 20); + }); // 定義頂部類名稱方塊 - let classShape = { + const classShape = { "id": myUtils.getClassShapeId(className, '', 'class'), "shape": 'clazz-shape', "label": className, @@ -167,15 +167,15 @@ class ClassShape { "y": 100 }, "ports": [{}] - } - classShape.ports = [] + }; + classShape.ports = []; // 定義下方函數名稱方塊 funcNames.forEach((funcName: string) => { // 代碼塊 連接桩 - let port = { + const port = { "id": myUtils.getClassShapeId(className, funcName, 'function'), "group": "list", "attrs": { @@ -215,12 +215,12 @@ class ClassShape { targetCodeBlock: myUtils.getCodeBlockShapeId(className, funcName), } } - } - classShape.ports.push(port) - }) + }; + classShape.ports.push(port); + }); - return classShape + return classShape; } } -export {ClassShape} +export {ClassShape}; diff --git a/src/CodeBlockShape.ts b/src/CodeBlockShape.ts index fec38aa..8fb5d49 100644 --- a/src/CodeBlockShape.ts +++ b/src/CodeBlockShape.ts @@ -1,12 +1,12 @@ import hljs from 'highlight.js'; -import {CodeData, Utils} from './Utils' +import {CodeData, Utils} from './Utils'; -const myUtils = new Utils() +const myUtils = new Utils(); type CodeBlockContent = { language: string, // 程式語言 code: string // 具體代碼 -} +}; class CodeBlockShape { @@ -18,23 +18,23 @@ class CodeBlockShape { public createCodeBlockShape(codeData: CodeData) { // 結果對象集合 - let result = [] + const result = []; // 將 CodeData 中的每個 func 的 code 轉換成 AntV 的 HTML 對象 - let codeDataFuncs = codeData.funcs + const codeDataFuncs = codeData.funcs; for (const codeDataFunc of codeDataFuncs) { // 獲取 代碼塊字串,並分割成行 - let codeText = codeDataFunc.code - let codeTextLines = codeText.split('\n') + const codeText = codeDataFunc.code; + const codeTextLines = codeText.split('\n'); // 獲取 代碼塊所需高度 - let blockHeight = myUtils.getTextHeight(codeDataFunc.code) + 30; + const blockHeight = myUtils.getTextHeight(codeDataFunc.code) + 30; // 計算代碼塊所需寬度 - let blockWidth = 0 + let blockWidth = 0; for (let i = 0; i < codeTextLines.length; i++) { - blockWidth = Math.max(blockWidth, myUtils.getTextWidth(codeTextLines[i], "13px") + 60) + blockWidth = Math.max(blockWidth, myUtils.getTextWidth(codeTextLines[i], "13px") + 60); } // 構建 HTML 對象 @@ -52,14 +52,14 @@ class CodeBlockShape { } }, html() { - const wrap = document.createElement('div') - wrap.innerHTML = '
' + hljs.highlight(codeText, {language: codeDataFunc.language}).value + '
' - return wrap + const wrap = document.createElement('div'); + wrap.innerHTML = '
' + hljs.highlight(codeText, {language: codeDataFunc.language}).value + '
'; + return wrap; }, - } + }; // 將 HTML 對象加入到返回結果中 - result.push(htmlShape) + result.push(htmlShape); } return result; diff --git a/src/Edge.ts b/src/Edge.ts index 3c51014..73fd3a1 100644 --- a/src/Edge.ts +++ b/src/Edge.ts @@ -1,7 +1,7 @@ import { Shape } from '@antv/x6'; -import { CodeData, Utils } from './Utils' +import { CodeData, Utils } from './Utils'; -const myUtils = new Utils() +const myUtils = new Utils(); class Edge { @@ -12,7 +12,7 @@ class Edge { */ public createFuncToCodeEdges(codeData: CodeData) { - let result = []; + const result = []; // 遍歷所有的 函數對象,替每個 函數 與 代碼塊圖形 創建 連線對象 for (const func of codeData.funcs) { @@ -44,10 +44,10 @@ class Edge { }, }, }, - }) + }); // 將 連線對象 加入到 返回結果 中 - result.push(edge) + result.push(edge); } return result; @@ -60,7 +60,7 @@ class Edge { */ public createFuncCallEdges(codeData: CodeData) { - let result = []; + const result = []; // 遍歷 CodeData 中的每個 函數對象 for (const func of codeData.funcs) { @@ -103,10 +103,10 @@ class Edge { stroke: "#2bb37b", }, }, - }) + }); // 將 連線對象 加入到 返回結果 中 - result.push(edge) + result.push(edge); } } @@ -115,4 +115,4 @@ class Edge { } -export { Edge } +export { Edge }; diff --git a/src/Graph.ts b/src/Graph.ts index 51f48a6..9c2a7db 100644 --- a/src/Graph.ts +++ b/src/Graph.ts @@ -1,15 +1,15 @@ -import {Cell, Graph, Shape} from '@antv/x6'; +import {Cell, Graph} from '@antv/x6'; import {CodeBlockContent, CodeBlockShape} from './CodeBlockShape'; import {ClassShape} from './ClassShape'; import {CLASS_SHAPE_ID_TAG, CODE_BLOCK_ID_TAG, CodeData, Utils} from './Utils'; -import {Edge} from './Edge' +import {Edge} from './Edge'; -const myUtils = new Utils() -const codeBlockShape = new CodeBlockShape() -const classShape = new ClassShape() -const edge = new Edge() +const myUtils = new Utils(); +const codeBlockShape = new CodeBlockShape(); +const classShape = new ClassShape(); +const edge = new Edge(); -export let initGraph = function (codeBlocks: CodeBlockContent[]) { +export const initGraph = function (codeBlocks: CodeBlockContent[]) { // 創建畫布 const graph = new Graph({ @@ -26,30 +26,30 @@ export let initGraph = function (codeBlocks: CodeBlockContent[]) { }); // 將 代碼塊字串 集合 解析成 CodeData 對象集合,並將相同 className 的對象進行合併 - let codeDatas: CodeData[] = [] + let codeDatas: CodeData[] = []; codeBlocks.forEach((codeBlock: CodeBlockContent) => { - let codeData: CodeData = myUtils.parseCodeData(codeBlock) - codeDatas.push(codeData) - }) - codeDatas = myUtils.mergeCodeDatas(codeDatas) + const codeData: CodeData = myUtils.parseCodeData(codeBlock); + codeDatas.push(codeData); + }); + codeDatas = myUtils.mergeCodeDatas(codeDatas); // 將 CodeData 對象列表 繪製成 類圖形、代碼塊圖形 for (const codeData of codeDatas) { // 將 類圖形、代碼塊圖形 加入到 畫布 中 - let funcNames = codeData.funcs.map(item => item.name) - graph.addNode(classShape.createClassShape(codeData.className, funcNames)) - graph.addNodes(codeBlockShape.createCodeBlockShape(codeData)) + const funcNames = codeData.funcs.map(item => item.name); + graph.addNode(classShape.createClassShape(codeData.className, funcNames)); + graph.addNodes(codeBlockShape.createCodeBlockShape(codeData)); // 創建 函數名稱 與 代碼塊圖形 的 連線 - graph.addEdges(edge.createFuncToCodeEdges(codeData)) + graph.addEdges(edge.createFuncToCodeEdges(codeData)); } // 繪製 CodeData 中的 函數調用 連線 for (const codeData of codeDatas) { - graph.addEdges(edge.createFuncCallEdges(codeData)) + graph.addEdges(edge.createFuncCallEdges(codeData)); } // 綁定 開啟/關閉 代碼塊圖形 事件 @@ -57,46 +57,46 @@ export let initGraph = function (codeBlocks: CodeBlockContent[]) { graph.on('toggle:codeBlock', ({e}) => { // 獲取 代碼塊圖形、開關文字 對象 - let codeBlock = graph.getCellById(e.currentTarget.getAttribute('target-code-block')) - let toggleText = e.currentTarget.parentNode.childNodes[5].children[0] + const codeBlock = graph.getCellById(e.currentTarget.getAttribute('target-code-block')); + const toggleText = e.currentTarget.parentNode.childNodes[5].children[0]; // 如果當前 代碼塊圖形 正在顯示,則關閉。反之則開啟 if (codeBlock.getProp().visible) { - codeBlock.hide() - toggleText.textContent = '+' - toggleText.setAttribute('dy', '0.3em') + codeBlock.hide(); + toggleText.textContent = '+'; + toggleText.setAttribute('dy', '0.3em'); } else { // 計算 代碼塊 顯示位置 - const intervalX = 100 - const posX = e.offsetX + intervalX - const posY = e.offsetY - (codeBlock.getProp().size.height / 2) - codeBlock.prop("position", {x: posX, y: posY}) + const intervalX = 100; + const posX = e.offsetX + intervalX; + const posY = e.offsetY - (codeBlock.getProp().size.height / 2); + codeBlock.prop("position", {x: posX, y: posY}); // 顯示 代碼塊,並更新按鈕內容 - codeBlock.show() - toggleText.textContent = '-' - toggleText.setAttribute('dy', '0.3em') + codeBlock.show(); + toggleText.textContent = '-'; + toggleText.setAttribute('dy', '0.3em'); } - }) + }); // 最大的 類圖形 的寬度 let maxClassShapeWidth = 0; // 所有的 類圖形 集合 - let classShapes: Cell[] = []; + const classShapes: Cell[] = []; // 遍歷 所有的圖形 for (const node of graph.getCells()) { // 默認隱藏所有的 代碼塊 if (node.id.startsWith(CODE_BLOCK_ID_TAG)) { - node.hide() + node.hide(); } // 計算 類圖形 最大寬度、加入到集合中 if (node.id.startsWith(CLASS_SHAPE_ID_TAG)) { - maxClassShapeWidth = Math.max(maxClassShapeWidth, node.getProp().size.width) - classShapes.push(node) + maxClassShapeWidth = Math.max(maxClassShapeWidth, node.getProp().size.width); + classShapes.push(node); } } @@ -104,23 +104,23 @@ export let initGraph = function (codeBlocks: CodeBlockContent[]) { * 計算 類圖形 的 座標 */ // 左側保留寬度 - const marginLeftWidth = 100 + const marginLeftWidth = 100; // 類圖形的 Y 座標 - let curY = 200 + let curY = 200; // 多個 類圖形 的 上下間格 - const intervalY = 150 + const intervalY = 150; // 所有 類圖形 的 中線 X 座標 - const midX = marginLeftWidth + (maxClassShapeWidth / 2) + const midX = marginLeftWidth + (maxClassShapeWidth / 2); for (const classShape of classShapes) { // 計算 類圖形 的 左上X 座標,並設置 - const posX = midX - (classShape.getProp().size.width / 2) - classShape.prop("position", {x: posX, y: curY}) + const posX = midX - (classShape.getProp().size.width / 2); + classShape.prop("position", {x: posX, y: curY}); // 下個 類圖形 的 Y 座標 = 當前 類圖形 高度 + 間隔 - curY = curY + classShape.getProp().size.height + intervalY + curY = curY + classShape.getProp().size.height + intervalY; } -} +}; diff --git a/src/SourceCodeView.ts b/src/SourceCodeView.ts index d1f27e3..1535c11 100644 --- a/src/SourceCodeView.ts +++ b/src/SourceCodeView.ts @@ -6,7 +6,7 @@ import {CodeBlockContent} from "./CodeBlockShape"; export default class SourceCodeView extends ItemView { // 代碼塊內容 集合 - codeBlocks: CodeBlockContent[] + codeBlocks: CodeBlockContent[]; constructor(codeBlocks: CodeBlockContent[], leaf: WorkspaceLeaf) { super(leaf); @@ -28,7 +28,7 @@ export default class SourceCodeView extends ItemView { container.empty(); // 創建 AntV 需要的容器 - const div = document.createElement("div") + const div = document.createElement("div"); div.id = 'container'; container.appendChild(div); diff --git a/src/Utils.ts b/src/Utils.ts index 2b49407..3e452cc 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -4,22 +4,22 @@ import {CodeBlockContent} from "./CodeBlockShape"; type CodeData = { className: string, // 類名稱 funcs: CodeDataFunc[] // 函數名稱 與 代碼塊字串 集合 -} +}; type CodeDataFunc = { language: string, // 程式語言 name: string, // 函數名稱 code: string, // 代碼塊字串 calls: CodeDataFuncCall[] // 調用的函數集合 -} +}; type CodeDataFuncCall = { className: string, // 類名稱 functionName: string // 函數名稱 -} +}; -export const CLASS_SHAPE_ID_TAG: string = "class-"; -export const CODE_BLOCK_ID_TAG: string = 'code-block-'; +export const CLASS_SHAPE_ID_TAG = "class-"; +export const CODE_BLOCK_ID_TAG = 'code-block-'; class Utils { @@ -43,12 +43,12 @@ class Utils { public getTextHeight(codeText: string) { // 創建一個新容器,將 HTML 代碼加入到容器中 - let node = document.createElement('div'); + const node = document.createElement('div'); node.innerHTML = '
' + hljs.highlight(codeText, {language: 'java'}).value + '
'; document.body.appendChild(node); // 計算 容器高度 - let height: number = parseInt(global.getComputedStyle(node).height.split('px')[0]); + const height: number = parseInt(global.getComputedStyle(node).height.split('px')[0]); // 移除容器 document.body.removeChild(node); @@ -67,61 +67,61 @@ class Utils { const content = codeBlockContent.code; // 類名、方法名 的 標示符 - const classTag = '@class' - const functionTag = '@function' - const callTag = '@call' + const classTag = '@class'; + const functionTag = '@function'; + const callTag = '@call'; - let codeLines = content.split('\n') + const codeLines = content.split('\n'); // 取得 註釋塊 的代碼 - let commentLines = [] + const commentLines = []; for (let i = 0; i < codeLines.length; i++) { - let codeLine = codeLines[i] + const codeLine = codeLines[i]; // 找到註釋開頭,則從當前行開始,加入到註釋塊列表中 if (codeLine.indexOf('/**') != -1) { - commentLines.push(codeLine) + commentLines.push(codeLine); } else if (commentLines.length > 0) { - commentLines.push(codeLine) + commentLines.push(codeLine); } // 當碰到第一個多行註釋的結尾,則跳出循環 if (codeLine.indexOf('*/') != -1) { - break + break; } } // 從 註釋塊 中獲取 類名、方法名、調用的函數集合 - let className = '' - let functionName = '' - let calls: CodeDataFuncCall[] = [] + let className = ''; + let functionName = ''; + const calls: CodeDataFuncCall[] = []; commentLines.forEach((comment) => { // 獲取 類名 if (comment.indexOf(classTag) != -1) { - className = comment.substring(comment.indexOf(classTag) + classTag.length).trim() + className = comment.substring(comment.indexOf(classTag) + classTag.length).trim(); } // 獲取 方法名 if (comment.indexOf(functionTag) != -1) { - functionName = comment.substring(comment.indexOf(functionTag) + functionTag.length).trim() + functionName = comment.substring(comment.indexOf(functionTag) + functionTag.length).trim(); } // 獲取 調用的函數 if (comment.indexOf(callTag) != -1) { - let callStr = comment.substring(comment.indexOf(callTag) + callTag.length).trim() + const callStr = comment.substring(comment.indexOf(callTag) + callTag.length).trim(); calls.push({ className: callStr.substring(0, callStr.indexOf('@')).trim(), functionName: callStr.substring(callStr.indexOf('@') + 1).trim() - }) + }); } - }) + }); // 封裝結果 - let result: CodeData = { + const result: CodeData = { className: className, funcs: [{ language: lang, @@ -129,9 +129,9 @@ class Utils { code: content, calls: calls }] - } + }; - return result + return result; } /** @@ -143,11 +143,11 @@ class Utils { */ public getClassShapeId(className: string, functionName: string, type: 'class' | 'function'): string { if (type == 'class') { - return CLASS_SHAPE_ID_TAG + className + return CLASS_SHAPE_ID_TAG + className; } else if (type == 'function') { - return CLASS_SHAPE_ID_TAG + className + '-' + functionName + return CLASS_SHAPE_ID_TAG + className + '-' + functionName; } - return '' + return ''; } /** @@ -157,7 +157,7 @@ class Utils { * @returns 圖形Id */ public getCodeBlockShapeId(className: string, functionName: string): string { - return CODE_BLOCK_ID_TAG + className + '-' + functionName + return CODE_BLOCK_ID_TAG + className + '-' + functionName; } /** @@ -168,27 +168,27 @@ class Utils { public mergeCodeDatas(codeDatas: CodeData[]): CodeData[] { // 對有相同 className 的 CodeData 的 func 進行合併 - let classNameToCodeData = new Map() + const classNameToCodeData = new Map(); codeDatas.forEach((codeData: CodeData) => { // 如果在 Map 中已存在相應的 CodeData,則將 func 進行合併 if (classNameToCodeData.has(codeData.className)) { - let tempCodeData = classNameToCodeData.get(codeData.className) as CodeData - tempCodeData.funcs.push(codeData.funcs[0]) + const tempCodeData = classNameToCodeData.get(codeData.className) as CodeData; + tempCodeData.funcs.push(codeData.funcs[0]); } // 如果在 Map 中還沒有相應的 CodeData,則將當前 CodeData 加入到 Map 中 else { - classNameToCodeData.set(codeData.className, codeData) + classNameToCodeData.set(codeData.className, codeData); } - }) + }); // 封裝返回結果 - let result: CodeData[] = [] - for (let codeData of Array.from(classNameToCodeData.values())) { - result.push(codeData) + const result: CodeData[] = []; + for (const codeData of Array.from(classNameToCodeData.values())) { + result.push(codeData); } - return result + return result; } } diff --git a/src/main.ts b/src/main.ts index 1c70a7f..ce46a57 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,13 +1,13 @@ -import {Plugin, Workspace, WorkspaceLeaf} from 'obsidian'; +import {Plugin, WorkspaceLeaf} from 'obsidian'; import SourceCodeView from "./SourceCodeView"; import {CodeBlockContent} from "./CodeBlockShape"; -export const SOURCE_CODE_VIEW_TYPE = 'source-code-view' +export const SOURCE_CODE_VIEW_TYPE = 'source-code-view'; export default class SourceCodeViewPlugin extends Plugin { // Obsidian 中 Markdown 的 代碼塊內容 集合 - codeBlockContents: CodeBlockContent[] = [] + codeBlockContents: CodeBlockContent[] = []; /** * 載入插件時,註冊相關組件 @@ -22,7 +22,7 @@ export default class SourceCodeViewPlugin extends Plugin { // 註冊 Obsidian 左側的按鈕 this.addRibbonIcon("file-json", "Show Resource Code View", () => { - this.initView() + this.initView(); }); } @@ -45,7 +45,7 @@ export default class SourceCodeViewPlugin extends Plugin { this.app.vault.process(activeFile, (data) => { // 清理數據 - this.codeBlockContents = [] + this.codeBlockContents = []; // 獲取文件內所有的 Markdown 代碼塊 const regex = /```(\w+)\s([\s\S]*?)```/gm; @@ -53,16 +53,16 @@ export default class SourceCodeViewPlugin extends Plugin { while ((match = regex.exec(data)) !== null) { const lang = match[1]; // 程式語言 const content = match[2]; // 代碼塊內容 - this.codeBlockContents.push({language: lang, code: content}) + this.codeBlockContents.push({language: lang, code: content}); } // 開啟分頁 - const preview = this.app.workspace.getLeaf('split', 'vertical') + const preview = this.app.workspace.getLeaf('split', 'vertical'); const mmPreview = new SourceCodeView(this.codeBlockContents, preview); - preview.open(mmPreview) + preview.open(mmPreview); // 不更改文件內容 - return data + return data; }); }