@flanksource/clicky-ui 0.3.45 → 0.3.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE.md +11 -0
- package/README.md +22 -0
- package/dist/ai.cjs +13 -8
- package/dist/ai.cjs.map +1 -1
- package/dist/ai.js +7 -2
- package/dist/ai.js.map +1 -1
- package/dist/components/ErrorWrapper.cjs +2 -3
- package/dist/components/ErrorWrapper.cjs.map +1 -1
- package/dist/components/ErrorWrapper.d.ts.map +1 -1
- package/dist/components/ErrorWrapper.js +3 -4
- package/dist/components/ErrorWrapper.js.map +1 -1
- package/dist/data/AccessMark.cjs +23 -0
- package/dist/data/AccessMark.cjs.map +1 -0
- package/dist/data/AccessMark.d.ts +11 -0
- package/dist/data/AccessMark.d.ts.map +1 -0
- package/dist/data/AccessMark.js +23 -0
- package/dist/data/AccessMark.js.map +1 -0
- package/dist/data/Clicky.cjs +3 -0
- package/dist/data/Clicky.cjs.map +1 -1
- package/dist/data/Clicky.js +3 -0
- package/dist/data/Clicky.js.map +1 -1
- package/dist/data/CodeDiff.cjs +116 -23
- package/dist/data/CodeDiff.cjs.map +1 -1
- package/dist/data/CodeDiff.d.ts +26 -0
- package/dist/data/CodeDiff.d.ts.map +1 -1
- package/dist/data/CodeDiff.js +116 -23
- package/dist/data/CodeDiff.js.map +1 -1
- package/dist/data/FilterPill.cjs +15 -2
- package/dist/data/FilterPill.cjs.map +1 -1
- package/dist/data/FilterPill.d.ts +1 -1
- package/dist/data/FilterPill.d.ts.map +1 -1
- package/dist/data/FilterPill.js +15 -2
- package/dist/data/FilterPill.js.map +1 -1
- package/dist/data/GraphDiagram.cjs +65 -13
- package/dist/data/GraphDiagram.cjs.map +1 -1
- package/dist/data/GraphDiagram.d.ts +9 -2
- package/dist/data/GraphDiagram.d.ts.map +1 -1
- package/dist/data/GraphDiagram.js +66 -14
- package/dist/data/GraphDiagram.js.map +1 -1
- package/dist/data/GraphDiagramGroups.cjs +100 -0
- package/dist/data/GraphDiagramGroups.cjs.map +1 -0
- package/dist/data/GraphDiagramGroups.d.ts +24 -0
- package/dist/data/GraphDiagramGroups.d.ts.map +1 -0
- package/dist/data/GraphDiagramGroups.js +100 -0
- package/dist/data/GraphDiagramGroups.js.map +1 -0
- package/dist/data/GraphDiagramNodes.cjs +17 -31
- package/dist/data/GraphDiagramNodes.cjs.map +1 -1
- package/dist/data/GraphDiagramNodes.d.ts +6 -13
- package/dist/data/GraphDiagramNodes.d.ts.map +1 -1
- package/dist/data/GraphDiagramNodes.js +17 -31
- package/dist/data/GraphDiagramNodes.js.map +1 -1
- package/dist/data/LogViewer.cjs +27 -8
- package/dist/data/LogViewer.cjs.map +1 -1
- package/dist/data/LogViewer.d.ts +11 -3
- package/dist/data/LogViewer.d.ts.map +1 -1
- package/dist/data/LogViewer.js +27 -8
- package/dist/data/LogViewer.js.map +1 -1
- package/dist/data/Properties.cjs +2 -15
- package/dist/data/Properties.cjs.map +1 -1
- package/dist/data/Properties.d.ts +4 -0
- package/dist/data/Properties.d.ts.map +1 -1
- package/dist/data/Properties.js +2 -15
- package/dist/data/Properties.js.map +1 -1
- package/dist/data/PropertyValue.cjs +37 -0
- package/dist/data/PropertyValue.cjs.map +1 -0
- package/dist/data/PropertyValue.d.ts +6 -0
- package/dist/data/PropertyValue.d.ts.map +1 -0
- package/dist/data/PropertyValue.js +37 -0
- package/dist/data/PropertyValue.js.map +1 -0
- package/dist/data/Tree.cjs +4 -3
- package/dist/data/Tree.cjs.map +1 -1
- package/dist/data/Tree.d.ts +3 -1
- package/dist/data/Tree.d.ts.map +1 -1
- package/dist/data/Tree.js +4 -3
- package/dist/data/Tree.js.map +1 -1
- package/dist/data/TreeNode.cjs +1 -1
- package/dist/data/TreeNode.cjs.map +1 -1
- package/dist/data/TreeNode.d.ts.map +1 -1
- package/dist/data/TreeNode.js +1 -1
- package/dist/data/TreeNode.js.map +1 -1
- package/dist/data/ai/ChatFab.cjs +1 -1
- package/dist/data/ai/ChatFab.cjs.map +1 -1
- package/dist/data/ai/ChatFab.js +1 -1
- package/dist/data/ai/ChatFab.js.map +1 -1
- package/dist/data/ai/ChatWindow.cjs +106 -171
- package/dist/data/ai/ChatWindow.cjs.map +1 -1
- package/dist/data/ai/ChatWindow.d.ts +6 -2
- package/dist/data/ai/ChatWindow.d.ts.map +1 -1
- package/dist/data/ai/ChatWindow.header.cjs +104 -0
- package/dist/data/ai/ChatWindow.header.cjs.map +1 -0
- package/dist/data/ai/ChatWindow.header.d.ts +29 -0
- package/dist/data/ai/ChatWindow.header.d.ts.map +1 -0
- package/dist/data/ai/ChatWindow.header.js +104 -0
- package/dist/data/ai/ChatWindow.header.js.map +1 -0
- package/dist/data/ai/ChatWindow.js +107 -172
- package/dist/data/ai/ChatWindow.js.map +1 -1
- package/dist/data/ai/ChatWindow.placement.cjs +95 -0
- package/dist/data/ai/ChatWindow.placement.cjs.map +1 -0
- package/dist/data/ai/ChatWindow.placement.d.ts +32 -0
- package/dist/data/ai/ChatWindow.placement.d.ts.map +1 -0
- package/dist/data/ai/ChatWindow.placement.js +95 -0
- package/dist/data/ai/ChatWindow.placement.js.map +1 -0
- package/dist/data/ai/SessionChatComposer.cjs +3 -1
- package/dist/data/ai/SessionChatComposer.cjs.map +1 -1
- package/dist/data/ai/SessionChatComposer.d.ts +4 -1
- package/dist/data/ai/SessionChatComposer.d.ts.map +1 -1
- package/dist/data/ai/SessionChatComposer.js +3 -1
- package/dist/data/ai/SessionChatComposer.js.map +1 -1
- package/dist/data/ai/SessionInspector.cjs +68 -72
- package/dist/data/ai/SessionInspector.cjs.map +1 -1
- package/dist/data/ai/SessionInspector.composer-slot.cjs +8 -0
- package/dist/data/ai/SessionInspector.composer-slot.cjs.map +1 -0
- package/dist/data/ai/SessionInspector.composer-slot.d.ts +9 -0
- package/dist/data/ai/SessionInspector.composer-slot.d.ts.map +1 -0
- package/dist/data/ai/SessionInspector.composer-slot.js +8 -0
- package/dist/data/ai/SessionInspector.composer-slot.js.map +1 -0
- package/dist/data/ai/SessionInspector.d.ts +6 -1
- package/dist/data/ai/SessionInspector.d.ts.map +1 -1
- package/dist/data/ai/SessionInspector.js +69 -73
- package/dist/data/ai/SessionInspector.js.map +1 -1
- package/dist/data/ai/SessionInspector.legacy.cjs +41 -42
- package/dist/data/ai/SessionInspector.legacy.cjs.map +1 -1
- package/dist/data/ai/SessionInspector.legacy.d.ts.map +1 -1
- package/dist/data/ai/SessionInspector.legacy.js +41 -42
- package/dist/data/ai/SessionInspector.legacy.js.map +1 -1
- package/dist/data/ai/SessionInspector.remote-view.cjs +14 -9
- package/dist/data/ai/SessionInspector.remote-view.cjs.map +1 -1
- package/dist/data/ai/SessionInspector.remote-view.d.ts +6 -2
- package/dist/data/ai/SessionInspector.remote-view.d.ts.map +1 -1
- package/dist/data/ai/SessionInspector.remote-view.js +14 -9
- package/dist/data/ai/SessionInspector.remote-view.js.map +1 -1
- package/dist/data/ai/SessionInspector.remote.cjs +84 -16
- package/dist/data/ai/SessionInspector.remote.cjs.map +1 -1
- package/dist/data/ai/SessionInspector.remote.d.ts +42 -7
- package/dist/data/ai/SessionInspector.remote.d.ts.map +1 -1
- package/dist/data/ai/SessionInspector.remote.js +86 -18
- package/dist/data/ai/SessionInspector.remote.js.map +1 -1
- package/dist/data/ai/SessionInspector.transcript.cjs +5 -0
- package/dist/data/ai/SessionInspector.transcript.cjs.map +1 -1
- package/dist/data/ai/SessionInspector.transcript.d.ts.map +1 -1
- package/dist/data/ai/SessionInspector.transcript.js +5 -0
- package/dist/data/ai/SessionInspector.transcript.js.map +1 -1
- package/dist/data/ai/SessionTail.cjs +63 -0
- package/dist/data/ai/SessionTail.cjs.map +1 -0
- package/dist/data/ai/SessionTail.d.ts +14 -0
- package/dist/data/ai/SessionTail.d.ts.map +1 -0
- package/dist/data/ai/SessionTail.js +63 -0
- package/dist/data/ai/SessionTail.js.map +1 -0
- package/dist/data/ai/SessionViewer.cjs +10 -3
- package/dist/data/ai/SessionViewer.cjs.map +1 -1
- package/dist/data/ai/SessionViewer.d.ts +7 -1
- package/dist/data/ai/SessionViewer.d.ts.map +1 -1
- package/dist/data/ai/SessionViewer.js +10 -3
- package/dist/data/ai/SessionViewer.js.map +1 -1
- package/dist/data/ai/SessionViewer.unified.d.ts +14 -0
- package/dist/data/ai/SessionViewer.unified.d.ts.map +1 -1
- package/dist/data/ai/index.d.ts +4 -3
- package/dist/data/ai/index.d.ts.map +1 -1
- package/dist/data/ai/use-session-scroll.cjs +30 -6
- package/dist/data/ai/use-session-scroll.cjs.map +1 -1
- package/dist/data/ai/use-session-scroll.d.ts +7 -0
- package/dist/data/ai/use-session-scroll.d.ts.map +1 -1
- package/dist/data/ai/use-session-scroll.js +30 -6
- package/dist/data/ai/use-session-scroll.js.map +1 -1
- package/dist/data/call-graph/CallGraph.cjs +50 -31
- package/dist/data/call-graph/CallGraph.cjs.map +1 -1
- package/dist/data/call-graph/CallGraph.d.ts +10 -1
- package/dist/data/call-graph/CallGraph.d.ts.map +1 -1
- package/dist/data/call-graph/CallGraph.js +52 -33
- package/dist/data/call-graph/CallGraph.js.map +1 -1
- package/dist/data/call-graph/CallGraphMembers.cjs +5 -4
- package/dist/data/call-graph/CallGraphMembers.cjs.map +1 -1
- package/dist/data/call-graph/CallGraphMembers.d.ts +1 -1
- package/dist/data/call-graph/CallGraphMembers.d.ts.map +1 -1
- package/dist/data/call-graph/CallGraphMembers.js +5 -4
- package/dist/data/call-graph/CallGraphMembers.js.map +1 -1
- package/dist/data/call-graph/CallGraphToolbar.cjs +17 -5
- package/dist/data/call-graph/CallGraphToolbar.cjs.map +1 -1
- package/dist/data/call-graph/CallGraphToolbar.d.ts +10 -0
- package/dist/data/call-graph/CallGraphToolbar.d.ts.map +1 -1
- package/dist/data/call-graph/CallGraphToolbar.js +18 -6
- package/dist/data/call-graph/CallGraphToolbar.js.map +1 -1
- package/dist/data/call-graph/call-graph-model.cjs +169 -18
- package/dist/data/call-graph/call-graph-model.cjs.map +1 -1
- package/dist/data/call-graph/call-graph-model.d.ts +40 -4
- package/dist/data/call-graph/call-graph-model.d.ts.map +1 -1
- package/dist/data/call-graph/call-graph-model.js +170 -19
- package/dist/data/call-graph/call-graph-model.js.map +1 -1
- package/dist/data/call-graph/call-graph-vocabulary.cjs +19 -1
- package/dist/data/call-graph/call-graph-vocabulary.cjs.map +1 -1
- package/dist/data/call-graph/call-graph-vocabulary.d.ts +4 -0
- package/dist/data/call-graph/call-graph-vocabulary.d.ts.map +1 -1
- package/dist/data/call-graph/call-graph-vocabulary.js +19 -1
- package/dist/data/call-graph/call-graph-vocabulary.js.map +1 -1
- package/dist/data/call-graph/call-graph.fixtures.d.ts.map +1 -1
- package/dist/data/call-graph/index.d.ts +2 -2
- package/dist/data/call-graph/index.d.ts.map +1 -1
- package/dist/data/call-graph/types.cjs.map +1 -1
- package/dist/data/call-graph/types.d.ts +7 -2
- package/dist/data/call-graph/types.d.ts.map +1 -1
- package/dist/data/call-graph/types.js.map +1 -1
- package/dist/data/chat/Chat.cjs +1 -1
- package/dist/data/chat/Chat.cjs.map +1 -1
- package/dist/data/chat/Chat.js +1 -1
- package/dist/data/chat/Chat.js.map +1 -1
- package/dist/data/chat/ChatRuntimeToolbar.cjs +4 -4
- package/dist/data/chat/ChatRuntimeToolbar.cjs.map +1 -1
- package/dist/data/chat/ChatRuntimeToolbar.d.ts.map +1 -1
- package/dist/data/chat/ChatRuntimeToolbar.js +4 -4
- package/dist/data/chat/ChatRuntimeToolbar.js.map +1 -1
- package/dist/data/chat/PromptInput.cjs +4 -2
- package/dist/data/chat/PromptInput.cjs.map +1 -1
- package/dist/data/chat/PromptInput.d.ts +5 -1
- package/dist/data/chat/PromptInput.d.ts.map +1 -1
- package/dist/data/chat/PromptInput.js +4 -2
- package/dist/data/chat/PromptInput.js.map +1 -1
- package/dist/data/data-access.cjs +8 -0
- package/dist/data/data-access.cjs.map +1 -0
- package/dist/data/data-access.d.ts +5 -0
- package/dist/data/data-access.d.ts.map +1 -0
- package/dist/data/data-access.js +8 -0
- package/dist/data/data-access.js.map +1 -0
- package/dist/data/diagnostics/ErrorDetails.cjs +13 -2
- package/dist/data/diagnostics/ErrorDetails.cjs.map +1 -1
- package/dist/data/diagnostics/ErrorDetails.d.ts +3 -1
- package/dist/data/diagnostics/ErrorDetails.d.ts.map +1 -1
- package/dist/data/diagnostics/ErrorDetails.js +14 -3
- package/dist/data/diagnostics/ErrorDetails.js.map +1 -1
- package/dist/data/diagnostics/FrameSourceWindow.cjs +3 -2
- package/dist/data/diagnostics/FrameSourceWindow.cjs.map +1 -1
- package/dist/data/diagnostics/FrameSourceWindow.d.ts.map +1 -1
- package/dist/data/diagnostics/FrameSourceWindow.js +3 -2
- package/dist/data/diagnostics/FrameSourceWindow.js.map +1 -1
- package/dist/data/diagnostics/error-diagnostics.cjs +5 -0
- package/dist/data/diagnostics/error-diagnostics.cjs.map +1 -1
- package/dist/data/diagnostics/error-diagnostics.d.ts +1 -0
- package/dist/data/diagnostics/error-diagnostics.d.ts.map +1 -1
- package/dist/data/diagnostics/error-diagnostics.js +6 -1
- package/dist/data/diagnostics/error-diagnostics.js.map +1 -1
- package/dist/data/git/GitChangeList.cjs +6 -2
- package/dist/data/git/GitChangeList.cjs.map +1 -1
- package/dist/data/git/GitChangeList.d.ts +6 -1
- package/dist/data/git/GitChangeList.d.ts.map +1 -1
- package/dist/data/git/GitChangeList.js +6 -2
- package/dist/data/git/GitChangeList.js.map +1 -1
- package/dist/data/graph-columns-layout.cjs +47 -16
- package/dist/data/graph-columns-layout.cjs.map +1 -1
- package/dist/data/graph-columns-layout.d.ts +34 -0
- package/dist/data/graph-columns-layout.d.ts.map +1 -1
- package/dist/data/graph-columns-layout.js +47 -16
- package/dist/data/graph-columns-layout.js.map +1 -1
- package/dist/data/graph-diagram-model.cjs +5 -0
- package/dist/data/graph-diagram-model.cjs.map +1 -1
- package/dist/data/graph-diagram-model.d.ts +19 -0
- package/dist/data/graph-diagram-model.d.ts.map +1 -1
- package/dist/data/graph-diagram-model.js +5 -0
- package/dist/data/graph-diagram-model.js.map +1 -1
- package/dist/data/graph-group-window.cjs +60 -0
- package/dist/data/graph-group-window.cjs.map +1 -0
- package/dist/data/graph-group-window.d.ts +33 -0
- package/dist/data/graph-group-window.d.ts.map +1 -0
- package/dist/data/graph-group-window.js +60 -0
- package/dist/data/graph-group-window.js.map +1 -0
- package/dist/data/har/HarPanel.cjs +3 -1
- package/dist/data/har/HarPanel.cjs.map +1 -1
- package/dist/data/har/HarPanel.d.ts +4 -1
- package/dist/data/har/HarPanel.d.ts.map +1 -1
- package/dist/data/har/HarPanel.js +3 -1
- package/dist/data/har/HarPanel.js.map +1 -1
- package/dist/data/test-runner/Expectation.cjs +57 -0
- package/dist/data/test-runner/Expectation.cjs.map +1 -0
- package/dist/data/test-runner/Expectation.d.ts +19 -0
- package/dist/data/test-runner/Expectation.d.ts.map +1 -0
- package/dist/data/test-runner/Expectation.js +57 -0
- package/dist/data/test-runner/Expectation.js.map +1 -0
- package/dist/data/test-runner/MarkIcons.cjs +38 -0
- package/dist/data/test-runner/MarkIcons.cjs.map +1 -0
- package/dist/data/test-runner/MarkIcons.d.ts +15 -0
- package/dist/data/test-runner/MarkIcons.d.ts.map +1 -0
- package/dist/data/test-runner/MarkIcons.js +38 -0
- package/dist/data/test-runner/MarkIcons.js.map +1 -0
- package/dist/data/test-runner/TestDetailPanel.cjs +74 -42
- package/dist/data/test-runner/TestDetailPanel.cjs.map +1 -1
- package/dist/data/test-runner/TestDetailPanel.d.ts.map +1 -1
- package/dist/data/test-runner/TestDetailPanel.js +76 -44
- package/dist/data/test-runner/TestDetailPanel.js.map +1 -1
- package/dist/data/test-runner/TestFailureDetail.cjs +23 -27
- package/dist/data/test-runner/TestFailureDetail.cjs.map +1 -1
- package/dist/data/test-runner/TestFailureDetail.d.ts +2 -2
- package/dist/data/test-runner/TestFailureDetail.d.ts.map +1 -1
- package/dist/data/test-runner/TestFailureDetail.js +23 -27
- package/dist/data/test-runner/TestFailureDetail.js.map +1 -1
- package/dist/data/test-runner/TestFilterBar.cjs +87 -93
- package/dist/data/test-runner/TestFilterBar.cjs.map +1 -1
- package/dist/data/test-runner/TestFilterBar.d.ts +3 -2
- package/dist/data/test-runner/TestFilterBar.d.ts.map +1 -1
- package/dist/data/test-runner/TestFilterBar.js +89 -95
- package/dist/data/test-runner/TestFilterBar.js.map +1 -1
- package/dist/data/test-runner/TestRunSummary.cjs +35 -21
- package/dist/data/test-runner/TestRunSummary.cjs.map +1 -1
- package/dist/data/test-runner/TestRunSummary.d.ts.map +1 -1
- package/dist/data/test-runner/TestRunSummary.js +35 -21
- package/dist/data/test-runner/TestRunSummary.js.map +1 -1
- package/dist/data/test-runner/TestRunner.cjs +52 -30
- package/dist/data/test-runner/TestRunner.cjs.map +1 -1
- package/dist/data/test-runner/TestRunner.d.ts +3 -2
- package/dist/data/test-runner/TestRunner.d.ts.map +1 -1
- package/dist/data/test-runner/TestRunner.js +52 -30
- package/dist/data/test-runner/TestRunner.js.map +1 -1
- package/dist/data/test-runner/TestTree.cjs +5 -2
- package/dist/data/test-runner/TestTree.cjs.map +1 -1
- package/dist/data/test-runner/TestTree.d.ts +5 -2
- package/dist/data/test-runner/TestTree.d.ts.map +1 -1
- package/dist/data/test-runner/TestTree.js +5 -2
- package/dist/data/test-runner/TestTree.js.map +1 -1
- package/dist/data/test-runner/TestTreeNode.cjs +27 -19
- package/dist/data/test-runner/TestTreeNode.cjs.map +1 -1
- package/dist/data/test-runner/TestTreeNode.d.ts.map +1 -1
- package/dist/data/test-runner/TestTreeNode.js +28 -20
- package/dist/data/test-runner/TestTreeNode.js.map +1 -1
- package/dist/data/test-runner/adapter.cjs +11 -0
- package/dist/data/test-runner/adapter.cjs.map +1 -1
- package/dist/data/test-runner/adapter.d.ts +18 -7
- package/dist/data/test-runner/adapter.d.ts.map +1 -1
- package/dist/data/test-runner/adapter.js +11 -0
- package/dist/data/test-runner/adapter.js.map +1 -1
- package/dist/data/test-runner/copy.cjs +114 -0
- package/dist/data/test-runner/copy.cjs.map +1 -0
- package/dist/data/test-runner/copy.d.ts +47 -0
- package/dist/data/test-runner/copy.d.ts.map +1 -0
- package/dist/data/test-runner/copy.js +114 -0
- package/dist/data/test-runner/copy.js.map +1 -0
- package/dist/data/test-runner/index.d.ts +5 -2
- package/dist/data/test-runner/index.d.ts.map +1 -1
- package/dist/data/test-runner/marks.cjs +143 -0
- package/dist/data/test-runner/marks.cjs.map +1 -0
- package/dist/data/test-runner/marks.d.ts +30 -0
- package/dist/data/test-runner/marks.d.ts.map +1 -0
- package/dist/data/test-runner/marks.js +143 -0
- package/dist/data/test-runner/marks.js.map +1 -0
- package/dist/data/test-runner/status.cjs +27 -44
- package/dist/data/test-runner/status.cjs.map +1 -1
- package/dist/data/test-runner/status.d.ts +12 -3
- package/dist/data/test-runner/status.d.ts.map +1 -1
- package/dist/data/test-runner/status.js +27 -44
- package/dist/data/test-runner/status.js.map +1 -1
- package/dist/data/use-group-windows.cjs +50 -0
- package/dist/data/use-group-windows.cjs.map +1 -0
- package/dist/data/use-group-windows.d.ts +27 -0
- package/dist/data/use-group-windows.d.ts.map +1 -0
- package/dist/data/use-group-windows.js +50 -0
- package/dist/data/use-group-windows.js.map +1 -0
- package/dist/data/verification/adapterViews.cjs +16 -41
- package/dist/data/verification/adapterViews.cjs.map +1 -1
- package/dist/data/verification/adapterViews.d.ts.map +1 -1
- package/dist/data/verification/adapterViews.js +16 -41
- package/dist/data/verification/adapterViews.js.map +1 -1
- package/dist/data/verification/adapters.cjs +115 -3
- package/dist/data/verification/adapters.cjs.map +1 -1
- package/dist/data/verification/adapters.d.ts.map +1 -1
- package/dist/data/verification/adapters.js +115 -3
- package/dist/data/verification/adapters.js.map +1 -1
- package/dist/data/verification/verifyReportTests.cjs.map +1 -1
- package/dist/data/verification/verifyReportTests.js.map +1 -1
- package/dist/data/version-info.cjs +3 -3
- package/dist/data/version-info.js +3 -3
- package/dist/data.cjs +54 -3
- package/dist/data.cjs.map +1 -1
- package/dist/data.d.ts +6 -2
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +58 -7
- package/dist/data.js.map +1 -1
- package/dist/hooks/event-hub.cjs +229 -0
- package/dist/hooks/event-hub.cjs.map +1 -0
- package/dist/hooks/event-hub.d.ts +26 -0
- package/dist/hooks/event-hub.d.ts.map +1 -0
- package/dist/hooks/event-hub.js +229 -0
- package/dist/hooks/event-hub.js.map +1 -0
- package/dist/hooks.cjs +2 -0
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.d.ts +1 -0
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +2 -0
- package/dist/hooks.js.map +1 -1
- package/dist/icons/components/UiLogoEslint.cjs +10 -0
- package/dist/icons/components/UiLogoEslint.cjs.map +1 -0
- package/dist/icons/components/UiLogoEslint.d.ts +9 -0
- package/dist/icons/components/UiLogoEslint.d.ts.map +1 -0
- package/dist/icons/components/UiLogoEslint.js +10 -0
- package/dist/icons/components/UiLogoEslint.js.map +1 -0
- package/dist/icons/components/UiLogoGo.cjs +10 -0
- package/dist/icons/components/UiLogoGo.cjs.map +1 -0
- package/dist/icons/components/UiLogoGo.d.ts +9 -0
- package/dist/icons/components/UiLogoGo.d.ts.map +1 -0
- package/dist/icons/components/UiLogoGo.js +10 -0
- package/dist/icons/components/UiLogoGo.js.map +1 -0
- package/dist/icons/components/UiLogoJest.cjs +10 -0
- package/dist/icons/components/UiLogoJest.cjs.map +1 -0
- package/dist/icons/components/UiLogoJest.d.ts +9 -0
- package/dist/icons/components/UiLogoJest.d.ts.map +1 -0
- package/dist/icons/components/UiLogoJest.js +10 -0
- package/dist/icons/components/UiLogoJest.js.map +1 -0
- package/dist/icons/components/UiLogoMarkdown.cjs +10 -0
- package/dist/icons/components/UiLogoMarkdown.cjs.map +1 -0
- package/dist/icons/components/UiLogoMarkdown.d.ts +9 -0
- package/dist/icons/components/UiLogoMarkdown.d.ts.map +1 -0
- package/dist/icons/components/UiLogoMarkdown.js +10 -0
- package/dist/icons/components/UiLogoMarkdown.js.map +1 -0
- package/dist/icons/components/UiLogoOxc.cjs +10 -0
- package/dist/icons/components/UiLogoOxc.cjs.map +1 -0
- package/dist/icons/components/UiLogoOxc.d.ts +9 -0
- package/dist/icons/components/UiLogoOxc.d.ts.map +1 -0
- package/dist/icons/components/UiLogoOxc.js +10 -0
- package/dist/icons/components/UiLogoOxc.js.map +1 -0
- package/dist/icons/components/UiLogoPlaywright.cjs +10 -0
- package/dist/icons/components/UiLogoPlaywright.cjs.map +1 -0
- package/dist/icons/components/UiLogoPlaywright.d.ts +9 -0
- package/dist/icons/components/UiLogoPlaywright.d.ts.map +1 -0
- package/dist/icons/components/UiLogoPlaywright.js +10 -0
- package/dist/icons/components/UiLogoPlaywright.js.map +1 -0
- package/dist/icons/components/UiLogoPython.cjs +10 -0
- package/dist/icons/components/UiLogoPython.cjs.map +1 -0
- package/dist/icons/components/UiLogoPython.d.ts +9 -0
- package/dist/icons/components/UiLogoPython.d.ts.map +1 -0
- package/dist/icons/components/UiLogoPython.js +10 -0
- package/dist/icons/components/UiLogoPython.js.map +1 -0
- package/dist/icons/components/UiLogoReact.cjs +10 -0
- package/dist/icons/components/UiLogoReact.cjs.map +1 -0
- package/dist/icons/components/UiLogoReact.d.ts +9 -0
- package/dist/icons/components/UiLogoReact.d.ts.map +1 -0
- package/dist/icons/components/UiLogoReact.js +10 -0
- package/dist/icons/components/UiLogoReact.js.map +1 -0
- package/dist/icons/components/UiLogoRuff.cjs +10 -0
- package/dist/icons/components/UiLogoRuff.cjs.map +1 -0
- package/dist/icons/components/UiLogoRuff.d.ts +9 -0
- package/dist/icons/components/UiLogoRuff.d.ts.map +1 -0
- package/dist/icons/components/UiLogoRuff.js +10 -0
- package/dist/icons/components/UiLogoRuff.js.map +1 -0
- package/dist/icons/components/UiLogoTypescript.cjs +10 -0
- package/dist/icons/components/UiLogoTypescript.cjs.map +1 -0
- package/dist/icons/components/UiLogoTypescript.d.ts +9 -0
- package/dist/icons/components/UiLogoTypescript.d.ts.map +1 -0
- package/dist/icons/components/UiLogoTypescript.js +10 -0
- package/dist/icons/components/UiLogoTypescript.js.map +1 -0
- package/dist/icons/components/UiLogoVitest.cjs +10 -0
- package/dist/icons/components/UiLogoVitest.cjs.map +1 -0
- package/dist/icons/components/UiLogoVitest.d.ts +9 -0
- package/dist/icons/components/UiLogoVitest.d.ts.map +1 -0
- package/dist/icons/components/UiLogoVitest.js +10 -0
- package/dist/icons/components/UiLogoVitest.js.map +1 -0
- package/dist/icons/index.d.ts +11 -0
- package/dist/icons/index.d.ts.map +1 -1
- package/dist/icons/registry.cjs +22 -0
- package/dist/icons/registry.cjs.map +1 -1
- package/dist/icons/registry.d.ts.map +1 -1
- package/dist/icons/registry.js +22 -0
- package/dist/icons/registry.js.map +1 -1
- package/dist/icons.cjs +22 -0
- package/dist/icons.cjs.map +1 -1
- package/dist/icons.js +22 -0
- package/dist/icons.js.map +1 -1
- package/dist/index.cjs +56 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +60 -7
- package/dist/index.js.map +1 -1
- package/dist/overlay/DropdownMenuSubmenu.cjs +4 -4
- package/dist/overlay/DropdownMenuSubmenu.cjs.map +1 -1
- package/dist/overlay/DropdownMenuSubmenu.js +4 -4
- package/dist/overlay/DropdownMenuSubmenu.js.map +1 -1
- package/dist/overlay/modalStack.cjs +13 -6
- package/dist/overlay/modalStack.cjs.map +1 -1
- package/dist/overlay/modalStack.d.ts.map +1 -1
- package/dist/overlay/modalStack.js +13 -6
- package/dist/overlay/modalStack.js.map +1 -1
- package/dist/rpc/InlineError.cjs +12 -43
- package/dist/rpc/InlineError.cjs.map +1 -1
- package/dist/rpc/InlineError.d.ts.map +1 -1
- package/dist/rpc/InlineError.js +13 -44
- package/dist/rpc/InlineError.js.map +1 -1
- package/dist/rpc/OperationScheduleDialog.cjs +63 -10
- package/dist/rpc/OperationScheduleDialog.cjs.map +1 -1
- package/dist/rpc/OperationScheduleDialog.d.ts +4 -0
- package/dist/rpc/OperationScheduleDialog.d.ts.map +1 -1
- package/dist/rpc/OperationScheduleDialog.js +63 -10
- package/dist/rpc/OperationScheduleDialog.js.map +1 -1
- package/dist/rpc/OperationSchedules.cjs +12 -2
- package/dist/rpc/OperationSchedules.cjs.map +1 -1
- package/dist/rpc/OperationSchedules.d.ts.map +1 -1
- package/dist/rpc/OperationSchedules.js +12 -2
- package/dist/rpc/OperationSchedules.js.map +1 -1
- package/dist/rpc/operation-schedule-model.cjs +2 -0
- package/dist/rpc/operation-schedule-model.cjs.map +1 -1
- package/dist/rpc/operation-schedule-model.d.ts.map +1 -1
- package/dist/rpc/operation-schedule-model.js +2 -0
- package/dist/rpc/operation-schedule-model.js.map +1 -1
- package/dist/rpc/operation-schedule-types.d.ts +7 -1
- package/dist/rpc/operation-schedule-types.d.ts.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/dist/data/test-runner/frameworkIcon.cjs +0 -27
- package/dist/data/test-runner/frameworkIcon.cjs.map +0 -1
- package/dist/data/test-runner/frameworkIcon.d.ts +0 -3
- package/dist/data/test-runner/frameworkIcon.d.ts.map +0 -1
- package/dist/data/test-runner/frameworkIcon.js +0 -27
- package/dist/data/test-runner/frameworkIcon.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CallGraphToolbar.js","sources":["../../../src/data/call-graph/CallGraphToolbar.tsx"],"sourcesContent":["import { useState, type FormEvent, type ReactNode } from \"react\";\nimport { Button } from \"../../components/button\";\nimport { InputField } from \"../../components/InputField\";\nimport { SegmentedControl } from \"../../components/SegmentedControl\";\nimport { Switch } from \"../../components/Switch\";\nimport { UiFilter, UiHome, UiWarningTriangle } from \"../../icons\";\nimport { DropdownMenu } from \"../../overlay/DropdownMenu\";\nimport { Badge } from \"../Badge\";\nimport {\n addExcludePattern,\n EXCLUDE_EXTERNAL,\n excludeGroup,\n excludePatternError,\n includeGroup,\n removeExcludePattern,\n setExternalHidden,\n type ExcludeMatcher,\n} from \"./call-graph-exclude\";\nimport { capitalize, excludedTally, omittedParts } from \"./call-graph-labels\";\nimport { toggleAccess } from \"./call-graph-model\";\nimport type { CallGraphVocabulary } from \"./call-graph-vocabulary\";\nimport { CALL_GRAPH_ACCESS, type CallGraphAccess, type CallGraphDirection, type CallGraphGroupFact, type CallGraphOmitted } from \"./types\";\n\nconst DIRECTIONS: { id: CallGraphDirection; label: string }[] = [\n { id: \"callers\", label: \"Callers\" },\n { id: \"both\", label: \"Both\" },\n { id: \"callees\", label: \"Callees\" },\n];\n\nfunction DepthStepper({ depth, maxDepth, onChange }: { depth: number; maxDepth: number; onChange: (depth: number) => void }) {\n return (\n <div className=\"flex items-center gap-1\" role=\"group\" aria-label=\"Depth\">\n <span className=\"text-xs text-muted-foreground\">Depth</span>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" className=\"size-8 px-0\" aria-label=\"Decrease depth\" disabled={depth <= 1} onClick={() => onChange(depth - 1)}>−</Button>\n <output className=\"w-5 text-center text-sm font-medium tabular-nums\" aria-live=\"polite\" aria-label=\"Graph depth\">{depth}</output>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" className=\"size-8 px-0\" aria-label=\"Increase depth\" disabled={depth >= maxDepth} onClick={() => onChange(depth + 1)}>+</Button>\n </div>\n );\n}\n\nfunction OmittedChip({ omitted, noun }: { omitted: CallGraphOmitted; noun: string }) {\n const parts = omittedParts(omitted);\n if (parts.length === 0) return null;\n const tally = excludedTally(omitted).map(({ group, count }) => `${group}: ${count}`);\n const title = [`Not drawn: ${parts.join(\", \")}`, ...(tally.length ? [`Excluded per ${noun}:`, ...tally] : [])].join(\"\\n\");\n return (\n <span title={title} data-testid=\"graph-omitted\">\n <Badge tone=\"warning\" size=\"md\" icon={UiWarningTriangle} clickToCopy={false}>{parts.join(\" · \")}</Badge>\n </span>\n );\n}\n\nexport interface ExclusionsProps {\n /** The patterns in force. */\n exclude: string[];\n groups: CallGraphGroupFact[];\n matches: ExcludeMatcher;\n onExclude: (patterns: string[]) => void;\n onDefaults: () => void;\n /** A graph for the last edit is loading: the facts describe the one before it, so editing waits. */\n busy: boolean;\n vocabulary: CallGraphVocabulary;\n}\n\nfunction GroupRow({ group, onToggle }: { group: CallGraphGroupFact; onToggle: () => void }) {\n const name = group.label ?? group.name;\n return (\n <li className=\"flex items-center gap-2 py-1\">\n <Switch checked={!group.excluded} onChange={onToggle} aria-label={`Show ${name}`} />\n <span className=\"min-w-0 flex-1 truncate font-mono text-xs\" title={group.name}>{name}</span>\n {group.external && <Badge variant=\"outline\" size=\"sm\" clickToCopy={false}>external</Badge>}\n <span className=\"w-8 shrink-0 text-right text-xs tabular-nums text-muted-foreground\" title={`${group.nodes} nodes`}>{group.nodes}</span>\n </li>\n );\n}\n\n/** The group facets: one switch per group the walk reached, the patterns in force, and free-text patterns. */\nfunction GroupFacets({ exclude, groups, matches, onExclude, onDefaults, busy, vocabulary }: ExclusionsProps) {\n const [filter, setFilter] = useState(\"\");\n const [pattern, setPattern] = useState(\"\");\n const [error, setError] = useState<string>();\n const { plural, patternHint } = vocabulary.group;\n const needle = filter.trim().toLowerCase();\n const shown = groups.filter((group) => `${group.name} ${group.label ?? \"\"}`.toLowerCase().includes(needle));\n const submit = (event: FormEvent) => {\n event.preventDefault();\n const typed = pattern.trim();\n const problem = excludePatternError(exclude, typed);\n setError(problem);\n if (problem) return;\n setPattern(\"\");\n onExclude(addExcludePattern(exclude, typed));\n };\n // The filter box comes first: the menu focuses its first control on opening, which must not be one that drops an exclusion.\n return (\n <fieldset disabled={busy} aria-busy={busy} className=\"flex w-96 min-w-0 max-w-[90vw] flex-col gap-2 p-2 text-sm\">\n <InputField aria-label={`Filter ${plural}`} placeholder={`Filter ${plural}`} value={filter} onChange={setFilter} />\n <div className=\"flex flex-wrap items-center gap-1\" aria-label=\"Exclusion patterns\">\n <span className=\"text-xs text-muted-foreground\">Excluding</span>\n {exclude.length === 0 && <span className=\"text-xs text-muted-foreground\">nothing</span>}\n {exclude.map((entry) => (\n <button key={entry} type=\"button\" className=\"rounded border border-border px-1.5 font-mono text-xs hover:bg-muted\"\n aria-label={`Stop excluding ${entry}`} title={`Stop excluding ${entry}`} onClick={() => onExclude(removeExcludePattern(exclude, entry))}>\n {entry} ×\n </button>\n ))}\n </div>\n <ul className=\"max-h-72 overflow-y-auto pr-1\" aria-label={plural}>\n {shown.map((group) => (\n <GroupRow key={group.name} group={group}\n onToggle={() => onExclude(group.excluded ? includeGroup(exclude, group, groups, matches) : excludeGroup(exclude, group.name))} />\n ))}\n {shown.length === 0 && (\n <li className=\"py-1 text-xs text-muted-foreground\">{groups.length ? `No ${vocabulary.group.noun} matches the filter.` : `The graph reached no ${vocabulary.group.noun}.`}</li>\n )}\n </ul>\n <form className=\"flex items-start gap-2\" onSubmit={submit}>\n <div className=\"flex min-w-0 flex-1 flex-col gap-1\">\n <InputField aria-label=\"Exclude pattern\" placeholder={patternHint} value={pattern} onChange={setPattern} />\n {error && <span role=\"alert\" className=\"text-xs text-destructive\">{error}</span>}\n </div>\n <Button type=\"submit\" size=\"sm\" variant=\"outline\">Exclude</Button>\n </form>\n <div className=\"flex justify-between gap-2 border-t border-border pt-2\">\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" onClick={onDefaults}>Reset to defaults</Button>\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" onClick={() => onExclude([])}>Show all</Button>\n </div>\n </fieldset>\n );\n}\n\nconst ACCESS_LABELS: Record<CallGraphAccess, string> = { call: \"Calls\", read: \"Reads\", write: \"Writes\" };\n\nexport interface DataAccessProps {\n access: CallGraphAccess[];\n onAccess: (access: CallGraphAccess[]) => void;\n columns: boolean;\n onColumns: (columns: boolean) => void;\n}\n\n/** Which edge types the graph follows, at least one, and whether columns and fields are nodes of their own. */\nfunction DataAccessControls({ access, onAccess, columns, onColumns }: DataAccessProps) {\n return (\n <>\n <div className=\"flex items-center gap-1\" role=\"group\" aria-label=\"Access\">\n {CALL_GRAPH_ACCESS.map((type) => {\n const on = access.includes(type);\n return (\n <Button key={type} type=\"button\" size=\"sm\" variant={on ? \"secondary\" : \"outline\"} aria-pressed={on} disabled={on && access.length === 1}\n title={on && access.length === 1 ? \"At least one kind of access stays on\" : undefined} onClick={() => onAccess(toggleAccess(access, type))}>\n {ACCESS_LABELS[type]}\n </Button>\n );\n })}\n </div>\n <Switch checked={columns} label=\"Columns\" onChange={onColumns} />\n </>\n );\n}\n\nexport interface CallGraphToolbarProps {\n /** Shown only when the host's graph has reads and writes. */\n data?: DataAccessProps | undefined;\n direction: CallGraphDirection;\n depth: number;\n maxDepth: number;\n /** Shown only when the host keeps a root across selection changes. */\n pin?: { pinned: boolean; canPin: boolean; onPin: (pinned: boolean) => void } | undefined;\n exclusions?: ExclusionsProps | undefined;\n omitted?: CallGraphOmitted | undefined;\n /** Host content at the toolbar's end, such as server timing. */\n end?: ReactNode;\n onDirection: (direction: CallGraphDirection) => void;\n onDepth: (depth: number) => void;\n onFit: () => void;\n onReset: () => void;\n vocabulary: CallGraphVocabulary;\n}\n\nexport function CallGraphToolbar(props: CallGraphToolbarProps) {\n const { exclusions, pin, vocabulary } = props;\n const excludedCount = exclusions?.groups.filter((group) => group.excluded).length ?? 0;\n const hasExternal = exclusions?.groups.some((group) => group.external) ?? false;\n const { noun, plural } = vocabulary.group;\n return (\n <div className=\"flex flex-wrap items-center gap-3\">\n <SegmentedControl value={props.direction} options={DIRECTIONS} onChange={props.onDirection} size=\"sm\" aria-label=\"Direction\" />\n <DepthStepper depth={props.depth} maxDepth={props.maxDepth} onChange={props.onDepth} />\n {props.data && <DataAccessControls {...props.data} />}\n {pin && (\n <Button type=\"button\" variant={pin.pinned ? \"secondary\" : \"outline\"} size=\"sm\" disabled={!pin.pinned && !pin.canPin} aria-pressed={pin.pinned}\n title={pin.pinned ? \"The graph keeps this root while the selection changes\" : \"Keep this root while the selection changes\"} onClick={() => pin.onPin(!pin.pinned)}>\n {pin.pinned ? \"Unpin root\" : \"Pin root\"}\n </Button>\n )}\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={props.onFit}>Fit</Button>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={props.onReset}><UiHome />Reset</Button>\n {exclusions && hasExternal && (\n <Switch checked={exclusions.exclude.includes(EXCLUDE_EXTERNAL)} disabled={exclusions.busy} label=\"Hide all external\"\n onChange={(hidden) => exclusions.onExclude(setExternalHidden(exclusions.exclude, hidden))} />\n )}\n {exclusions && (\n <DropdownMenu icon={UiFilter} label={`${capitalize(plural)}${excludedCount ? ` (${excludedCount} excluded)` : \"\"}`} variant=\"outline\" size=\"sm\"\n menuLabel={`${capitalize(noun)} exclusions`} title={`Choose the ${plural} the graph leaves out`}>\n {() => <GroupFacets {...exclusions} />}\n </DropdownMenu>\n )}\n <div className=\"ml-auto flex items-center gap-2\">\n {props.omitted && <OmittedChip omitted={props.omitted} noun={noun} />}\n {props.end}\n </div>\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CallGraphToolbar.js","sources":["../../../src/data/call-graph/CallGraphToolbar.tsx"],"sourcesContent":["import { useState, type FormEvent, type ReactNode } from \"react\";\nimport { Button } from \"../../components/button\";\nimport { IconButton } from \"../../components/IconButton\";\nimport { InputField } from \"../../components/InputField\";\nimport { SegmentedControl } from \"../../components/SegmentedControl\";\nimport { Switch } from \"../../components/Switch\";\nimport { UiCollapseAll, UiExpandAll, UiFilter, UiHome, UiWarningTriangle } from \"../../icons\";\nimport { DropdownMenu } from \"../../overlay/DropdownMenu\";\nimport { Badge } from \"../Badge\";\nimport {\n addExcludePattern,\n EXCLUDE_EXTERNAL,\n excludeGroup,\n excludePatternError,\n includeGroup,\n removeExcludePattern,\n setExternalHidden,\n type ExcludeMatcher,\n} from \"./call-graph-exclude\";\nimport { capitalize, excludedTally, omittedParts } from \"./call-graph-labels\";\nimport { baseAccess, toggleAccess } from \"./call-graph-model\";\nimport type { CallGraphVocabulary } from \"./call-graph-vocabulary\";\nimport { CALL_GRAPH_ACCESS, type CallGraphAccess, type CallGraphDirection, type CallGraphGroupFact, type CallGraphOmitted } from \"./types\";\n\nconst DIRECTIONS: { id: CallGraphDirection; label: string }[] = [\n { id: \"callers\", label: \"Callers\" },\n { id: \"both\", label: \"Both\" },\n { id: \"callees\", label: \"Callees\" },\n];\n\nfunction DepthStepper({ depth, maxDepth, onChange }: { depth: number; maxDepth: number; onChange: (depth: number) => void }) {\n return (\n <div className=\"flex items-center gap-1\" role=\"group\" aria-label=\"Depth\">\n <span className=\"text-xs text-muted-foreground\">Depth</span>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" className=\"size-8 px-0\" aria-label=\"Decrease depth\" disabled={depth <= 1} onClick={() => onChange(depth - 1)}>−</Button>\n <output className=\"w-5 text-center text-sm font-medium tabular-nums\" aria-live=\"polite\" aria-label=\"Graph depth\">{depth}</output>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" className=\"size-8 px-0\" aria-label=\"Increase depth\" disabled={depth >= maxDepth} onClick={() => onChange(depth + 1)}>+</Button>\n </div>\n );\n}\n\nfunction OmittedChip({ omitted, noun }: { omitted: CallGraphOmitted; noun: string }) {\n const parts = omittedParts(omitted);\n if (parts.length === 0) return null;\n const tally = excludedTally(omitted).map(({ group, count }) => `${group}: ${count}`);\n const title = [`Not drawn: ${parts.join(\", \")}`, ...(tally.length ? [`Excluded per ${noun}:`, ...tally] : [])].join(\"\\n\");\n return (\n <span title={title} data-testid=\"graph-omitted\">\n <Badge tone=\"warning\" size=\"md\" icon={UiWarningTriangle} clickToCopy={false}>{parts.join(\" · \")}</Badge>\n </span>\n );\n}\n\nexport interface ExclusionsProps {\n /** The patterns in force. */\n exclude: string[];\n groups: CallGraphGroupFact[];\n matches: ExcludeMatcher;\n onExclude: (patterns: string[]) => void;\n onDefaults: () => void;\n /** A graph for the last edit is loading: the facts describe the one before it, so editing waits. */\n busy: boolean;\n vocabulary: CallGraphVocabulary;\n}\n\nfunction GroupRow({ group, onToggle }: { group: CallGraphGroupFact; onToggle: () => void }) {\n const name = group.label ?? group.name;\n return (\n <li className=\"flex items-center gap-2 py-1\">\n <Switch checked={!group.excluded} onChange={onToggle} aria-label={`Show ${name}`} />\n <span className=\"min-w-0 flex-1 truncate font-mono text-xs\" title={group.name}>{name}</span>\n {group.external && <Badge variant=\"outline\" size=\"sm\" clickToCopy={false}>external</Badge>}\n <span className=\"w-8 shrink-0 text-right text-xs tabular-nums text-muted-foreground\" title={`${group.nodes} nodes`}>{group.nodes}</span>\n </li>\n );\n}\n\n/** The group facets: one switch per group the walk reached, the patterns in force, and free-text patterns. */\nfunction GroupFacets({ exclude, groups, matches, onExclude, onDefaults, busy, vocabulary }: ExclusionsProps) {\n const [filter, setFilter] = useState(\"\");\n const [pattern, setPattern] = useState(\"\");\n const [error, setError] = useState<string>();\n const { plural, patternHint } = vocabulary.group;\n const needle = filter.trim().toLowerCase();\n const shown = groups.filter((group) => `${group.name} ${group.label ?? \"\"}`.toLowerCase().includes(needle));\n const submit = (event: FormEvent) => {\n event.preventDefault();\n const typed = pattern.trim();\n const problem = excludePatternError(exclude, typed);\n setError(problem);\n if (problem) return;\n setPattern(\"\");\n onExclude(addExcludePattern(exclude, typed));\n };\n // The filter box comes first: the menu focuses its first control on opening, which must not be one that drops an exclusion.\n return (\n <fieldset disabled={busy} aria-busy={busy} className=\"flex w-96 min-w-0 max-w-[90vw] flex-col gap-2 p-2 text-sm\">\n <InputField aria-label={`Filter ${plural}`} placeholder={`Filter ${plural}`} value={filter} onChange={setFilter} />\n <div className=\"flex flex-wrap items-center gap-1\" aria-label=\"Exclusion patterns\">\n <span className=\"text-xs text-muted-foreground\">Excluding</span>\n {exclude.length === 0 && <span className=\"text-xs text-muted-foreground\">nothing</span>}\n {exclude.map((entry) => (\n <button key={entry} type=\"button\" className=\"rounded border border-border px-1.5 font-mono text-xs hover:bg-muted\"\n aria-label={`Stop excluding ${entry}`} title={`Stop excluding ${entry}`} onClick={() => onExclude(removeExcludePattern(exclude, entry))}>\n {entry} ×\n </button>\n ))}\n </div>\n <ul className=\"max-h-72 overflow-y-auto pr-1\" aria-label={plural}>\n {shown.map((group) => (\n <GroupRow key={group.name} group={group}\n onToggle={() => onExclude(group.excluded ? includeGroup(exclude, group, groups, matches) : excludeGroup(exclude, group.name))} />\n ))}\n {shown.length === 0 && (\n <li className=\"py-1 text-xs text-muted-foreground\">{groups.length ? `No ${vocabulary.group.noun} matches the filter.` : `The graph reached no ${vocabulary.group.noun}.`}</li>\n )}\n </ul>\n <form className=\"flex items-start gap-2\" onSubmit={submit}>\n <div className=\"flex min-w-0 flex-1 flex-col gap-1\">\n <InputField aria-label=\"Exclude pattern\" placeholder={patternHint} value={pattern} onChange={setPattern} />\n {error && <span role=\"alert\" className=\"text-xs text-destructive\">{error}</span>}\n </div>\n <Button type=\"submit\" size=\"sm\" variant=\"outline\">Exclude</Button>\n </form>\n <div className=\"flex justify-between gap-2 border-t border-border pt-2\">\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" onClick={onDefaults}>Reset to defaults</Button>\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" onClick={() => onExclude([])}>Show all</Button>\n </div>\n </fieldset>\n );\n}\n\nconst ACCESS_LABELS: Record<CallGraphAccess, string> = { call: \"Calls\", read: \"Reads\", write: \"Writes\", variable: \"Variables\" };\n\nexport interface DataAccessProps {\n access: CallGraphAccess[];\n onAccess: (access: CallGraphAccess[]) => void;\n columns: boolean;\n onColumns: (columns: boolean) => void;\n /** Offers the Variables toggle, on top of the access types. */\n variables?: boolean;\n}\n\n/** Which edge types the graph follows, at least one of calls, reads and writes, and whether columns and fields are nodes of their own. */\nfunction DataAccessControls({ access, onAccess, columns, onColumns, variables }: DataAccessProps) {\n const lastOn = baseAccess(access).length === 1;\n return (\n <>\n <div className=\"flex items-center gap-1\" role=\"group\" aria-label=\"Access\">\n {(variables ? [...CALL_GRAPH_ACCESS, \"variable\" as const] : CALL_GRAPH_ACCESS).map((type) => {\n const on = access.includes(type);\n const kept = on && lastOn && type !== \"variable\";\n return (\n <Button key={type} type=\"button\" size=\"sm\" variant={on ? \"secondary\" : \"outline\"} aria-pressed={on} disabled={kept}\n title={kept ? \"At least one kind of access stays on\" : undefined} onClick={() => onAccess(toggleAccess(access, type))}>\n {ACCESS_LABELS[type]}\n </Button>\n );\n })}\n </div>\n <Switch checked={columns} label=\"Columns\" onChange={onColumns} />\n </>\n );\n}\n\nexport interface GroupCollapseProps {\n anyCollapsed: boolean;\n anyExpanded: boolean;\n onExpandAll: () => void;\n onCollapseAll: () => void;\n}\n\n/** Expand or collapse every group the graph draws at once. */\nfunction GroupCollapseControls({ anyCollapsed, anyExpanded, onExpandAll, onCollapseAll }: GroupCollapseProps) {\n return (\n <div className=\"flex items-center gap-0.5\" role=\"group\" aria-label=\"Groups\">\n <IconButton icon={UiExpandAll} label=\"Expand all groups\" className=\"size-7\" disabled={!anyCollapsed} onClick={onExpandAll} />\n <IconButton icon={UiCollapseAll} label=\"Collapse all groups\" className=\"size-7\" disabled={!anyExpanded} onClick={onCollapseAll} />\n </div>\n );\n}\n\nexport interface CallGraphToolbarProps {\n /** Shown only when the host's graph has reads and writes. */\n data?: DataAccessProps | undefined;\n /** Shown only when the graph draws a group that can collapse. */\n groupCollapse?: GroupCollapseProps | undefined;\n direction: CallGraphDirection;\n depth: number;\n maxDepth: number;\n /** Shown only when the host keeps a root across selection changes. */\n pin?: { pinned: boolean; canPin: boolean; onPin: (pinned: boolean) => void } | undefined;\n exclusions?: ExclusionsProps | undefined;\n omitted?: CallGraphOmitted | undefined;\n /** Host content at the toolbar's end, such as server timing. */\n end?: ReactNode;\n onDirection: (direction: CallGraphDirection) => void;\n onDepth: (depth: number) => void;\n onFit: () => void;\n onReset: () => void;\n vocabulary: CallGraphVocabulary;\n}\n\nexport function CallGraphToolbar(props: CallGraphToolbarProps) {\n const { exclusions, pin, vocabulary } = props;\n const excludedCount = exclusions?.groups.filter((group) => group.excluded).length ?? 0;\n const hasExternal = exclusions?.groups.some((group) => group.external) ?? false;\n const { noun, plural } = vocabulary.group;\n return (\n <div className=\"flex flex-wrap items-center gap-3\">\n <SegmentedControl value={props.direction} options={DIRECTIONS} onChange={props.onDirection} size=\"sm\" aria-label=\"Direction\" />\n <DepthStepper depth={props.depth} maxDepth={props.maxDepth} onChange={props.onDepth} />\n {props.data && <DataAccessControls {...props.data} />}\n {pin && (\n <Button type=\"button\" variant={pin.pinned ? \"secondary\" : \"outline\"} size=\"sm\" disabled={!pin.pinned && !pin.canPin} aria-pressed={pin.pinned}\n title={pin.pinned ? \"The graph keeps this root while the selection changes\" : \"Keep this root while the selection changes\"} onClick={() => pin.onPin(!pin.pinned)}>\n {pin.pinned ? \"Unpin root\" : \"Pin root\"}\n </Button>\n )}\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={props.onFit}>Fit</Button>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={props.onReset}><UiHome />Reset</Button>\n {props.groupCollapse && <GroupCollapseControls {...props.groupCollapse} />}\n {exclusions && hasExternal && (\n <Switch checked={exclusions.exclude.includes(EXCLUDE_EXTERNAL)} disabled={exclusions.busy} label=\"Hide all external\"\n onChange={(hidden) => exclusions.onExclude(setExternalHidden(exclusions.exclude, hidden))} />\n )}\n {exclusions && (\n <DropdownMenu icon={UiFilter} label={`${capitalize(plural)}${excludedCount ? ` (${excludedCount} excluded)` : \"\"}`} variant=\"outline\" size=\"sm\"\n menuLabel={`${capitalize(noun)} exclusions`} title={`Choose the ${plural} the graph leaves out`}>\n {() => <GroupFacets {...exclusions} />}\n </DropdownMenu>\n )}\n <div className=\"ml-auto flex items-center gap-2\">\n {props.omitted && <OmittedChip omitted={props.omitted} noun={noun} />}\n {props.end}\n </div>\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const dataAccess = require("../data-access.cjs");
|
|
3
4
|
const callGraphLabels = require("./call-graph-labels.cjs");
|
|
4
5
|
const callGraphVocabulary = require("./call-graph-vocabulary.cjs");
|
|
5
6
|
const types = require("./types.cjs");
|
|
@@ -9,8 +10,12 @@ const DEFAULT_EDGE_LABELS = { call: "call", dispatch: "dispatch", read: "read",
|
|
|
9
10
|
const EDGE_TONE = { dispatch: "info", read: "success", write: "warning" };
|
|
10
11
|
function toggleAccess(access, type) {
|
|
11
12
|
const on = !access.includes(type);
|
|
12
|
-
if (!on && access.length === 1) throw new Error(`call graph: ${type} is the only access type on`);
|
|
13
|
-
return
|
|
13
|
+
if (!on && type !== "variable" && baseAccess(access).length === 1) throw new Error(`call graph: ${type} is the only access type on`);
|
|
14
|
+
return ACCESS_ORDER.filter((entry) => entry === type ? on : access.includes(entry));
|
|
15
|
+
}
|
|
16
|
+
const ACCESS_ORDER = [...types.CALL_GRAPH_ACCESS, "variable"];
|
|
17
|
+
function baseAccess(access) {
|
|
18
|
+
return access.filter((type) => types.CALL_GRAPH_ACCESS.includes(type));
|
|
14
19
|
}
|
|
15
20
|
function requireNode(graph, id) {
|
|
16
21
|
const node = graph.nodes.find((candidate) => candidate.id === id);
|
|
@@ -35,16 +40,19 @@ function outerSide(node) {
|
|
|
35
40
|
function expansionDirection(node) {
|
|
36
41
|
return outerSide(node) === "in" ? "callers" : "callees";
|
|
37
42
|
}
|
|
38
|
-
function
|
|
43
|
+
function outerEdges(graph, node) {
|
|
39
44
|
const side = outerSide(node);
|
|
40
|
-
return graph.edges.filter((edge) => (side === "out" ? edge.from : edge.to) === node.id)
|
|
45
|
+
return graph.edges.filter((edge) => (side === "out" ? edge.from : edge.to) === node.id);
|
|
41
46
|
}
|
|
42
|
-
function expandCount(graph, visible, nodeId, direction, vocabulary) {
|
|
47
|
+
function expandCount(graph, visible, nodeId, direction, vocabulary, merged = /* @__PURE__ */ new Map()) {
|
|
43
48
|
const node = requireNode(graph, nodeId);
|
|
44
49
|
const side = outerSide(node);
|
|
45
50
|
if (!vocabulary.hasSource(node) || direction === (side === "out" ? "callers" : "callees")) return 0;
|
|
46
51
|
const drawn = new Set(visible.nodes.map((entry) => entry.id));
|
|
47
|
-
const accounted =
|
|
52
|
+
const accounted = outerEdges(graph, node).filter((edge) => drawn.has(side === "out" ? edge.to : edge.from)).reduce((sum, edge) => {
|
|
53
|
+
var _a;
|
|
54
|
+
return sum + (((_a = merged.get(edge.id)) == null ? void 0 : _a.sources.length) ?? 1);
|
|
55
|
+
}, 0);
|
|
48
56
|
return Math.max(0, (side === "out" ? node.out : node.in) - accounted);
|
|
49
57
|
}
|
|
50
58
|
function accessTotals(graph, node) {
|
|
@@ -83,19 +91,26 @@ function mergeGraph(held, expansion) {
|
|
|
83
91
|
return { ...held, nodes: [...held.nodes, ...added], edges: [...edges, ...incoming.values()], groups };
|
|
84
92
|
}
|
|
85
93
|
function groupRank(graph, vocabulary) {
|
|
86
|
-
const
|
|
94
|
+
const rootGroups2 = new Set(graph.roots.map((id) => requireNode(graph, id).group));
|
|
87
95
|
const sourced = new Set(graph.nodes.filter((node) => vocabulary.hasSource(node)).map((node) => node.group));
|
|
88
96
|
return (node) => {
|
|
89
97
|
if (node.group === void 0) return 3;
|
|
90
|
-
if (
|
|
98
|
+
if (rootGroups2.has(node.group)) return 0;
|
|
91
99
|
return sourced.has(node.group) ? 1 : 2;
|
|
92
100
|
};
|
|
93
101
|
}
|
|
94
|
-
function
|
|
95
|
-
|
|
102
|
+
function accessInto(edges, id) {
|
|
103
|
+
return edges.reduce((held, edge) => edge.to === id && (edge.type === "read" || edge.type === "write") ? dataAccess.mergeAccess(held, edge.type) : held, void 0);
|
|
104
|
+
}
|
|
105
|
+
function toDiagramNode(node, { direction, options, glyphs, vocabulary }, drawn, records) {
|
|
106
|
+
var _a;
|
|
107
|
+
const { graph, visible } = drawn;
|
|
108
|
+
const count = expandCount(graph, visible, node.id, direction, vocabulary, drawn.merged);
|
|
96
109
|
const isRoot = graph.roots.includes(node.id);
|
|
97
110
|
const tone = isRoot ? "info" : node.unresolved ? "warning" : void 0;
|
|
98
|
-
const compact = !isRoot && vocabulary.isData(node) && !vocabulary.hasSource(node);
|
|
111
|
+
const compact = node.group !== void 0 && records.has(node.group) || !isRoot && vocabulary.isData(node) && !vocabulary.hasSource(node);
|
|
112
|
+
const aside = callGraphVocabulary.dataMemberAside(node);
|
|
113
|
+
const access = glyphs.access && accessInto(visible.edges, node.id);
|
|
99
114
|
return {
|
|
100
115
|
id: node.id,
|
|
101
116
|
label: node.label,
|
|
@@ -104,13 +119,16 @@ function toDiagramNode(node, { graph, visible, direction, options, glyphs, vocab
|
|
|
104
119
|
level: node.depth,
|
|
105
120
|
...options.grouped && node.group !== void 0 ? { group: node.group } : {},
|
|
106
121
|
...compact ? { size: "compact" } : {},
|
|
122
|
+
...aside !== void 0 ? { aside } : {},
|
|
123
|
+
...access ? { mark: (_a = glyphs.access) == null ? void 0 : _a.call(glyphs, access) } : {},
|
|
107
124
|
...tone !== void 0 ? { tone } : {},
|
|
108
125
|
...vocabulary.muted(node) ? { muted: true } : {},
|
|
109
126
|
...count > 0 ? { expandCount: count } : {}
|
|
110
127
|
};
|
|
111
128
|
}
|
|
112
|
-
function toDiagramEdge(edge, { options, glyphs, edgeLabels }) {
|
|
113
|
-
const
|
|
129
|
+
function toDiagramEdge(edge, { options, glyphs, edgeLabels, vocabulary }, drawn) {
|
|
130
|
+
const merge = drawn.merged.get(edge.id);
|
|
131
|
+
const label = [callGraphLabels.edgeLabel(edge, options), merge && countWords(merge.members, drawn.graph, vocabulary)].filter(Boolean).join(" · ") || void 0;
|
|
114
132
|
const title = callGraphLabels.edgeTitle(edge);
|
|
115
133
|
return {
|
|
116
134
|
id: edge.id,
|
|
@@ -137,23 +155,156 @@ function columnGap({
|
|
|
137
155
|
});
|
|
138
156
|
return Math.max(MIN_COLUMN_GAP, Math.round(Math.max(0, ...chars) * PILL_CHAR_WIDTH) + PILL_CHROME);
|
|
139
157
|
}
|
|
158
|
+
function recordGroups(visible, vocabulary) {
|
|
159
|
+
var _a;
|
|
160
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
161
|
+
for (const node of visible.nodes) {
|
|
162
|
+
if (node.group !== void 0) grouped.set(node.group, [...grouped.get(node.group) ?? [], node]);
|
|
163
|
+
}
|
|
164
|
+
const records = /* @__PURE__ */ new Map();
|
|
165
|
+
for (const [group, nodes] of grouped) {
|
|
166
|
+
const kind = (_a = nodes[0]) == null ? void 0 : _a.kind;
|
|
167
|
+
if (kind !== void 0 && nodes.every((node) => vocabulary.isData(node) && callGraphVocabulary.isDataMember(node) && node.kind === kind)) {
|
|
168
|
+
const owner = callGraphVocabulary.DATA_MEMBER_OWNER[kind];
|
|
169
|
+
if (owner === void 0) throw new Error(`call graph: no owner kind for data member "${kind}"`);
|
|
170
|
+
records.set(group, owner);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return records;
|
|
174
|
+
}
|
|
175
|
+
const STAND_IN_PREFIX = "group:";
|
|
176
|
+
function standInId(group) {
|
|
177
|
+
return `${STAND_IN_PREFIX}${group}`;
|
|
178
|
+
}
|
|
179
|
+
function rootGroups(graph) {
|
|
180
|
+
return new Set(graph.roots.map((id) => requireNode(graph, id).group));
|
|
181
|
+
}
|
|
182
|
+
function collapsibleGroups(graph, visible) {
|
|
183
|
+
const roots = rootGroups(graph);
|
|
184
|
+
return [...new Set(visible.nodes.map((node) => node.group))].filter((group) => group !== void 0 && !roots.has(group));
|
|
185
|
+
}
|
|
186
|
+
function countWords(members, graph, vocabulary) {
|
|
187
|
+
const [first] = members;
|
|
188
|
+
const kind = first && members.every((member) => member.kind === first.kind) ? vocabulary.kindOf(graph, first) : "member";
|
|
189
|
+
return `${members.length} ${kind}${members.length === 1 ? "" : "s"}`;
|
|
190
|
+
}
|
|
191
|
+
function memberProperties(members) {
|
|
192
|
+
const keys = { column: "columns", field: "fields" };
|
|
193
|
+
const names = /* @__PURE__ */ new Map();
|
|
194
|
+
for (const member of members) {
|
|
195
|
+
const key = keys[member.kind] ?? "members";
|
|
196
|
+
names.set(key, [...names.get(key) ?? [], member.label]);
|
|
197
|
+
}
|
|
198
|
+
return Object.fromEntries([...names].map(([key, list]) => [key, list.join(", ")]));
|
|
199
|
+
}
|
|
200
|
+
function mergeEdges(id, sources, standInOf, nodes) {
|
|
201
|
+
const [first] = sources;
|
|
202
|
+
if (!first) throw new Error(`call graph: merged edge "${id}" stands for no edge`);
|
|
203
|
+
const memberIds = [...new Set(sources.flatMap((edge2) => [edge2.from, edge2.to]).filter((end) => standInOf.has(end)))];
|
|
204
|
+
const members = memberIds.map((member) => {
|
|
205
|
+
const node = nodes.get(member);
|
|
206
|
+
if (!node) throw new Error(`call graph: no node "${member}"`);
|
|
207
|
+
return node;
|
|
208
|
+
});
|
|
209
|
+
const kind = sources.every((edge2) => edge2.kind === first.kind) ? first.kind : void 0;
|
|
210
|
+
const edge = {
|
|
211
|
+
id,
|
|
212
|
+
from: standInOf.get(first.from) ?? first.from,
|
|
213
|
+
to: standInOf.get(first.to) ?? first.to,
|
|
214
|
+
type: first.type,
|
|
215
|
+
...kind !== void 0 ? { kind } : {},
|
|
216
|
+
sites: distinctSites(sources.flatMap((source) => source.sites)),
|
|
217
|
+
properties: memberProperties(members)
|
|
218
|
+
};
|
|
219
|
+
return [edge, { sources: [...sources], members }];
|
|
220
|
+
}
|
|
221
|
+
function foldEdges(edges, standInOf, nodes) {
|
|
222
|
+
const kept = [];
|
|
223
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
224
|
+
for (const edge of edges) {
|
|
225
|
+
const from = standInOf.get(edge.from) ?? edge.from;
|
|
226
|
+
const to = standInOf.get(edge.to) ?? edge.to;
|
|
227
|
+
if (from === edge.from && to === edge.to) kept.push(edge);
|
|
228
|
+
else grouped.set(`${from}|${to}|${edge.type}`, [...grouped.get(`${from}|${to}|${edge.type}`) ?? [], edge]);
|
|
229
|
+
}
|
|
230
|
+
const merged = new Map([...grouped].map(([id, sources]) => mergeEdges(id, sources, standInOf, nodes)).map(([edge, merge]) => [edge.id, { edge, merge }]));
|
|
231
|
+
return { edges: [...kept, ...[...merged.values()].map(({ edge }) => edge)], merged: new Map([...merged].map(([id, { merge }]) => [id, merge])) };
|
|
232
|
+
}
|
|
233
|
+
function standInNode(id, fold, graph, records, edges) {
|
|
234
|
+
var _a, _b;
|
|
235
|
+
const [first, ...rest] = fold.members;
|
|
236
|
+
if (!first) throw new Error(`call graph: collapsed group "${fold.group}" holds no node`);
|
|
237
|
+
const nearest = rest.reduce((best, member) => Math.abs(member.depth) < Math.abs(best.depth) ? member : best, first);
|
|
238
|
+
return {
|
|
239
|
+
id,
|
|
240
|
+
identifier: {},
|
|
241
|
+
kind: records.get(fold.group) ?? first.kind,
|
|
242
|
+
label: ((_b = (_a = graph.groups) == null ? void 0 : _a.find((group) => group.id === fold.group)) == null ? void 0 : _b.label) ?? fold.group,
|
|
243
|
+
group: fold.group,
|
|
244
|
+
depth: nearest.depth,
|
|
245
|
+
in: edges.filter((edge) => edge.to === id).length,
|
|
246
|
+
out: edges.filter((edge) => edge.from === id).length
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
function foldGroups(graph, visible, collapsed, records) {
|
|
250
|
+
var _a;
|
|
251
|
+
const roots = rootGroups(graph);
|
|
252
|
+
const folds = /* @__PURE__ */ new Map();
|
|
253
|
+
const standInOf = /* @__PURE__ */ new Map();
|
|
254
|
+
for (const node of visible.nodes) {
|
|
255
|
+
if (node.group === void 0 || roots.has(node.group) || !collapsed.includes(node.group)) continue;
|
|
256
|
+
const id = standInId(node.group);
|
|
257
|
+
folds.set(id, { group: node.group, members: [...((_a = folds.get(id)) == null ? void 0 : _a.members) ?? [], node] });
|
|
258
|
+
standInOf.set(node.id, id);
|
|
259
|
+
}
|
|
260
|
+
if (folds.size === 0) return { graph, visible, folds, merged: /* @__PURE__ */ new Map() };
|
|
261
|
+
const { edges, merged } = foldEdges(graph.edges, standInOf, new Map(graph.nodes.map((node) => [node.id, node])));
|
|
262
|
+
const standIns = [...folds].map(([id, fold]) => standInNode(id, fold, graph, records, edges));
|
|
263
|
+
const nodes = [...visible.nodes.filter((node) => !standInOf.has(node.id)), ...standIns];
|
|
264
|
+
const drawnIds = new Set(nodes.map((node) => node.id));
|
|
265
|
+
return {
|
|
266
|
+
graph: { ...graph, nodes: [...graph.nodes.filter((node) => !standInOf.has(node.id)), ...standIns], edges },
|
|
267
|
+
visible: { nodes, edges: edges.filter((edge) => drawnIds.has(edge.from) && drawnIds.has(edge.to)) },
|
|
268
|
+
folds,
|
|
269
|
+
merged
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
function toDiagramGroup({ id, label }, { glyphs, graph, vocabulary }, drawn, records, collapsible) {
|
|
273
|
+
const fold = drawn.folds.get(standInId(id));
|
|
274
|
+
return {
|
|
275
|
+
id,
|
|
276
|
+
label: glyphs.group(callGraphLabels.groupCaption(label), records.get(id)),
|
|
277
|
+
title: label,
|
|
278
|
+
...records.has(id) ? { variant: "record" } : {},
|
|
279
|
+
...(collapsible == null ? void 0 : collapsible.has(id)) ? { collapsed: fold !== void 0 } : {},
|
|
280
|
+
...fold ? { aside: countWords(fold.members, graph, vocabulary) } : {}
|
|
281
|
+
};
|
|
282
|
+
}
|
|
140
283
|
function toDiagram(input) {
|
|
141
|
-
const { graph, visible, options,
|
|
142
|
-
const
|
|
284
|
+
const { graph, visible, options, vocabulary, collapsed } = input;
|
|
285
|
+
const records = options.grouped ? recordGroups(visible, vocabulary) : /* @__PURE__ */ new Map();
|
|
286
|
+
const drawn = options.grouped && collapsed ? foldGroups(graph, visible, collapsed, records) : { graph, visible, folds: /* @__PURE__ */ new Map(), merged: /* @__PURE__ */ new Map() };
|
|
287
|
+
const collapsible = options.grouped && collapsed ? new Set(collapsibleGroups(graph, visible)) : void 0;
|
|
288
|
+
const rank = groupRank(drawn.graph, vocabulary);
|
|
143
289
|
return {
|
|
144
|
-
nodes: [...visible.nodes].sort((a, b) => rank(a) - rank(b)).map((node) => toDiagramNode(node, input)),
|
|
145
|
-
edges: visible.edges.map((edge) => toDiagramEdge(edge, input)),
|
|
146
|
-
groups: options.grouped ? (graph.groups ?? []).map((
|
|
290
|
+
nodes: [...drawn.visible.nodes].sort((a, b) => rank(a) - rank(b)).map((node) => toDiagramNode(node, input, drawn, records)),
|
|
291
|
+
edges: drawn.visible.edges.map((edge) => toDiagramEdge(edge, input, drawn)),
|
|
292
|
+
groups: options.grouped ? (graph.groups ?? []).map((group) => toDiagramGroup(group, input, drawn, records, collapsible)) : [],
|
|
293
|
+
drawn
|
|
147
294
|
};
|
|
148
295
|
}
|
|
149
296
|
exports.CALL_GRAPH_DEFAULT_DEPTH = CALL_GRAPH_DEFAULT_DEPTH;
|
|
150
297
|
exports.CALL_GRAPH_MAX_DEPTH = CALL_GRAPH_MAX_DEPTH;
|
|
151
298
|
exports.DEFAULT_EDGE_LABELS = DEFAULT_EDGE_LABELS;
|
|
299
|
+
exports.baseAccess = baseAccess;
|
|
300
|
+
exports.collapsibleGroups = collapsibleGroups;
|
|
152
301
|
exports.columnGap = columnGap;
|
|
153
302
|
exports.expandCount = expandCount;
|
|
154
303
|
exports.expansionDirection = expansionDirection;
|
|
155
304
|
exports.mergeGraph = mergeGraph;
|
|
305
|
+
exports.recordGroups = recordGroups;
|
|
156
306
|
exports.requireNode = requireNode;
|
|
307
|
+
exports.standInId = standInId;
|
|
157
308
|
exports.toDiagram = toDiagram;
|
|
158
309
|
exports.toggleAccess = toggleAccess;
|
|
159
310
|
exports.visibleGraph = visibleGraph;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"call-graph-model.cjs","sources":["../../../src/data/call-graph/call-graph-model.ts"],"sourcesContent":["// Pure mapping from a call graph to what GraphDiagram draws, and how a `+N` expansion merges into the\n// held graph. It decides what is shown and leaves drawing a glyph to the DiagramGlyphs it is handed,\n// so it renders nothing itself.\nimport type { ReactNode } from \"react\";\nimport type { BadgeTone } from \"../Badge\";\nimport type { GraphDiagramEdge, GraphDiagramGroup, GraphDiagramNode } from \"../graph-diagram-model\";\nimport { edgeLabel, edgeTitle, groupCaption, isConditional, type PillOptions } from \"./call-graph-labels\";\nimport { nodeTitle, siteKey, type CallGraphVocabulary } from \"./call-graph-vocabulary\";\nimport {\n CALL_GRAPH_ACCESS,\n type CallGraph,\n type CallGraphAccess,\n type CallGraphDirection,\n type CallGraphEdge,\n type CallGraphEdgeLabels,\n type CallGraphEdgeType,\n type CallGraphGroup,\n type CallGraphNode,\n type CallGraphSite,\n} from \"./types\";\n\n/** The deepest graph uir builds (graph.MaxDepth). */\nexport const CALL_GRAPH_MAX_DEPTH = 8;\n/** The depth uir builds when none is asked for (graph.DefaultDepth). */\nexport const CALL_GRAPH_DEFAULT_DEPTH = 2;\n\nexport const DEFAULT_EDGE_LABELS: CallGraphEdgeLabels = { call: \"call\", dispatch: \"dispatch\", read: \"read\", write: \"write\" };\n\n/** The tone each edge type but a plain call is drawn in: dispatch blue, a read green, a write amber. */\nconst EDGE_TONE: Record<Exclude<CallGraphEdgeType, \"call\">, BadgeTone> = { dispatch: \"info\", read: \"success\", write: \"warning\" };\n\n/** Turns one access type on or off, in the usual order. Turning the last one off fails: a graph follows something. */\nexport function toggleAccess(access: readonly CallGraphAccess[], type: CallGraphAccess): CallGraphAccess[] {\n const on = !access.includes(type);\n if (!on && access.length === 1) throw new Error(`call graph: ${type} is the only access type on`);\n return CALL_GRAPH_ACCESS.filter((entry) => (entry === type ? on : access.includes(entry)));\n}\n\nexport interface GraphView {\n direction: CallGraphDirection;\n /** Nodes further than this many hops from the root are hidden. */\n depth: number;\n /** Node ids shown regardless of `depth`, because a `+N` expansion revealed them. */\n revealed: readonly string[];\n}\n\nexport interface VisibleGraph {\n nodes: CallGraphNode[];\n edges: CallGraphEdge[];\n}\n\nexport interface DiagramOptions extends PillOptions {\n /** Box nodes by their `group`. */\n grouped: boolean;\n}\n\nexport type DiagramNode = GraphDiagramNode & { label: string; level: number; title: string };\nexport type DiagramEdge = GraphDiagramEdge & { dashed: boolean };\nexport type DiagramGroup = GraphDiagramGroup & { title: string };\n\nexport interface Diagram {\n nodes: DiagramNode[];\n edges: DiagramEdge[];\n groups: DiagramGroup[];\n}\n\n/** Draws the glyphs the model chooses. The component supplies icons; the tests supply strings. */\nexport interface DiagramGlyphs {\n /** `words` is the icon's name for a screen reader, such as `external function`. */\n node(glyph: string, words: string): ReactNode;\n /** The pill icon of an edge type; a plain call has none. */\n edge(type: CallGraphEdgeType): ReactNode | undefined;\n group(caption: string): ReactNode;\n}\n\nexport interface DiagramInput {\n graph: CallGraph;\n visible: VisibleGraph;\n direction: CallGraphDirection;\n options: DiagramOptions;\n glyphs: DiagramGlyphs;\n vocabulary: CallGraphVocabulary;\n edgeLabels: CallGraphEdgeLabels;\n}\n\nexport function requireNode(graph: CallGraph, id: string): CallGraphNode {\n const node = graph.nodes.find((candidate) => candidate.id === id);\n if (!node) throw new Error(`call graph: no node \"${id}\"`);\n return node;\n}\n\nfunction inDirection(depth: number, direction: CallGraphDirection): boolean {\n if (direction === \"both\" || depth === 0) return true;\n return direction === \"callees\" ? depth > 0 : depth < 0;\n}\n\n/** The nodes on the requested side within `depth`, plus revealed ones, and the edges between them. */\nexport function visibleGraph(graph: CallGraph, view: GraphView): VisibleGraph {\n const revealed = new Set(view.revealed);\n const nodes = graph.nodes.filter(\n (node) => inDirection(node.depth, view.direction) && (Math.abs(node.depth) <= view.depth || revealed.has(node.id)),\n );\n const ids = new Set(nodes.map((node) => node.id));\n return { nodes, edges: graph.edges.filter((edge) => ids.has(edge.from) && ids.has(edge.to)) };\n}\n\n/** A caller grows toward its own callers; the root and callees grow toward their callees. */\nfunction outerSide(node: CallGraphNode): \"in\" | \"out\" {\n return node.depth < 0 ? \"in\" : \"out\";\n}\n\n/** The direction a `+N` expansion of the node walks: its outer side, the side `+N` counts. */\nexport function expansionDirection(node: CallGraphNode): Exclude<CallGraphDirection, \"both\"> {\n return outerSide(node) === \"in\" ? \"callers\" : \"callees\";\n}\n\n/** The ids at the far end of a node's edges on its outer side, as the response holds them. */\nfunction outerNeighbours(graph: CallGraph, node: CallGraphNode): string[] {\n const side = outerSide(node);\n return graph.edges.filter((edge) => (side === \"out\" ? edge.from : edge.to) === node.id).map((edge) => (side === \"out\" ? edge.to : edge.from));\n}\n\n/** The neighbours on a node's outer side that the response holds and are not drawn. */\nexport function hiddenNeighbours(graph: CallGraph, visible: VisibleGraph, nodeId: string): string[] {\n const drawn = new Set(visible.nodes.map((node) => node.id));\n return outerNeighbours(graph, requireNode(graph, nodeId)).filter((id, index, all) => !drawn.has(id) && all.indexOf(id) === index);\n}\n\n/**\n * The `+N` on a node: how many more edges there are to load on its outer side. Only that side's count\n * is a total (`out` for the root and callees, `in` for callers); the other equals the edges in the\n * response. Excluded neighbours are in neither. From it come off the edges drawn. A node without a\n * source cannot be expanded, nor can the side the direction hides.\n */\nexport function expandCount(\n graph: CallGraph,\n visible: VisibleGraph,\n nodeId: string,\n direction: CallGraphDirection,\n vocabulary: Pick<CallGraphVocabulary, \"hasSource\">,\n): number {\n const node = requireNode(graph, nodeId);\n const side = outerSide(node);\n if (!vocabulary.hasSource(node) || direction === (side === \"out\" ? \"callers\" : \"callees\")) return 0;\n const drawn = new Set(visible.nodes.map((entry) => entry.id));\n const accounted = outerNeighbours(graph, node).filter((id) => drawn.has(id)).length;\n return Math.max(0, (side === \"out\" ? node.out : node.in) - accounted);\n}\n\nexport interface NodeTotals {\n callers?: number;\n callees?: number;\n readers?: number;\n writers?: number;\n}\n\n/**\n * A data node's readers, writers and callers: the edges into it the graph holds, by type, each left\n * out when there are none.\n */\nfunction accessTotals(graph: CallGraph, node: CallGraphNode): NodeTotals {\n const into = (types: readonly CallGraphEdgeType[]) => graph.edges.filter((edge) => edge.to === node.id && types.includes(edge.type)).length;\n const totals: [keyof NodeTotals, number][] = [[\"readers\", into([\"read\"])], [\"writers\", into([\"write\"])], [\"callers\", into([\"call\", \"dispatch\"])]];\n return Object.fromEntries(totals.filter(([, count]) => count > 0));\n}\n\n/**\n * A node's call totals on the sides the response walked: callees at depth >= 0, callers at depth <= 0.\n * A data node counts who reads, writes and calls it instead.\n */\nexport function walkedTotals(graph: CallGraph, node: CallGraphNode, vocabulary: Pick<CallGraphVocabulary, \"isData\">): NodeTotals {\n if (vocabulary.isData(node)) return accessTotals(graph, node);\n const walked = (sign: number) => graph.nodes.some((other) => Math.sign(other.depth) === sign);\n return {\n ...(node.depth <= 0 && walked(-1) ? { callers: node.in } : {}),\n ...(node.depth >= 0 && walked(1) ? { callees: node.out } : {}),\n };\n}\n\nfunction distinctSites(sites: CallGraphSite[]): CallGraphSite[] {\n return sites.filter((site, index) => sites.findIndex((other) => siteKey(other) === siteKey(site)) === index);\n}\n\nconst edgeKey = (edge: CallGraphEdge) => `${edge.from}|${edge.to}|${edge.type}`;\n\n/**\n * Merges a one-hop expansion into the held graph. The expansion is rooted at a held node, so its\n * depths are re-signed from that node's depth. Held nodes keep their place; edges are keyed by\n * `from|to|type`, gain the call sites they did not hold and keep their first non-empty properties;\n * the held response's other fields stay.\n */\nexport function mergeGraph<T extends CallGraph>(held: T, expansion: CallGraph): T {\n const [rootId] = expansion.roots;\n const base = held.nodes.find((node) => node.id === rootId);\n if (rootId === undefined || !base) throw new Error(`call graph: expansion root \"${rootId}\" is not in the held graph`);\n const heldIds = new Set(held.nodes.map((node) => node.id));\n const added = expansion.nodes.filter((node) => !heldIds.has(node.id)).map((node) => ({ ...node, depth: base.depth + node.depth }));\n const incoming = new Map(expansion.edges.map((edge) => [edgeKey(edge), edge]));\n const edges = held.edges.map((edge) => {\n const more = incoming.get(edgeKey(edge));\n incoming.delete(edgeKey(edge));\n if (!more) return edge;\n const properties = edge.properties && Object.keys(edge.properties).length > 0 ? edge.properties : more.properties;\n return { ...edge, sites: distinctSites([...edge.sites, ...more.sites]), ...(properties ? { properties } : {}) };\n });\n const groupIds = new Set((held.groups ?? []).map((group) => group.id));\n const groups: CallGraphGroup[] = [...(held.groups ?? []), ...(expansion.groups ?? []).filter((group) => !groupIds.has(group.id))];\n return { ...held, nodes: [...held.nodes, ...added], edges: [...edges, ...incoming.values()], groups };\n}\n\n/**\n * The order nodes are handed to the diagram, which stacks groups in the order they first appear: the\n * root's group, then the other groups holding nodes with a source, then the others, then nodes in no group.\n */\nfunction groupRank(graph: CallGraph, vocabulary: CallGraphVocabulary): (node: CallGraphNode) => number {\n const rootGroups = new Set(graph.roots.map((id) => requireNode(graph, id).group));\n const sourced = new Set(graph.nodes.filter((node) => vocabulary.hasSource(node)).map((node) => node.group));\n return (node) => {\n if (node.group === undefined) return 3;\n if (rootGroups.has(node.group)) return 0;\n return sourced.has(node.group) ? 1 : 2;\n };\n}\n\nfunction toDiagramNode(node: CallGraphNode, { graph, visible, direction, options, glyphs, vocabulary }: DiagramInput): DiagramNode {\n const count = expandCount(graph, visible, node.id, direction, vocabulary);\n const isRoot = graph.roots.includes(node.id);\n const tone = isRoot ? \"info\" : node.unresolved ? \"warning\" : undefined;\n // A table, column, entity or field is a name its group box already places: one short line will do.\n const compact = !isRoot && vocabulary.isData(node) && !vocabulary.hasSource(node);\n return {\n id: node.id,\n label: node.label,\n icon: glyphs.node(vocabulary.glyphOf(graph, node), vocabulary.kindOf(graph, node)),\n title: nodeTitle(graph, node, vocabulary),\n level: node.depth,\n ...(options.grouped && node.group !== undefined ? { group: node.group } : {}),\n ...(compact ? { size: \"compact\" as const } : {}),\n ...(tone !== undefined ? { tone } : {}),\n ...(vocabulary.muted(node) ? { muted: true } : {}),\n ...(count > 0 ? { expandCount: count } : {}),\n };\n}\n\nfunction toDiagramEdge(edge: CallGraphEdge, { options, glyphs, edgeLabels }: DiagramInput): DiagramEdge {\n const label = edgeLabel(edge, options);\n const title = edgeTitle(edge);\n return {\n id: edge.id,\n from: edge.from,\n to: edge.to,\n dashed: isConditional(edge),\n ...(edge.type === \"call\" ? {} : { tone: EDGE_TONE[edge.type], icon: glyphs.edge(edge.type), iconLabel: edgeLabels[edge.type] }),\n ...(label !== undefined ? { label } : {}),\n ...(title !== undefined ? { title } : {}),\n };\n}\n\n/** Mean glyph advance of the 10px pill text, and the pill's padding plus a little air. */\nconst PILL_CHAR_WIDTH = 5.2;\nconst PILL_CHROME = 22;\n/** The room a pill's icon and its gap take, in characters. */\nconst PILL_ICON_CHARS = 3;\nconst MIN_COLUMN_GAP = 96;\n\n/**\n * The gap between columns: as wide as the longest pill on an edge between two columns, so no pill\n * covers a node. Wider gaps than the pills need make the diagram wider, and so smaller once fitted.\n */\nexport function columnGap({\n nodes,\n edges,\n}: {\n nodes: readonly Pick<DiagramNode, \"id\" | \"level\">[];\n edges: readonly Pick<DiagramEdge, \"id\" | \"from\" | \"to\" | \"label\" | \"icon\">[];\n}): number {\n const level = new Map(nodes.map((node) => [node.id, node.level]));\n const chars = edges\n .filter((edge) => level.get(edge.from) !== level.get(edge.to))\n .map((edge) => (edge.label?.length ?? 0) + (edge.icon != null ? PILL_ICON_CHARS : 0));\n return Math.max(MIN_COLUMN_GAP, Math.round(Math.max(0, ...chars) * PILL_CHAR_WIDTH) + PILL_CHROME);\n}\n\nexport function toDiagram(input: DiagramInput): Diagram {\n const { graph, visible, options, glyphs, vocabulary } = input;\n const rank = groupRank(graph, vocabulary);\n return {\n nodes: [...visible.nodes].sort((a, b) => rank(a) - rank(b)).map((node) => toDiagramNode(node, input)),\n edges: visible.edges.map((edge) => toDiagramEdge(edge, input)),\n groups: options.grouped ? (graph.groups ?? []).map(({ id, label }) => ({ id, label: glyphs.group(groupCaption(label)), title: label })) : [],\n };\n}\n"],"names":["CALL_GRAPH_ACCESS","types","siteKey","nodeTitle","edgeLabel","edgeTitle","isConditional","groupCaption"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"call-graph-model.cjs","sources":["../../../src/data/call-graph/call-graph-model.ts"],"sourcesContent":["// Pure mapping from a call graph to what GraphDiagram draws, and how a `+N` expansion merges into the\n// held graph. It decides what is shown and leaves drawing a glyph to the DiagramGlyphs it is handed,\n// so it renders nothing itself.\nimport type { ReactNode } from \"react\";\nimport type { BadgeTone } from \"../Badge\";\nimport { mergeAccess, type DataAccess } from \"../data-access\";\nimport type { GraphDiagramEdge, GraphDiagramGroup, GraphDiagramNode } from \"../graph-diagram-model\";\nimport { edgeLabel, edgeTitle, groupCaption, isConditional, type PillOptions } from \"./call-graph-labels\";\nimport { DATA_MEMBER_OWNER, dataMemberAside, isDataMember, nodeTitle, siteKey, type CallGraphVocabulary } from \"./call-graph-vocabulary\";\nimport {\n CALL_GRAPH_ACCESS,\n type CallGraph,\n type CallGraphAccess,\n type CallGraphDirection,\n type CallGraphEdge,\n type CallGraphEdgeLabels,\n type CallGraphEdgeType,\n type CallGraphGroup,\n type CallGraphNode,\n type CallGraphSite,\n} from \"./types\";\n\n/** The deepest graph uir builds (graph.MaxDepth). */\nexport const CALL_GRAPH_MAX_DEPTH = 8;\n/** The depth uir builds when none is asked for (graph.DefaultDepth). */\nexport const CALL_GRAPH_DEFAULT_DEPTH = 2;\n\nexport const DEFAULT_EDGE_LABELS: CallGraphEdgeLabels = { call: \"call\", dispatch: \"dispatch\", read: \"read\", write: \"write\" };\n\n/** The tone each edge type but a plain call is drawn in: dispatch blue, a read green, a write amber. */\nconst EDGE_TONE: Record<Exclude<CallGraphEdgeType, \"call\">, BadgeTone> = { dispatch: \"info\", read: \"success\", write: \"warning\" };\n\n/** Turns one access type on or off, in the usual order. Turning the last one off fails: a graph follows something. */\nexport function toggleAccess(access: readonly CallGraphAccess[], type: CallGraphAccess): CallGraphAccess[] {\n const on = !access.includes(type);\n if (!on && type !== \"variable\" && baseAccess(access).length === 1) throw new Error(`call graph: ${type} is the only access type on`);\n return ACCESS_ORDER.filter((entry) => (entry === type ? on : access.includes(entry)));\n}\n\n/** Every access type in the usual order: variables last, on top of the others. */\nconst ACCESS_ORDER: readonly CallGraphAccess[] = [...CALL_GRAPH_ACCESS, \"variable\"];\n\n/** The access types of `access` that are not variables, at least one of which a graph follows. */\nexport function baseAccess(access: readonly CallGraphAccess[]): CallGraphAccess[] {\n return access.filter((type) => CALL_GRAPH_ACCESS.includes(type));\n}\n\nexport interface GraphView {\n direction: CallGraphDirection;\n /** Nodes further than this many hops from the root are hidden. */\n depth: number;\n /** Node ids shown regardless of `depth`, because a `+N` expansion revealed them. */\n revealed: readonly string[];\n}\n\nexport interface VisibleGraph {\n nodes: CallGraphNode[];\n edges: CallGraphEdge[];\n}\n\nexport interface DiagramOptions extends PillOptions {\n /** Box nodes by their `group`. */\n grouped: boolean;\n}\n\nexport type DiagramNode = GraphDiagramNode & { label: string; level: number; title: string };\nexport type DiagramEdge = GraphDiagramEdge & { dashed: boolean };\nexport type DiagramGroup = GraphDiagramGroup & { title: string; aside?: string };\n\nexport interface Diagram {\n nodes: DiagramNode[];\n edges: DiagramEdge[];\n groups: DiagramGroup[];\n /** The graph as drawn, collapsed groups folded into their stand-ins: what a selection is looked up in. */\n drawn: DrawnGraph;\n}\n\n/** Draws the glyphs the model chooses. The component supplies icons; the tests supply strings. */\nexport interface DiagramGlyphs {\n /** `words` is the icon's name for a screen reader, such as `external function`. */\n node(glyph: string, words: string): ReactNode;\n /** The pill icon of an edge type; a plain call has none. */\n edge(type: CallGraphEdgeType): ReactNode | undefined;\n group(caption: string, glyph?: string): ReactNode;\n /** The mark of a node the reads and writes into it access; without it no node is marked. */\n access?(access: DataAccess): ReactNode;\n}\n\nexport interface DiagramInput {\n graph: CallGraph;\n visible: VisibleGraph;\n direction: CallGraphDirection;\n options: DiagramOptions;\n glyphs: DiagramGlyphs;\n vocabulary: CallGraphVocabulary;\n edgeLabels: CallGraphEdgeLabels;\n /**\n * The groups drawn as their header alone, by id: each folds into one stand-in node, and its members'\n * edges merge onto it. The root's group never folds. Leave it out and no group can collapse.\n */\n collapsed?: readonly string[];\n}\n\nexport function requireNode(graph: CallGraph, id: string): CallGraphNode {\n const node = graph.nodes.find((candidate) => candidate.id === id);\n if (!node) throw new Error(`call graph: no node \"${id}\"`);\n return node;\n}\n\nfunction inDirection(depth: number, direction: CallGraphDirection): boolean {\n if (direction === \"both\" || depth === 0) return true;\n return direction === \"callees\" ? depth > 0 : depth < 0;\n}\n\n/** The nodes on the requested side within `depth`, plus revealed ones, and the edges between them. */\nexport function visibleGraph(graph: CallGraph, view: GraphView): VisibleGraph {\n const revealed = new Set(view.revealed);\n const nodes = graph.nodes.filter(\n (node) => inDirection(node.depth, view.direction) && (Math.abs(node.depth) <= view.depth || revealed.has(node.id)),\n );\n const ids = new Set(nodes.map((node) => node.id));\n return { nodes, edges: graph.edges.filter((edge) => ids.has(edge.from) && ids.has(edge.to)) };\n}\n\n/** A caller grows toward its own callers; the root and callees grow toward their callees. */\nfunction outerSide(node: CallGraphNode): \"in\" | \"out\" {\n return node.depth < 0 ? \"in\" : \"out\";\n}\n\n/** The direction a `+N` expansion of the node walks: its outer side, the side `+N` counts. */\nexport function expansionDirection(node: CallGraphNode): Exclude<CallGraphDirection, \"both\"> {\n return outerSide(node) === \"in\" ? \"callers\" : \"callees\";\n}\n\n/** A node's edges on its outer side, as the response holds them. */\nfunction outerEdges(graph: CallGraph, node: CallGraphNode): CallGraphEdge[] {\n const side = outerSide(node);\n return graph.edges.filter((edge) => (side === \"out\" ? edge.from : edge.to) === node.id);\n}\n\n/** The ids at the far end of a node's edges on its outer side, as the response holds them. */\nfunction outerNeighbours(graph: CallGraph, node: CallGraphNode): string[] {\n const side = outerSide(node);\n return outerEdges(graph, node).map((edge) => (side === \"out\" ? edge.to : edge.from));\n}\n\n/** The neighbours on a node's outer side that the response holds and are not drawn. */\nexport function hiddenNeighbours(graph: CallGraph, visible: VisibleGraph, nodeId: string): string[] {\n const drawn = new Set(visible.nodes.map((node) => node.id));\n return outerNeighbours(graph, requireNode(graph, nodeId)).filter((id, index, all) => !drawn.has(id) && all.indexOf(id) === index);\n}\n\n/**\n * The `+N` on a node: how many more edges there are to load on its outer side. Only that side's count\n * is a total (`out` for the root and callees, `in` for callers); the other equals the edges in the\n * response. Excluded neighbours are in neither. From it come off the edges drawn, a merged edge counting\n * every edge it stands for. A node without a source cannot be expanded, nor can the side the direction hides.\n */\nexport function expandCount(\n graph: CallGraph,\n visible: VisibleGraph,\n nodeId: string,\n direction: CallGraphDirection,\n vocabulary: Pick<CallGraphVocabulary, \"hasSource\">,\n merged: ReadonlyMap<string, EdgeMerge> = new Map(),\n): number {\n const node = requireNode(graph, nodeId);\n const side = outerSide(node);\n if (!vocabulary.hasSource(node) || direction === (side === \"out\" ? \"callers\" : \"callees\")) return 0;\n const drawn = new Set(visible.nodes.map((entry) => entry.id));\n const accounted = outerEdges(graph, node)\n .filter((edge) => drawn.has(side === \"out\" ? edge.to : edge.from))\n .reduce((sum, edge) => sum + (merged.get(edge.id)?.sources.length ?? 1), 0);\n return Math.max(0, (side === \"out\" ? node.out : node.in) - accounted);\n}\n\nexport interface NodeTotals {\n callers?: number;\n callees?: number;\n readers?: number;\n writers?: number;\n}\n\n/**\n * A data node's readers, writers and callers: the edges into it the graph holds, by type, each left\n * out when there are none.\n */\nfunction accessTotals(graph: CallGraph, node: CallGraphNode): NodeTotals {\n const into = (types: readonly CallGraphEdgeType[]) => graph.edges.filter((edge) => edge.to === node.id && types.includes(edge.type)).length;\n const totals: [keyof NodeTotals, number][] = [[\"readers\", into([\"read\"])], [\"writers\", into([\"write\"])], [\"callers\", into([\"call\", \"dispatch\"])]];\n return Object.fromEntries(totals.filter(([, count]) => count > 0));\n}\n\n/**\n * A node's call totals on the sides the response walked: callees at depth >= 0, callers at depth <= 0.\n * A data node counts who reads, writes and calls it instead.\n */\nexport function walkedTotals(graph: CallGraph, node: CallGraphNode, vocabulary: Pick<CallGraphVocabulary, \"isData\">): NodeTotals {\n if (vocabulary.isData(node)) return accessTotals(graph, node);\n const walked = (sign: number) => graph.nodes.some((other) => Math.sign(other.depth) === sign);\n return {\n ...(node.depth <= 0 && walked(-1) ? { callers: node.in } : {}),\n ...(node.depth >= 0 && walked(1) ? { callees: node.out } : {}),\n };\n}\n\nfunction distinctSites(sites: CallGraphSite[]): CallGraphSite[] {\n return sites.filter((site, index) => sites.findIndex((other) => siteKey(other) === siteKey(site)) === index);\n}\n\nconst edgeKey = (edge: CallGraphEdge) => `${edge.from}|${edge.to}|${edge.type}`;\n\n/**\n * Merges a one-hop expansion into the held graph. The expansion is rooted at a held node, so its\n * depths are re-signed from that node's depth. Held nodes keep their place; edges are keyed by\n * `from|to|type`, gain the call sites they did not hold and keep their first non-empty properties;\n * the held response's other fields stay.\n */\nexport function mergeGraph<T extends CallGraph>(held: T, expansion: CallGraph): T {\n const [rootId] = expansion.roots;\n const base = held.nodes.find((node) => node.id === rootId);\n if (rootId === undefined || !base) throw new Error(`call graph: expansion root \"${rootId}\" is not in the held graph`);\n const heldIds = new Set(held.nodes.map((node) => node.id));\n const added = expansion.nodes.filter((node) => !heldIds.has(node.id)).map((node) => ({ ...node, depth: base.depth + node.depth }));\n const incoming = new Map(expansion.edges.map((edge) => [edgeKey(edge), edge]));\n const edges = held.edges.map((edge) => {\n const more = incoming.get(edgeKey(edge));\n incoming.delete(edgeKey(edge));\n if (!more) return edge;\n const properties = edge.properties && Object.keys(edge.properties).length > 0 ? edge.properties : more.properties;\n return { ...edge, sites: distinctSites([...edge.sites, ...more.sites]), ...(properties ? { properties } : {}) };\n });\n const groupIds = new Set((held.groups ?? []).map((group) => group.id));\n const groups: CallGraphGroup[] = [...(held.groups ?? []), ...(expansion.groups ?? []).filter((group) => !groupIds.has(group.id))];\n return { ...held, nodes: [...held.nodes, ...added], edges: [...edges, ...incoming.values()], groups };\n}\n\n/**\n * The order nodes are handed to the diagram, which stacks groups in the order they first appear: the\n * root's group, then the other groups holding nodes with a source, then the others, then nodes in no group.\n */\nfunction groupRank(graph: CallGraph, vocabulary: CallGraphVocabulary): (node: CallGraphNode) => number {\n const rootGroups = new Set(graph.roots.map((id) => requireNode(graph, id).group));\n const sourced = new Set(graph.nodes.filter((node) => vocabulary.hasSource(node)).map((node) => node.group));\n return (node) => {\n if (node.group === undefined) return 3;\n if (rootGroups.has(node.group)) return 0;\n return sourced.has(node.group) ? 1 : 2;\n };\n}\n\n/** How the reads and writes among `edges` into the node access it, or undefined when none do. */\nfunction accessInto(edges: readonly CallGraphEdge[], id: string): DataAccess | undefined {\n return edges.reduce<DataAccess | undefined>((held, edge) => (edge.to === id && (edge.type === \"read\" || edge.type === \"write\") ? mergeAccess(held, edge.type) : held), undefined);\n}\n\nfunction toDiagramNode(node: CallGraphNode, { direction, options, glyphs, vocabulary }: DiagramInput, drawn: DrawnGraph, records: ReadonlyMap<string, string>): DiagramNode {\n const { graph, visible } = drawn;\n const count = expandCount(graph, visible, node.id, direction, vocabulary, drawn.merged);\n const isRoot = graph.roots.includes(node.id);\n const tone = isRoot ? \"info\" : node.unresolved ? \"warning\" : undefined;\n // A table, column, entity or field is a name its group box already places: one short line will do.\n const compact = (node.group !== undefined && records.has(node.group)) || (!isRoot && vocabulary.isData(node) && !vocabulary.hasSource(node));\n const aside = dataMemberAside(node);\n const access = glyphs.access && accessInto(visible.edges, node.id);\n return {\n id: node.id,\n label: node.label,\n icon: glyphs.node(vocabulary.glyphOf(graph, node), vocabulary.kindOf(graph, node)),\n title: nodeTitle(graph, node, vocabulary),\n level: node.depth,\n ...(options.grouped && node.group !== undefined ? { group: node.group } : {}),\n ...(compact ? { size: \"compact\" as const } : {}),\n ...(aside !== undefined ? { aside } : {}),\n ...(access ? { mark: glyphs.access?.(access) } : {}),\n ...(tone !== undefined ? { tone } : {}),\n ...(vocabulary.muted(node) ? { muted: true } : {}),\n ...(count > 0 ? { expandCount: count } : {}),\n };\n}\n\nfunction toDiagramEdge(edge: CallGraphEdge, { options, glyphs, edgeLabels, vocabulary }: DiagramInput, drawn: DrawnGraph): DiagramEdge {\n const merge = drawn.merged.get(edge.id);\n const label = [edgeLabel(edge, options), merge && countWords(merge.members, drawn.graph, vocabulary)].filter(Boolean).join(\" · \") || undefined;\n const title = edgeTitle(edge);\n return {\n id: edge.id,\n from: edge.from,\n to: edge.to,\n dashed: isConditional(edge),\n ...(edge.type === \"call\" ? {} : { tone: EDGE_TONE[edge.type], icon: glyphs.edge(edge.type), iconLabel: edgeLabels[edge.type] }),\n ...(label !== undefined ? { label } : {}),\n ...(title !== undefined ? { title } : {}),\n };\n}\n\n/** Mean glyph advance of the 10px pill text, and the pill's padding plus a little air. */\nconst PILL_CHAR_WIDTH = 5.2;\nconst PILL_CHROME = 22;\n/** The room a pill's icon and its gap take, in characters. */\nconst PILL_ICON_CHARS = 3;\nconst MIN_COLUMN_GAP = 96;\n\n/**\n * The gap between columns: as wide as the longest pill on an edge between two columns, so no pill\n * covers a node. Wider gaps than the pills need make the diagram wider, and so smaller once fitted.\n */\nexport function columnGap({\n nodes,\n edges,\n}: {\n nodes: readonly Pick<DiagramNode, \"id\" | \"level\">[];\n edges: readonly Pick<DiagramEdge, \"id\" | \"from\" | \"to\" | \"label\" | \"icon\">[];\n}): number {\n const level = new Map(nodes.map((node) => [node.id, node.level]));\n const chars = edges\n .filter((edge) => level.get(edge.from) !== level.get(edge.to))\n .map((edge) => (edge.label?.length ?? 0) + (edge.icon != null ? PILL_ICON_CHARS : 0));\n return Math.max(MIN_COLUMN_GAP, Math.round(Math.max(0, ...chars) * PILL_CHAR_WIDTH) + PILL_CHROME);\n}\n\nexport function recordGroups(visible: VisibleGraph, vocabulary: CallGraphVocabulary): Map<string, string> {\n const grouped = new Map<string, CallGraphNode[]>();\n for (const node of visible.nodes) {\n if (node.group !== undefined) grouped.set(node.group, [...(grouped.get(node.group) ?? []), node]);\n }\n const records = new Map<string, string>();\n for (const [group, nodes] of grouped) {\n const kind = nodes[0]?.kind;\n if (kind !== undefined && nodes.every((node) => vocabulary.isData(node) && isDataMember(node) && node.kind === kind)) {\n const owner = DATA_MEMBER_OWNER[kind];\n if (owner === undefined) throw new Error(`call graph: no owner kind for data member \"${kind}\"`);\n records.set(group, owner);\n }\n }\n return records;\n}\n\n/** A collapsed group's members, and the stand-in node drawn for them. */\nexport interface GroupFold {\n group: string;\n members: CallGraphNode[];\n}\n\n/** One edge drawn for the edges of several members: the edges it stands for and the members at their ends. */\nexport interface EdgeMerge {\n sources: CallGraphEdge[];\n members: CallGraphNode[];\n}\n\nexport interface DrawnGraph {\n graph: CallGraph;\n visible: VisibleGraph;\n /** By stand-in id. */\n folds: ReadonlyMap<string, GroupFold>;\n /** By the id of the edge drawn for them. */\n merged: ReadonlyMap<string, EdgeMerge>;\n}\n\nconst STAND_IN_PREFIX = \"group:\";\n\n/** The id of the node a collapsed group is drawn as. */\nexport function standInId(group: string): string {\n return `${STAND_IN_PREFIX}${group}`;\n}\n\nfunction rootGroups(graph: CallGraph): Set<string | undefined> {\n return new Set(graph.roots.map((id) => requireNode(graph, id).group));\n}\n\n/** The groups that hold a drawn node and can collapse: every one but the root's, in first-drawn order. */\nexport function collapsibleGroups(graph: CallGraph, visible: VisibleGraph): string[] {\n const roots = rootGroups(graph);\n return [...new Set(visible.nodes.map((node) => node.group))].filter((group): group is string => group !== undefined && !roots.has(group));\n}\n\n/** \"10 columns\", \"2 fields\", \"3 variables\": how many members, in the words of their one kind, else \"members\". */\nfunction countWords(members: readonly CallGraphNode[], graph: CallGraph, vocabulary: CallGraphVocabulary): string {\n const [first] = members;\n const kind = first && members.every((member) => member.kind === first.kind) ? vocabulary.kindOf(graph, first) : \"member\";\n return `${members.length} ${kind}${members.length === 1 ? \"\" : \"s\"}`;\n}\n\n/** A merged edge's properties: the names of the members it stands for, gathered as columns, fields or members. */\nfunction memberProperties(members: readonly CallGraphNode[]): Record<string, string> {\n const keys: Record<string, string> = { column: \"columns\", field: \"fields\" };\n const names = new Map<string, string[]>();\n for (const member of members) {\n const key = keys[member.kind] ?? \"members\";\n names.set(key, [...(names.get(key) ?? []), member.label]);\n }\n return Object.fromEntries([...names].map(([key, list]) => [key, list.join(\", \")]));\n}\n\nfunction mergeEdges(id: string, sources: readonly CallGraphEdge[], standInOf: ReadonlyMap<string, string>, nodes: ReadonlyMap<string, CallGraphNode>): [CallGraphEdge, EdgeMerge] {\n const [first] = sources;\n if (!first) throw new Error(`call graph: merged edge \"${id}\" stands for no edge`);\n const memberIds = [...new Set(sources.flatMap((edge) => [edge.from, edge.to]).filter((end) => standInOf.has(end)))];\n const members = memberIds.map((member) => {\n const node = nodes.get(member);\n if (!node) throw new Error(`call graph: no node \"${member}\"`);\n return node;\n });\n const kind = sources.every((edge) => edge.kind === first.kind) ? first.kind : undefined;\n const edge: CallGraphEdge = {\n id, from: standInOf.get(first.from) ?? first.from, to: standInOf.get(first.to) ?? first.to, type: first.type,\n ...(kind !== undefined ? { kind } : {}),\n sites: distinctSites(sources.flatMap((source) => source.sites)),\n properties: memberProperties(members),\n };\n return [edge, { sources: [...sources], members }];\n}\n\n/** Edges with an end in a collapsed group, re-ended on its stand-in and merged per stand-in, other end and type. */\nfunction foldEdges(edges: readonly CallGraphEdge[], standInOf: ReadonlyMap<string, string>, nodes: ReadonlyMap<string, CallGraphNode>) {\n const kept: CallGraphEdge[] = [];\n const grouped = new Map<string, CallGraphEdge[]>();\n for (const edge of edges) {\n const from = standInOf.get(edge.from) ?? edge.from;\n const to = standInOf.get(edge.to) ?? edge.to;\n if (from === edge.from && to === edge.to) kept.push(edge);\n else grouped.set(`${from}|${to}|${edge.type}`, [...(grouped.get(`${from}|${to}|${edge.type}`) ?? []), edge]);\n }\n const merged = new Map([...grouped].map(([id, sources]) => mergeEdges(id, sources, standInOf, nodes)).map(([edge, merge]) => [edge.id, { edge, merge }]));\n return { edges: [...kept, ...[...merged.values()].map(({ edge }) => edge)], merged: new Map([...merged].map(([id, { merge }]) => [id, merge])) };\n}\n\n/** The node a collapsed group is drawn as: its owner's kind for a record, else its first member's, at the depth nearest the root. */\nfunction standInNode(id: string, fold: GroupFold, graph: CallGraph, records: ReadonlyMap<string, string>, edges: readonly CallGraphEdge[]): CallGraphNode {\n const [first, ...rest] = fold.members;\n if (!first) throw new Error(`call graph: collapsed group \"${fold.group}\" holds no node`);\n const nearest = rest.reduce((best, member) => (Math.abs(member.depth) < Math.abs(best.depth) ? member : best), first);\n return {\n id, identifier: {}, kind: records.get(fold.group) ?? first.kind,\n label: graph.groups?.find((group) => group.id === fold.group)?.label ?? fold.group,\n group: fold.group, depth: nearest.depth,\n in: edges.filter((edge) => edge.to === id).length, out: edges.filter((edge) => edge.from === id).length,\n };\n}\n\n/** The graph with each collapsed group's drawn members folded into one stand-in. */\nfunction foldGroups(graph: CallGraph, visible: VisibleGraph, collapsed: readonly string[], records: ReadonlyMap<string, string>): DrawnGraph {\n const roots = rootGroups(graph);\n const folds = new Map<string, GroupFold>();\n const standInOf = new Map<string, string>();\n for (const node of visible.nodes) {\n if (node.group === undefined || roots.has(node.group) || !collapsed.includes(node.group)) continue;\n const id = standInId(node.group);\n folds.set(id, { group: node.group, members: [...(folds.get(id)?.members ?? []), node] });\n standInOf.set(node.id, id);\n }\n if (folds.size === 0) return { graph, visible, folds, merged: new Map() };\n const { edges, merged } = foldEdges(graph.edges, standInOf, new Map(graph.nodes.map((node) => [node.id, node])));\n const standIns = [...folds].map(([id, fold]) => standInNode(id, fold, graph, records, edges));\n const nodes = [...visible.nodes.filter((node) => !standInOf.has(node.id)), ...standIns];\n const drawnIds = new Set(nodes.map((node) => node.id));\n return {\n graph: { ...graph, nodes: [...graph.nodes.filter((node) => !standInOf.has(node.id)), ...standIns], edges },\n visible: { nodes, edges: edges.filter((edge) => drawnIds.has(edge.from) && drawnIds.has(edge.to)) },\n folds,\n merged,\n };\n}\n\nfunction toDiagramGroup({ id, label }: CallGraphGroup, { glyphs, graph, vocabulary }: DiagramInput, drawn: DrawnGraph, records: ReadonlyMap<string, string>, collapsible: ReadonlySet<string> | undefined): DiagramGroup {\n const fold = drawn.folds.get(standInId(id));\n return {\n id, label: glyphs.group(groupCaption(label), records.get(id)), title: label,\n ...(records.has(id) ? { variant: \"record\" as const } : {}),\n ...(collapsible?.has(id) ? { collapsed: fold !== undefined } : {}),\n ...(fold ? { aside: countWords(fold.members, graph, vocabulary) } : {}),\n };\n}\n\nexport function toDiagram(input: DiagramInput): Diagram {\n const { graph, visible, options, vocabulary, collapsed } = input;\n const records = options.grouped ? recordGroups(visible, vocabulary) : new Map<string, string>();\n const drawn = options.grouped && collapsed ? foldGroups(graph, visible, collapsed, records) : { graph, visible, folds: new Map(), merged: new Map() };\n const collapsible = options.grouped && collapsed ? new Set(collapsibleGroups(graph, visible)) : undefined;\n const rank = groupRank(drawn.graph, vocabulary);\n return {\n nodes: [...drawn.visible.nodes].sort((a, b) => rank(a) - rank(b)).map((node) => toDiagramNode(node, input, drawn, records)),\n edges: drawn.visible.edges.map((edge) => toDiagramEdge(edge, input, drawn)),\n groups: options.grouped ? (graph.groups ?? []).map((group) => toDiagramGroup(group, input, drawn, records, collapsible)) : [],\n drawn,\n };\n}\n"],"names":["CALL_GRAPH_ACCESS","types","siteKey","rootGroups","mergeAccess","dataMemberAside","nodeTitle","edgeLabel","edgeTitle","isConditional","isDataMember","DATA_MEMBER_OWNER","edge","groupCaption"],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
|
+
import { DataAccess } from '../data-access.js';
|
|
2
3
|
import { GraphDiagramEdge, GraphDiagramGroup, GraphDiagramNode } from '../graph-diagram-model.js';
|
|
3
4
|
import { PillOptions } from './call-graph-labels.js';
|
|
4
5
|
import { CallGraphVocabulary } from './call-graph-vocabulary.js';
|
|
@@ -10,6 +11,8 @@ export declare const CALL_GRAPH_DEFAULT_DEPTH = 2;
|
|
|
10
11
|
export declare const DEFAULT_EDGE_LABELS: CallGraphEdgeLabels;
|
|
11
12
|
/** Turns one access type on or off, in the usual order. Turning the last one off fails: a graph follows something. */
|
|
12
13
|
export declare function toggleAccess(access: readonly CallGraphAccess[], type: CallGraphAccess): CallGraphAccess[];
|
|
14
|
+
/** The access types of `access` that are not variables, at least one of which a graph follows. */
|
|
15
|
+
export declare function baseAccess(access: readonly CallGraphAccess[]): CallGraphAccess[];
|
|
13
16
|
export interface GraphView {
|
|
14
17
|
direction: CallGraphDirection;
|
|
15
18
|
/** Nodes further than this many hops from the root are hidden. */
|
|
@@ -35,11 +38,14 @@ export type DiagramEdge = GraphDiagramEdge & {
|
|
|
35
38
|
};
|
|
36
39
|
export type DiagramGroup = GraphDiagramGroup & {
|
|
37
40
|
title: string;
|
|
41
|
+
aside?: string;
|
|
38
42
|
};
|
|
39
43
|
export interface Diagram {
|
|
40
44
|
nodes: DiagramNode[];
|
|
41
45
|
edges: DiagramEdge[];
|
|
42
46
|
groups: DiagramGroup[];
|
|
47
|
+
/** The graph as drawn, collapsed groups folded into their stand-ins: what a selection is looked up in. */
|
|
48
|
+
drawn: DrawnGraph;
|
|
43
49
|
}
|
|
44
50
|
/** Draws the glyphs the model chooses. The component supplies icons; the tests supply strings. */
|
|
45
51
|
export interface DiagramGlyphs {
|
|
@@ -47,7 +53,9 @@ export interface DiagramGlyphs {
|
|
|
47
53
|
node(glyph: string, words: string): ReactNode;
|
|
48
54
|
/** The pill icon of an edge type; a plain call has none. */
|
|
49
55
|
edge(type: CallGraphEdgeType): ReactNode | undefined;
|
|
50
|
-
group(caption: string): ReactNode;
|
|
56
|
+
group(caption: string, glyph?: string): ReactNode;
|
|
57
|
+
/** The mark of a node the reads and writes into it access; without it no node is marked. */
|
|
58
|
+
access?(access: DataAccess): ReactNode;
|
|
51
59
|
}
|
|
52
60
|
export interface DiagramInput {
|
|
53
61
|
graph: CallGraph;
|
|
@@ -57,6 +65,11 @@ export interface DiagramInput {
|
|
|
57
65
|
glyphs: DiagramGlyphs;
|
|
58
66
|
vocabulary: CallGraphVocabulary;
|
|
59
67
|
edgeLabels: CallGraphEdgeLabels;
|
|
68
|
+
/**
|
|
69
|
+
* The groups drawn as their header alone, by id: each folds into one stand-in node, and its members'
|
|
70
|
+
* edges merge onto it. The root's group never folds. Leave it out and no group can collapse.
|
|
71
|
+
*/
|
|
72
|
+
collapsed?: readonly string[];
|
|
60
73
|
}
|
|
61
74
|
export declare function requireNode(graph: CallGraph, id: string): CallGraphNode;
|
|
62
75
|
/** The nodes on the requested side within `depth`, plus revealed ones, and the edges between them. */
|
|
@@ -68,10 +81,10 @@ export declare function hiddenNeighbours(graph: CallGraph, visible: VisibleGraph
|
|
|
68
81
|
/**
|
|
69
82
|
* The `+N` on a node: how many more edges there are to load on its outer side. Only that side's count
|
|
70
83
|
* is a total (`out` for the root and callees, `in` for callers); the other equals the edges in the
|
|
71
|
-
* response. Excluded neighbours are in neither. From it come off the edges drawn
|
|
72
|
-
* source cannot be expanded, nor can the side the direction hides.
|
|
84
|
+
* response. Excluded neighbours are in neither. From it come off the edges drawn, a merged edge counting
|
|
85
|
+
* every edge it stands for. A node without a source cannot be expanded, nor can the side the direction hides.
|
|
73
86
|
*/
|
|
74
|
-
export declare function expandCount(graph: CallGraph, visible: VisibleGraph, nodeId: string, direction: CallGraphDirection, vocabulary: Pick<CallGraphVocabulary, "hasSource">): number;
|
|
87
|
+
export declare function expandCount(graph: CallGraph, visible: VisibleGraph, nodeId: string, direction: CallGraphDirection, vocabulary: Pick<CallGraphVocabulary, "hasSource">, merged?: ReadonlyMap<string, EdgeMerge>): number;
|
|
75
88
|
export interface NodeTotals {
|
|
76
89
|
callers?: number;
|
|
77
90
|
callees?: number;
|
|
@@ -98,5 +111,28 @@ export declare function columnGap({ nodes, edges, }: {
|
|
|
98
111
|
nodes: readonly Pick<DiagramNode, "id" | "level">[];
|
|
99
112
|
edges: readonly Pick<DiagramEdge, "id" | "from" | "to" | "label" | "icon">[];
|
|
100
113
|
}): number;
|
|
114
|
+
export declare function recordGroups(visible: VisibleGraph, vocabulary: CallGraphVocabulary): Map<string, string>;
|
|
115
|
+
/** A collapsed group's members, and the stand-in node drawn for them. */
|
|
116
|
+
export interface GroupFold {
|
|
117
|
+
group: string;
|
|
118
|
+
members: CallGraphNode[];
|
|
119
|
+
}
|
|
120
|
+
/** One edge drawn for the edges of several members: the edges it stands for and the members at their ends. */
|
|
121
|
+
export interface EdgeMerge {
|
|
122
|
+
sources: CallGraphEdge[];
|
|
123
|
+
members: CallGraphNode[];
|
|
124
|
+
}
|
|
125
|
+
export interface DrawnGraph {
|
|
126
|
+
graph: CallGraph;
|
|
127
|
+
visible: VisibleGraph;
|
|
128
|
+
/** By stand-in id. */
|
|
129
|
+
folds: ReadonlyMap<string, GroupFold>;
|
|
130
|
+
/** By the id of the edge drawn for them. */
|
|
131
|
+
merged: ReadonlyMap<string, EdgeMerge>;
|
|
132
|
+
}
|
|
133
|
+
/** The id of the node a collapsed group is drawn as. */
|
|
134
|
+
export declare function standInId(group: string): string;
|
|
135
|
+
/** The groups that hold a drawn node and can collapse: every one but the root's, in first-drawn order. */
|
|
136
|
+
export declare function collapsibleGroups(graph: CallGraph, visible: VisibleGraph): string[];
|
|
101
137
|
export declare function toDiagram(input: DiagramInput): Diagram;
|
|
102
138
|
//# sourceMappingURL=call-graph-model.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"call-graph-model.d.ts","sourceRoot":"","sources":["../../../src/data/call-graph/call-graph-model.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AACpG,OAAO,EAAqD,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAC1G,OAAO,
|
|
1
|
+
{"version":3,"file":"call-graph-model.d.ts","sourceRoot":"","sources":["../../../src/data/call-graph/call-graph-model.ts"],"names":[],"mappings":"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"}
|