新增 被調用的函數集合屬性

This commit is contained in:
Waiting 2024-06-03 23:40:40 +08:00
parent aff1ac6efc
commit 2ae559fcaf
4 changed files with 167 additions and 115 deletions

1
.gitignore vendored
View file

@ -20,3 +20,4 @@ data.json
# Exclude macOS Finder (System Explorer) View States # Exclude macOS Finder (System Explorer) View States
.DS_Store .DS_Store
package-lock.json

View file

@ -30,110 +30,124 @@ Graph.registerPortLayout(
/** /**
* *
*/ */
Graph.registerNode( let clazzShapeDef = {
'clazz-shape', // 最上層 class 名稱
{ inherit: 'rect',
// 最上層 class 名稱 markup: [
inherit: 'rect', {
markup: [ tagName: 'rect',
{ selector: 'body',
tagName: 'rect',
selector: 'body',
},
{
tagName: 'text',
selector: 'label',
},
],
attrs: {
rect: {
strokeWidth: 1,
stroke: '#e5885c',
fill: '#fd9a6c',
},
label: {
fontWeight: 'bold',
fill: '#ffffff',
fontSize: 14,
textAnchor: 'middle',
textVerticalAnchor: 'middle'
},
}, },
// 該 class 所屬的方法列表 {
ports: { tagName: 'text',
groups: { selector: 'label',
list: { },
position: 'classFuncPosition', ],
markup: [ attrs: {
{ rect: {
tagName: 'rect', strokeWidth: 1,
selector: 'func', stroke: '#e5885c',
}, fill: '#fd9a6c',
{ },
tagName: 'text', label: {
selector: 'funcName', fontWeight: 'bold',
}, fill: '#ffffff',
{ fontSize: 14,
tagName: 'circle', textAnchor: 'middle',
selector: 'funcInCircle' textVerticalAnchor: 'middle'
}, },
{ },
tagName: 'circle', // 該 class 所屬的方法列表
selector: 'funcOutCircle' ports: {
}, groups: {
{ list: {
tagName: 'circle', position: 'classFuncPosition',
selector: 'toggle' markup: [
}, {
{ tagName: 'rect',
tagName: 'text', selector: 'func',
selector: 'toggleText'
}
],
attrs: {
func: {
strokeWidth: 1,
stroke: '#e5885c',
fill: '#FFFFFF',
},
funcName: {
fontSize: 13,
textAnchor: 'middle',
textVerticalAnchor: 'middle'
},
funcInCircle: {
r: 5,
stroke: '#efab7c',
strokeWidth: 1,
fill: '#fff'
},
funcOutCircle: {
r: 5,
stroke: '#efab7c',
strokeWidth: 1,
fill: '#fff'
},
toggle: {
r: 7,
stroke: '#b2bec3',
strokeWidth: 2,
fill: '#fff',
cursor: 'pointer',
},
toggleText: {
fontSize: 12,
fontWeight: 800,
fill: '#b2bec3',
textAnchor: 'middle',
textVerticalAnchor: 'middle',
'pointer-events': 'none', // 避免按鈕不靈敏
cursor: 'pointer',
}
}, },
{
tagName: 'text',
selector: 'funcName',
},
{
tagName: 'circle',
selector: 'funcInCircle'
},
// {
// tagName: 'circle',
// selector: 'funcOutCircle'
// },
{
tagName: 'circle',
selector: 'toggle'
},
{
tagName: 'text',
selector: 'toggleText'
}
],
attrs: {
func: {
strokeWidth: 1,
stroke: '#e5885c',
fill: '#FFFFFF',
},
funcName: {
fontSize: 13,
textAnchor: 'middle',
textVerticalAnchor: 'middle'
},
funcInCircle: {
r: 5,
stroke: '#efab7c',
strokeWidth: 1,
fill: '#fff'
},
// funcOutCircle: {
// r: 5,
// stroke: '#efab7c',
// strokeWidth: 1,
// fill: '#fff'
// },
toggle: {
r: 7,
stroke: '#b2bec3',
strokeWidth: 2,
fill: '#fff',
cursor: 'pointer',
},
toggleText: {
fontSize: 12,
fontWeight: 800,
fill: '#b2bec3',
textAnchor: 'middle',
textVerticalAnchor: 'middle',
'pointer-events': 'none', // 避免按鈕不靈敏
cursor: 'pointer',
}
}, },
}, },
}, },
}, },
};
clazzShapeDef.ports.groups.list.markup.push( {
tagName: 'circle',
selector: 'funcOutCircle'
});
clazzShapeDef.ports.groups.list.attrs.funcOutCircle = {
r: 5,
stroke: '#efab7c',
strokeWidth: 1,
fill: '#fff'
}
Graph.registerNode(
'clazz-shape',
clazzShapeDef,
true, true,
); );
@ -170,7 +184,6 @@ class ClassShape {
}; };
classShape.ports = []; classShape.ports = [];
// 定義下方函數名稱方塊 // 定義下方函數名稱方塊
funcNames.forEach((funcName: string) => { funcNames.forEach((funcName: string) => {

View file

@ -25,14 +25,18 @@ export const initGraph = function (codeBlocks: CodeBlockContent[]) {
}, },
}); });
// 將 代碼塊字串 集合 解析成 CodeData 對象集合,並將相同 className 的對象進行合併 // 將 代碼塊字串 集合 解析成 CodeData 對象集合
let codeDatas: CodeData[] = []; let codeDatas: CodeData[] = [];
codeBlocks.forEach((codeBlock: CodeBlockContent) => { codeBlocks.forEach((codeBlock: CodeBlockContent) => {
const codeData: CodeData = myUtils.parseCodeData(codeBlock); const codeData: CodeData = myUtils.parseCodeData(codeBlock);
codeDatas.push(codeData); codeDatas.push(codeData);
}); });
// 將相同 className 的對象進行合併
codeDatas = myUtils.mergeCodeDatas(codeDatas); codeDatas = myUtils.mergeCodeDatas(codeDatas);
// 設置 CodeDataFunc 中的 calleds 屬性
myUtils.setCalleds(codeDatas);
// 將 CodeData 對象列表 繪製成 類圖形、代碼塊圖形 // 將 CodeData 對象列表 繪製成 類圖形、代碼塊圖形
for (const codeData of codeDatas) { for (const codeData of codeDatas) {

View file

@ -1,5 +1,5 @@
import hljs from "highlight.js"; import hljs from "highlight.js";
import {CodeBlockContent} from "./CodeBlockShape"; import { CodeBlockContent } from "./CodeBlockShape";
type CodeData = { type CodeData = {
className: string, // 類名稱 className: string, // 類名稱
@ -10,7 +10,8 @@ type CodeDataFunc = {
language: string, // 程式語言 language: string, // 程式語言
name: string, // 函數名稱 name: string, // 函數名稱
code: string, // 代碼塊字串 code: string, // 代碼塊字串
calls: CodeDataFuncCall[] // 調用的函數集合 calls: CodeDataFuncCall[], // 調用的函數集合
calleds: CodeDataFuncCall[], // 被調用的函數集合
}; };
type CodeDataFuncCall = { type CodeDataFuncCall = {
@ -21,6 +22,9 @@ type CodeDataFuncCall = {
export const CLASS_SHAPE_ID_TAG = "class-"; export const CLASS_SHAPE_ID_TAG = "class-";
export const CODE_BLOCK_ID_TAG = 'code-block-'; export const CODE_BLOCK_ID_TAG = 'code-block-';
// Key: 函數的唯一標示符Value: 函數對象
const funcNameToFunc = new Map<string, CodeDataFunc>();
class Utils { class Utils {
/** /**
@ -44,7 +48,7 @@ class Utils {
// 創建一個新容器,將 HTML 代碼加入到容器中 // 創建一個新容器,將 HTML 代碼加入到容器中
const node = document.createElement('div'); const node = document.createElement('div');
node.innerHTML = '<pre style="padding-left: 20px">' + hljs.highlight(codeText, {language: 'java'}).value + '</pre>'; node.innerHTML = '<pre style="padding-left: 20px">' + hljs.highlight(codeText, { language: 'java' }).value + '</pre>';
document.body.appendChild(node); document.body.appendChild(node);
// 計算 容器高度 // 計算 容器高度
@ -94,8 +98,15 @@ class Utils {
// 從 註釋塊 中獲取 類名、方法名、調用的函數集合 // 從 註釋塊 中獲取 類名、方法名、調用的函數集合
let className = ''; let className = '';
let functionName = '';
const calls: CodeDataFuncCall[] = []; const calls: CodeDataFuncCall[] = [];
const calleds: CodeDataFuncCall[] = [];
let codeDataFunc = {
language: lang,
name: '',
code: content,
calls: calls,
calleds: calleds
};
commentLines.forEach((comment) => { commentLines.forEach((comment) => {
@ -106,16 +117,20 @@ class Utils {
// 獲取 方法名 // 獲取 方法名
if (comment.indexOf(functionTag) != -1) { if (comment.indexOf(functionTag) != -1) {
functionName = comment.substring(comment.indexOf(functionTag) + functionTag.length).trim(); codeDataFunc.name = comment.substring(comment.indexOf(functionTag) + functionTag.length).trim();
// 保存 到 共用 Map 中
funcNameToFunc.set(this.getClassShapeId(className, codeDataFunc.name, 'function'), codeDataFunc);
} }
// 獲取 調用的函數 // 獲取 調用的函數
if (comment.indexOf(callTag) != -1) { if (comment.indexOf(callTag) != -1) {
const callStr = comment.substring(comment.indexOf(callTag) + callTag.length).trim(); const callStr = comment.substring(comment.indexOf(callTag) + callTag.length).trim();
calls.push({ const call = {
className: callStr.substring(0, callStr.indexOf('@')).trim(), className: callStr.substring(0, callStr.indexOf('@')).trim(),
functionName: callStr.substring(callStr.indexOf('@') + 1).trim() functionName: callStr.substring(callStr.indexOf('@') + 1).trim()
}); }
calls.push(call);
} }
}); });
@ -123,12 +138,7 @@ class Utils {
// 封裝結果 // 封裝結果
const result: CodeData = { const result: CodeData = {
className: className, className: className,
funcs: [{ funcs: [codeDataFunc]
language: lang,
name: functionName,
code: content,
calls: calls
}]
}; };
return result; return result;
@ -190,9 +200,33 @@ class Utils {
return result; return result;
} }
/**
* CodeData CodeDataFunc calleds
* @param codeDatas CodeData
*/
public setCalleds(codeDatas: CodeData[]) {
// 遍歷 呼叫函數 的 對象屬性
for (const codeData of codeDatas) {
for (const codeDataFunc of codeData.funcs) {
for (const call of codeDataFunc.calls) {
// 取得 被調用的 函數對象
let calledCodeDataFunc: CodeDataFunc | undefined = funcNameToFunc.get(this.getClassShapeId(call.className, call.functionName, 'function'));
// 將 呼叫函數對象的屬性 加入到 被調用的函數對象 的 被調用函數集合 中
calledCodeDataFunc?.calleds.push({
className: codeDataFunc.name,
functionName: codeData.className
});
}
}
}
}
} }
export {Utils}; export { Utils };
export type {CodeData, CodeDataFunc}; export type { CodeData, CodeDataFunc };