Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 29 additions & 37 deletions jig-core/src/main/resources/templates/assets/package.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
// 状態/DOMヘルパー
// contextは「UI状態・設定値など長期的に保持する値」に限定する。
// 一時的な中間データはcontextに保存せず、関数内のローカル変数で扱う。
const packageContext = {
packageSummaryCache: null,
diagramNodeIdToFqn: new Map(),
aggregationDepth: 0,
diagramElement: null,
pendingDiagramRender: null,
lastDiagramSource: '',
lastDiagramEdgeCount: 0,
DEFAULT_MAX_EDGES: 500,
packageFilterFqn: null,
relatedFilterMode: 'direct',
relatedFilterFqn: null,
Expand All @@ -16,6 +13,7 @@ const packageContext = {
};

const DIAGRAM_CLICK_HANDLER_NAME = 'filterPackageDiagram';
const DEFAULT_MAX_EDGES = 500;

const dom = {
getRelatedFilterTarget: () => document.getElementById('related-filter-target'),
Expand Down Expand Up @@ -881,8 +879,7 @@ function getOrCreateDiagramErrorBox(diagram) {
return dom.createDiagramErrorBox(diagram);
}

function showDiagramErrorMessage(message, withAction, err, hash, context) {
const diagram = context.diagramElement;
function showDiagramErrorMessage(diagram, message, pendingRender, err, hash) {
if (!diagram) return;
console.error(message);
if (err) {
Expand All @@ -896,12 +893,11 @@ function showDiagramErrorMessage(message, withAction, err, hash, context) {
const actionNode = dom.getDiagramErrorActionNode();
dom.setNodeTextContent(messageNode, message);
if (actionNode) {
dom.setNodeDisplay(actionNode, withAction ? '' : 'none');
if (withAction) {
const hasAction = Boolean(pendingRender);
dom.setNodeDisplay(actionNode, hasAction ? '' : 'none');
if (hasAction) {
dom.setNodeOnClick(actionNode, function () {
if (!context.pendingDiagramRender) return;
renderDiagramWithMermaid(context.pendingDiagramRender.text, context.pendingDiagramRender.maxEdges, context);
context.pendingDiagramRender = null;
renderDiagramWithMermaid(diagram, pendingRender.text, pendingRender.maxEdges);
});
} else {
dom.setNodeOnClick(actionNode, null);
Expand All @@ -922,8 +918,7 @@ function hideDiagramErrorMessage(diagram) {
dom.setDiagramElementDisplay(diagram, '');
}

function renderDiagramWithMermaid(text, maxEdges, context) {
const diagram = context.diagramElement;
function renderDiagramWithMermaid(diagram, text, maxEdges) {
if (!diagram || !window.mermaid) return;
hideDiagramErrorMessage(diagram);
dom.removeDiagramAttribute(diagram, 'data-processed');
Expand All @@ -933,10 +928,10 @@ function renderDiagramWithMermaid(text, maxEdges, context) {
}

// 描画/更新
function renderMutualDependencyList(mutualPairs, causeRelationEvidence, context) {
function renderMutualDependencyList(mutualPairs, causeRelationEvidence, aggregationDepth) {
const container = dom.getMutualDependencyList();
if (!container) return;
const items = buildMutualDependencyItems(mutualPairs, causeRelationEvidence, context.aggregationDepth);
const items = buildMutualDependencyItems(mutualPairs, causeRelationEvidence, aggregationDepth);
if (items.length === 0) {
container.style.display = 'none';
container.innerHTML = '';
Expand Down Expand Up @@ -970,13 +965,12 @@ function renderMutualDependencyList(mutualPairs, causeRelationEvidence, context)
function renderPackageDiagram(context, packageFilterFqn, relatedFilterFqn) {
const diagram = dom.getDiagram();
if (!diagram) return;
context.diagramElement = diagram;

const renderPlan = buildDiagramRenderPlan(context, packageFilterFqn, relatedFilterFqn);
applyDiagramRenderPlan(context, renderPlan);
if (shouldSkipDiagramRenderByEdgeLimit(context)) return;
setDiagramSource(diagram, context.lastDiagramSource);
renderDiagramWithMermaidIfAvailable(context);
if (shouldSkipDiagramRenderByEdgeLimit(diagram, renderPlan, context)) return;
setDiagramSource(diagram, renderPlan.source);
renderDiagramWithMermaidIfAvailable(diagram, renderPlan, context);
}

function buildDiagramRenderPlan(context, packageFilterFqn, relatedFilterFqn) {
Expand Down Expand Up @@ -1013,20 +1007,19 @@ function buildDiagramRenderPlan(context, packageFilterFqn, relatedFilterFqn) {

function applyDiagramRenderPlan(context, renderPlan) {
context.diagramNodeIdToFqn = renderPlan.nodeIdToFqn;
renderMutualDependencyList(renderPlan.mutualPairs, renderPlan.filteredCauseRelationEvidence, context);
context.lastDiagramSource = renderPlan.source;
context.lastDiagramEdgeCount = renderPlan.uniqueRelations.length;
renderMutualDependencyList(renderPlan.mutualPairs, renderPlan.filteredCauseRelationEvidence, context.aggregationDepth);
}

function shouldSkipDiagramRenderByEdgeLimit(context) {
if (context.lastDiagramEdgeCount <= context.DEFAULT_MAX_EDGES) return false;
context.pendingDiagramRender = {text: context.lastDiagramSource, maxEdges: context.lastDiagramEdgeCount};
function shouldSkipDiagramRenderByEdgeLimit(diagram, renderPlan, context) {
const edgeCount = renderPlan.uniqueRelations.length;
if (edgeCount <= DEFAULT_MAX_EDGES) return false;
const pendingRender = {text: renderPlan.source, maxEdges: edgeCount};
const message = [
'関連数が多すぎるため描画を省略しました。',
`エッジ数: ${context.lastDiagramEdgeCount}(上限: ${context.DEFAULT_MAX_EDGES})`,
`エッジ数: ${edgeCount}(上限: ${DEFAULT_MAX_EDGES})`,
'描画する場合はボタンを押してください。',
].join('\n');
showDiagramErrorMessage(message, true, null, null, context);
showDiagramErrorMessage(diagram, message, pendingRender, null, null);
return true;
}

Expand All @@ -1035,22 +1028,21 @@ function setDiagramSource(diagram, source) {
diagram.textContent = source;
}

function renderDiagramWithMermaidIfAvailable(context) {
function renderDiagramWithMermaidIfAvailable(diagram, renderPlan, context) {
if (!window.mermaid) return;
ensureMermaidParseErrorHandler(context);
renderDiagramWithMermaid(context.lastDiagramSource, context.DEFAULT_MAX_EDGES, context);
ensureMermaidParseErrorHandler(diagram, renderPlan, context);
renderDiagramWithMermaid(diagram, renderPlan.source, DEFAULT_MAX_EDGES);
}

function ensureMermaidParseErrorHandler(context) {
if (mermaid.parseError) return;
function ensureMermaidParseErrorHandler(diagram, renderPlan, context) {
mermaid.parseError = function (err, hash) {
const message = err && err.message ? err.message : String(err);
const location = hash ? `\nLine: ${hash.line} Column: ${hash.loc}` : '';
const isEdgeLimit = message.includes('Edge limit exceeded');
if (isEdgeLimit) {
context.pendingDiagramRender = {text: context.lastDiagramSource, maxEdges: context.lastDiagramEdgeCount};
}
showDiagramErrorMessage(`Mermaid parse error: ${message}${location}`, isEdgeLimit, err, hash, context);
const pendingRender = isEdgeLimit
? {text: renderPlan.source, maxEdges: renderPlan.uniqueRelations.length}
: null;
showDiagramErrorMessage(diagram, `Mermaid parse error: ${message}${location}`, pendingRender, err, hash);
};
}

Expand Down
13 changes: 3 additions & 10 deletions jig-core/src/test/js/package.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,6 @@ function setupDiagramEnvironment(doc, context) {
const diagram = doc.createElement('div');
diagram.id = 'package-relation-diagram';
container.appendChild(diagram);
context.diagramElement = diagram;
const mutual = doc.createElement('div');
mutual.id = 'mutual-dependency-list';
doc.elementsById.set('mutual-dependency-list', mutual);
Expand All @@ -254,11 +253,6 @@ test.describe('package.js', () => {
packageSummaryCache: null,
diagramNodeIdToFqn: new Map(),
aggregationDepth: 0,
diagramElement: null,
pendingDiagramRender: null,
lastDiagramSource: '',
lastDiagramEdgeCount: 0,
DEFAULT_MAX_EDGES: 500,
packageFilterFqn: null,
relatedFilterMode: 'direct',
relatedFilterFqn: null,
Expand Down Expand Up @@ -872,7 +866,7 @@ test.describe('package.js', () => {
{from: 'app.alpha.A', to: 'app.beta.B'},
{from: 'app.beta.B', to: 'app.alpha.A'},
],
testContext
testContext.aggregationDepth
);

assert.equal(container.style.display, '');
Expand Down Expand Up @@ -906,9 +900,8 @@ test.describe('package.js', () => {

test('renderPackageDiagram: エッジ数超過時は保留/エラー表示する', () => {
const doc = setupDocument();
// setupDiagramEnvironmentはtestContext.diagramElementを設定する。
// そのdiagramElementがdomヘルパーによって操作されることをモックする。
const diagramMock = setupDiagramEnvironment(doc, testContext); // testContext.diagramElementも設定される
// setupDiagramEnvironmentが作るdiagramをdomヘルパーが操作することをモックする。
const diagramMock = setupDiagramEnvironment(doc, testContext);

// Mock dom helpers used by showDiagramErrorMessage internally
const errorBoxMock = { style: { display: 'none' } };
Expand Down