codebase-onboarder 0.5.0 → 0.7.0
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/README.md +196 -47
- package/bin/build-if-source.js +23 -0
- package/cli/commands.d.ts +26 -0
- package/cli/commands.js +836 -811
- package/cli/commands.js.map +1 -0
- package/cli/explorer/advanced.d.ts +14 -0
- package/cli/explorer/advanced.js +449 -0
- package/cli/explorer/advanced.js.map +1 -0
- package/cli/explorer/app.d.ts +1 -0
- package/cli/explorer/app.js +396 -229
- package/cli/explorer/app.js.map +1 -0
- package/cli/explorer/assistant.d.ts +9 -0
- package/cli/explorer/assistant.js +58 -0
- package/cli/explorer/assistant.js.map +1 -0
- package/cli/explorer/commands.d.ts +17 -0
- package/cli/explorer/commands.js +400 -162
- package/cli/explorer/commands.js.map +1 -0
- package/cli/explorer/featureViews.d.ts +124 -0
- package/cli/explorer/featureViews.js +179 -0
- package/cli/explorer/featureViews.js.map +1 -0
- package/cli/explorer/github.d.ts +21 -0
- package/cli/explorer/github.js +73 -0
- package/cli/explorer/github.js.map +1 -0
- package/cli/explorer/graphs.d.ts +7 -0
- package/cli/explorer/graphs.js +173 -0
- package/cli/explorer/graphs.js.map +1 -0
- package/cli/explorer/picker.d.ts +22 -0
- package/cli/explorer/picker.js +150 -0
- package/cli/explorer/picker.js.map +1 -0
- package/cli/explorer/report.d.ts +85 -0
- package/cli/explorer/report.js +60 -0
- package/cli/explorer/report.js.map +1 -0
- package/cli/explorer/session.d.ts +449 -0
- package/cli/explorer/session.js +184 -95
- package/cli/explorer/session.js.map +1 -0
- package/cli/explorer/views.d.ts +19 -0
- package/cli/explorer/views.js +496 -412
- package/cli/explorer/views.js.map +1 -0
- package/cli/explorer/wrap.d.ts +1 -0
- package/cli/explorer/wrap.js +33 -0
- package/cli/explorer/wrap.js.map +1 -0
- package/cli/main.d.ts +1 -0
- package/cli/main.js +235 -138
- package/cli/main.js.map +1 -0
- package/cli/prompt.d.ts +5 -0
- package/cli/prompt.js +84 -80
- package/cli/prompt.js.map +1 -0
- package/cli/scanOptions.d.ts +2 -0
- package/cli/scanOptions.js +11 -0
- package/cli/scanOptions.js.map +1 -0
- package/cli/ui.d.ts +33 -0
- package/cli/ui.js +55 -35
- package/cli/ui.js.map +1 -0
- package/cli/wizard.d.ts +187 -0
- package/cli/wizard.js +304 -284
- package/cli/wizard.js.map +1 -0
- package/package.json +15 -4
- package/public/app.d.ts +1 -0
- package/public/app.js +1057 -1009
- package/public/app.js.map +1 -0
- package/public/browser.d.ts +68 -0
- package/public/browser.js +2 -0
- package/public/browser.js.map +1 -0
- package/public/index.html +30 -13
- package/public/js/about.d.ts +6 -0
- package/public/js/about.js +165 -172
- package/public/js/about.js.map +1 -0
- package/public/js/aiDraft.d.ts +3 -0
- package/public/js/aiDraft.js +116 -124
- package/public/js/aiDraft.js.map +1 -0
- package/public/js/analysisPanel.d.ts +7 -0
- package/public/js/analysisPanel.js +166 -166
- package/public/js/analysisPanel.js.map +1 -0
- package/public/js/analysisReport.d.ts +38 -0
- package/public/js/analysisReport.js +105 -110
- package/public/js/analysisReport.js.map +1 -0
- package/public/js/api.d.ts +26 -0
- package/public/js/api.js +176 -167
- package/public/js/api.js.map +1 -0
- package/public/js/atlas.d.ts +6 -0
- package/public/js/atlas.js +50 -58
- package/public/js/atlas.js.map +1 -0
- package/public/js/blameView.d.ts +2 -0
- package/public/js/blameView.js +36 -37
- package/public/js/blameView.js.map +1 -0
- package/public/js/codeTab.d.ts +3 -0
- package/public/js/codeTab.js +175 -180
- package/public/js/codeTab.js.map +1 -0
- package/public/js/codeViewer.d.ts +5 -0
- package/public/js/codeViewer.js +162 -150
- package/public/js/codeViewer.js.map +1 -0
- package/public/js/components/FileChip.d.ts +9 -0
- package/public/js/components/FileChip.js +45 -49
- package/public/js/components/FileChip.js.map +1 -0
- package/public/js/components/MetricSparkline.d.ts +7 -0
- package/public/js/components/MetricSparkline.js +35 -44
- package/public/js/components/MetricSparkline.js.map +1 -0
- package/public/js/components/RiskBadge.d.ts +9 -0
- package/public/js/components/RiskBadge.js +55 -63
- package/public/js/components/RiskBadge.js.map +1 -0
- package/public/js/deepAnalysisView.d.ts +99 -0
- package/public/js/deepAnalysisView.js +282 -302
- package/public/js/deepAnalysisView.js.map +1 -0
- package/public/js/diagramPane.d.ts +8 -0
- package/public/js/diagramPane.js +133 -135
- package/public/js/diagramPane.js.map +1 -0
- package/public/js/diffView.d.ts +6 -0
- package/public/js/diffView.js +222 -209
- package/public/js/diffView.js.map +1 -0
- package/public/js/docsView.d.ts +2 -0
- package/public/js/docsView.js +441 -442
- package/public/js/docsView.js.map +1 -0
- package/public/js/dom.d.ts +189 -0
- package/public/js/dom.js +5 -0
- package/public/js/dom.js.map +1 -0
- package/public/js/fileSourceBrowser.d.ts +5 -0
- package/public/js/fileSourceBrowser.js +33 -41
- package/public/js/fileSourceBrowser.js.map +1 -0
- package/public/js/flameGraph.d.ts +5 -0
- package/public/js/flameGraph.js +62 -72
- package/public/js/flameGraph.js.map +1 -0
- package/public/js/forceGraph.d.ts +10 -0
- package/public/js/forceGraph.js +581 -556
- package/public/js/forceGraph.js.map +1 -0
- package/public/js/heatmap.d.ts +4 -0
- package/public/js/heatmap.js +142 -164
- package/public/js/heatmap.js.map +1 -0
- package/public/js/highlight.d.ts +2 -0
- package/public/js/highlight.js +116 -107
- package/public/js/highlight.js.map +1 -0
- package/public/js/html.d.ts +2 -0
- package/public/js/html.js +14 -44
- package/public/js/html.js.map +1 -0
- package/public/js/insightsView.d.ts +5 -0
- package/public/js/insightsView.js +93 -111
- package/public/js/insightsView.js.map +1 -0
- package/public/js/inspector.d.ts +37 -0
- package/public/js/inspector.js +416 -445
- package/public/js/inspector.js.map +1 -0
- package/public/js/llm.d.ts +113 -0
- package/public/js/llm.js +233 -272
- package/public/js/llm.js.map +1 -0
- package/public/js/mapView.d.ts +3 -0
- package/public/js/mapView.js +121 -120
- package/public/js/mapView.js.map +1 -0
- package/public/js/markdown.d.ts +3 -0
- package/public/js/markdown.js +84 -91
- package/public/js/markdown.js.map +1 -0
- package/public/js/mindmap.d.ts +32 -0
- package/public/js/mindmap.js +244 -259
- package/public/js/mindmap.js.map +1 -0
- package/public/js/mobilePanels.d.ts +5 -0
- package/public/js/mobilePanels.js +50 -0
- package/public/js/mobilePanels.js.map +1 -0
- package/public/js/repoFiles.d.ts +12 -0
- package/public/js/repoFiles.js +28 -27
- package/public/js/repoFiles.js.map +1 -0
- package/public/js/reviewView.d.ts +28 -0
- package/public/js/reviewView.js +256 -0
- package/public/js/reviewView.js.map +1 -0
- package/public/js/sbomView.d.ts +3 -0
- package/public/js/sbomView.js +59 -67
- package/public/js/sbomView.js.map +1 -0
- package/public/js/scanCache.d.ts +16 -0
- package/public/js/scanCache.js +67 -65
- package/public/js/scanCache.js.map +1 -0
- package/public/js/search.d.ts +7 -0
- package/public/js/search.js +868 -800
- package/public/js/search.js.map +1 -0
- package/public/js/searchLocal.d.ts +42 -0
- package/public/js/searchLocal.js +87 -0
- package/public/js/searchLocal.js.map +1 -0
- package/public/js/serverSettings.d.ts +5 -0
- package/public/js/serverSettings.js +153 -164
- package/public/js/serverSettings.js.map +1 -0
- package/public/js/state.d.ts +798 -0
- package/public/js/state.js +114 -122
- package/public/js/state.js.map +1 -0
- package/public/js/tour.d.ts +6 -0
- package/public/js/tour.js +5 -7
- package/public/js/tour.js.map +1 -0
- package/public/js/transitions.d.ts +2 -0
- package/public/js/transitions.js +9 -10
- package/public/js/transitions.js.map +1 -0
- package/public/js/tree.d.ts +12 -0
- package/public/js/tree.js +157 -154
- package/public/js/tree.js.map +1 -0
- package/public/js/workflowsView.d.ts +3 -0
- package/public/js/workflowsView.js +15 -22
- package/public/js/workflowsView.js.map +1 -0
- package/public/search.css +495 -0
- package/public/styles.css +163 -346
- package/public/workbench.css +166 -0
- package/server/apiAuth.d.ts +3 -0
- package/server/apiAuth.js +18 -20
- package/server/apiAuth.js.map +1 -0
- package/server/apiDiff.d.ts +2 -0
- package/server/apiDiff.js +20 -18
- package/server/apiDiff.js.map +1 -0
- package/server/apiDocs.d.ts +2 -0
- package/server/apiDocs.js +38 -40
- package/server/apiDocs.js.map +1 -0
- package/server/apiFile.d.ts +1 -0
- package/server/apiFile.js +14 -17
- package/server/apiFile.js.map +1 -0
- package/server/apiGitBlame.d.ts +2 -0
- package/server/apiGitBlame.js +50 -51
- package/server/apiGitBlame.js.map +1 -0
- package/server/apiMcp.d.ts +4 -0
- package/server/apiMcp.js +64 -66
- package/server/apiMcp.js.map +1 -0
- package/server/apiReview.d.ts +2 -0
- package/server/apiReview.js +45 -0
- package/server/apiReview.js.map +1 -0
- package/server/apiScan.d.ts +5 -0
- package/server/apiScan.js +90 -71
- package/server/apiScan.js.map +1 -0
- package/server/apiSearch.d.ts +33 -0
- package/server/apiSearch.js +184 -200
- package/server/apiSearch.js.map +1 -0
- package/server/apiSettings.d.ts +4 -0
- package/server/apiSettings.js +84 -85
- package/server/apiSettings.js.map +1 -0
- package/server/apiTools.d.ts +3 -0
- package/server/apiTools.js +55 -56
- package/server/apiTools.js.map +1 -0
- package/server/auth.d.ts +5 -0
- package/server/auth.js +54 -51
- package/server/auth.js.map +1 -0
- package/server/config.d.ts +42 -0
- package/server/config.js +189 -194
- package/server/config.js.map +1 -0
- package/server/daemon.d.ts +12 -0
- package/server/daemon.js +124 -114
- package/server/daemon.js.map +1 -0
- package/server/fileSourceNode.d.ts +2 -0
- package/server/fileSourceNode.js +34 -36
- package/server/fileSourceNode.js.map +1 -0
- package/server/gitClone.d.ts +9 -0
- package/server/gitClone.js +59 -61
- package/server/gitClone.js.map +1 -0
- package/server/gitDiff.d.ts +36 -0
- package/server/gitDiff.js +271 -169
- package/server/gitDiff.js.map +1 -0
- package/server/gitHistory.d.ts +12 -0
- package/server/gitHistory.js +80 -80
- package/server/gitHistory.js.map +1 -0
- package/server/gitRemote.d.ts +12 -0
- package/server/gitRemote.js +60 -0
- package/server/gitRemote.js.map +1 -0
- package/server/htmlText.d.ts +4 -0
- package/server/htmlText.js +16 -23
- package/server/htmlText.js.map +1 -0
- package/server/http.d.ts +5 -0
- package/server/http.js +27 -30
- package/server/http.js.map +1 -0
- package/server/httpGuards.d.ts +2 -0
- package/server/httpGuards.js +47 -43
- package/server/httpGuards.js.map +1 -0
- package/server/https.d.ts +34 -0
- package/server/https.js +121 -111
- package/server/https.js.map +1 -0
- package/server/index.d.ts +40 -0
- package/server/index.js +139 -147
- package/server/index.js.map +1 -0
- package/server/layout.d.ts +26 -0
- package/server/layout.js +59 -37
- package/server/layout.js.map +1 -0
- package/server/llmProxy.d.ts +3 -0
- package/server/llmProxy.js +137 -135
- package/server/llmProxy.js.map +1 -0
- package/server/logger.d.ts +38 -0
- package/server/logger.js +198 -211
- package/server/logger.js.map +1 -0
- package/server/mcp/analysis.d.ts +29 -0
- package/server/mcp/analysis.js +99 -120
- package/server/mcp/analysis.js.map +1 -0
- package/server/mcp/http.d.ts +9 -0
- package/server/mcp/http.js +128 -137
- package/server/mcp/http.js.map +1 -0
- package/server/mcp/runner.d.ts +68 -0
- package/server/mcp/runner.js +208 -218
- package/server/mcp/runner.js.map +1 -0
- package/server/mcp/server.d.ts +29 -0
- package/server/mcp/server.js +166 -179
- package/server/mcp/server.js.map +1 -0
- package/server/mcp/standalone.d.ts +1 -0
- package/server/mcp/standalone.js +8 -10
- package/server/mcp/standalone.js.map +1 -0
- package/server/mcp/tools.d.ts +2020 -0
- package/server/mcp/tools.js +523 -574
- package/server/mcp/tools.js.map +1 -0
- package/server/paths.d.ts +3 -0
- package/server/paths.js +17 -15
- package/server/paths.js.map +1 -0
- package/server/pidfile.d.ts +9 -0
- package/server/pidfile.js +43 -45
- package/server/pidfile.js.map +1 -0
- package/server/review.d.ts +5 -0
- package/server/review.js +35 -0
- package/server/review.js.map +1 -0
- package/server/router.d.ts +33 -0
- package/server/router.js +191 -197
- package/server/router.js.map +1 -0
- package/server/scanRequest.d.ts +3 -0
- package/server/scanRequest.js +36 -0
- package/server/scanRequest.js.map +1 -0
- package/server/searchIndex.d.ts +17 -0
- package/server/searchIndex.js +83 -80
- package/server/searchIndex.js.map +1 -0
- package/server/sessions.d.ts +14 -0
- package/server/sessions.js +62 -70
- package/server/sessions.js.map +1 -0
- package/server/startup.d.ts +118 -0
- package/server/startup.js +143 -148
- package/server/startup.js.map +1 -0
- package/server/static.d.ts +6 -0
- package/server/static.js +28 -31
- package/server/static.js.map +1 -0
- package/server/tools/install.d.ts +4 -0
- package/server/tools/install.js +176 -185
- package/server/tools/install.js.map +1 -0
- package/server/tools/parse.d.ts +8 -0
- package/server/tools/parse.js +112 -114
- package/server/tools/parse.js.map +1 -0
- package/server/tools/platform.d.ts +9 -0
- package/server/tools/platform.js +49 -47
- package/server/tools/platform.js.map +1 -0
- package/server/tools/registry.d.ts +137 -0
- package/server/tools/registry.js +173 -172
- package/server/tools/registry.js.map +1 -0
- package/server/tools/scan.d.ts +34 -0
- package/server/tools/scan.js +89 -98
- package/server/tools/scan.js.map +1 -0
- package/server/tools.d.ts +34 -0
- package/server/tools.js +94 -107
- package/server/tools.js.map +1 -0
- package/server/tunnel.d.ts +29 -0
- package/server/tunnel.js +61 -66
- package/server/tunnel.js.map +1 -0
- package/shared/analyzer/docs.d.ts +16 -0
- package/shared/analyzer/docs.js +99 -93
- package/shared/analyzer/docs.js.map +1 -0
- package/shared/analyzer/explainLocal.d.ts +4 -0
- package/shared/analyzer/explainLocal.js +122 -142
- package/shared/analyzer/explainLocal.js.map +1 -0
- package/shared/analyzer/github.d.ts +37 -0
- package/shared/analyzer/github.js +79 -0
- package/shared/analyzer/github.js.map +1 -0
- package/shared/analyzer/graph.d.ts +41 -0
- package/shared/analyzer/graph.js +393 -400
- package/shared/analyzer/graph.js.map +1 -0
- package/shared/analyzer/health.d.ts +33 -0
- package/shared/analyzer/health.js +197 -193
- package/shared/analyzer/health.js.map +1 -0
- package/shared/analyzer/history.d.ts +29 -0
- package/shared/analyzer/history.js +110 -111
- package/shared/analyzer/history.js.map +1 -0
- package/shared/analyzer/jsonConfig.d.ts +2 -0
- package/shared/analyzer/jsonConfig.js +61 -0
- package/shared/analyzer/jsonConfig.js.map +1 -0
- package/shared/analyzer/languages/csharp.d.ts +26 -0
- package/shared/analyzer/languages/csharp.js +83 -88
- package/shared/analyzer/languages/csharp.js.map +1 -0
- package/shared/analyzer/languages/generic.d.ts +23 -0
- package/shared/analyzer/languages/generic.js +94 -105
- package/shared/analyzer/languages/generic.js.map +1 -0
- package/shared/analyzer/languages/go.d.ts +24 -0
- package/shared/analyzer/languages/go.js +45 -54
- package/shared/analyzer/languages/go.js.map +1 -0
- package/shared/analyzer/languages/index.d.ts +6 -0
- package/shared/analyzer/languages/index.js +19 -20
- package/shared/analyzer/languages/index.js.map +1 -0
- package/shared/analyzer/languages/java.d.ts +20 -0
- package/shared/analyzer/languages/java.js +73 -78
- package/shared/analyzer/languages/java.js.map +1 -0
- package/shared/analyzer/languages/javascript.d.ts +12 -0
- package/shared/analyzer/languages/javascript.js +258 -209
- package/shared/analyzer/languages/javascript.js.map +1 -0
- package/shared/analyzer/languages/python.d.ts +23 -0
- package/shared/analyzer/languages/python.js +92 -100
- package/shared/analyzer/languages/python.js.map +1 -0
- package/shared/analyzer/languages/rust.d.ts +17 -0
- package/shared/analyzer/languages/rust.js +96 -98
- package/shared/analyzer/languages/rust.js.map +1 -0
- package/shared/analyzer/languages/typescript.d.ts +11 -0
- package/shared/analyzer/languages/typescript.js +117 -116
- package/shared/analyzer/languages/typescript.js.map +1 -0
- package/shared/analyzer/licenses.d.ts +18 -0
- package/shared/analyzer/licenses.js +130 -133
- package/shared/analyzer/licenses.js.map +1 -0
- package/shared/analyzer/metrics.d.ts +20 -0
- package/shared/analyzer/metrics.js +112 -104
- package/shared/analyzer/metrics.js.map +1 -0
- package/shared/analyzer/pathUtil.d.ts +10 -0
- package/shared/analyzer/pathUtil.js +29 -35
- package/shared/analyzer/pathUtil.js.map +1 -0
- package/shared/analyzer/patterns.d.ts +11 -0
- package/shared/analyzer/patterns.js +231 -253
- package/shared/analyzer/patterns.js.map +1 -0
- package/shared/analyzer/scan.d.ts +62 -0
- package/shared/analyzer/scan.js +451 -442
- package/shared/analyzer/scan.js.map +1 -0
- package/shared/analyzer/scanControl.d.ts +11 -0
- package/shared/analyzer/scanControl.js +62 -0
- package/shared/analyzer/scanControl.js.map +1 -0
- package/shared/analyzer/security.d.ts +18 -0
- package/shared/analyzer/security.js +159 -159
- package/shared/analyzer/security.js.map +1 -0
- package/shared/analyzer/services.d.ts +5 -0
- package/shared/analyzer/services.js +141 -138
- package/shared/analyzer/services.js.map +1 -0
- package/shared/analyzer/stack.d.ts +6 -0
- package/shared/analyzer/stack.js +134 -141
- package/shared/analyzer/stack.js.map +1 -0
- package/shared/analyzer/tour.d.ts +2 -0
- package/shared/analyzer/tour.js +45 -53
- package/shared/analyzer/tour.js.map +1 -0
- package/shared/analyzer/util.d.ts +8 -0
- package/shared/analyzer/util.js +130 -76
- package/shared/analyzer/util.js.map +1 -0
- package/shared/analyzer/workflows.d.ts +8 -0
- package/shared/analyzer/workflows.js +139 -134
- package/shared/analyzer/workflows.js.map +1 -0
- package/shared/contracts.d.ts +250 -0
- package/shared/contracts.js +2 -0
- package/shared/contracts.js.map +1 -0
- package/shared/diagram/aiFacts.d.ts +35 -0
- package/shared/diagram/aiFacts.js +102 -105
- package/shared/diagram/aiFacts.js.map +1 -0
- package/shared/diagram/aiMermaid.d.ts +5 -0
- package/shared/diagram/aiMermaid.js +46 -45
- package/shared/diagram/aiMermaid.js.map +1 -0
- package/shared/diagram/atlas.d.ts +16 -0
- package/shared/diagram/atlas.js +51 -60
- package/shared/diagram/atlas.js.map +1 -0
- package/shared/diagram/mermaid.d.ts +43 -0
- package/shared/diagram/mermaid.js +348 -370
- package/shared/diagram/mermaid.js.map +1 -0
- package/shared/review/contracts.d.ts +95 -0
- package/shared/review/contracts.js +2 -0
- package/shared/review/contracts.js.map +1 -0
- package/shared/review/review.d.ts +10 -0
- package/shared/review/review.js +184 -0
- package/shared/review/review.js.map +1 -0
- package/shared/search/query.d.ts +32 -0
- package/shared/search/query.js +395 -388
- package/shared/search/query.js.map +1 -0
package/public/js/blameView.js
CHANGED
|
@@ -1,41 +1,40 @@
|
|
|
1
1
|
export function initBlameView(container) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
container.appendChild(div);
|
|
28
|
-
});
|
|
29
|
-
};
|
|
2
|
+
return function renderBlame(blameData, options = {}) {
|
|
3
|
+
if (!blameData || !blameData.lines) {
|
|
4
|
+
container.hidden = true;
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
container.hidden = false;
|
|
8
|
+
container.innerHTML = '';
|
|
9
|
+
// Hash author to color
|
|
10
|
+
function getAuthorColor(author) {
|
|
11
|
+
let hash = 0;
|
|
12
|
+
for (let i = 0; i < author.length; i++)
|
|
13
|
+
hash = author.charCodeAt(i) + ((hash << 5) - hash);
|
|
14
|
+
return `hsl(${Math.abs(hash) % 360}, 60%, 50%)`;
|
|
15
|
+
}
|
|
16
|
+
blameData.lines.forEach(line => {
|
|
17
|
+
const div = document.createElement('div');
|
|
18
|
+
div.className = 'blame-line';
|
|
19
|
+
div.style.backgroundColor = getAuthorColor(line.author || 'Unknown');
|
|
20
|
+
const tooltip = document.createElement('div');
|
|
21
|
+
tooltip.className = 'blame-tooltip';
|
|
22
|
+
tooltip.textContent = `${line.author} - ${line.date || ''} (${(line.sha || '').substring(0, 7)})`;
|
|
23
|
+
div.appendChild(tooltip);
|
|
24
|
+
container.appendChild(div);
|
|
25
|
+
});
|
|
26
|
+
};
|
|
30
27
|
}
|
|
31
|
-
|
|
32
28
|
export async function fetchBlame(scanId, path) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
29
|
+
try {
|
|
30
|
+
const res = await fetch(`/api/blame?scan=${encodeURIComponent(scanId)}&path=${encodeURIComponent(path)}`);
|
|
31
|
+
if (!res.ok)
|
|
32
|
+
return null;
|
|
33
|
+
return await res.json();
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
console.error('Failed to fetch blame:', err);
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
41
39
|
}
|
|
40
|
+
//# sourceMappingURL=blameView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blameView.js","sourceRoot":"","sources":["../../src/public/js/blameView.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,aAAa,CAAC,SAAS;IACrC,OAAO,SAAS,WAAW,CAAC,SAAS,EAAE,OAAO,GAAwB,EAAE;QACtE,IAAI,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;YACnC,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC;YACxB,OAAO;QACT,CAAC;QACD,SAAS,CAAC,MAAM,GAAG,KAAK,CAAC;QACzB,SAAS,CAAC,SAAS,GAAG,EAAE,CAAC;QAEzB,uBAAuB;QACvB,SAAS,cAAc,CAAC,MAAM;YAC5B,IAAI,IAAI,GAAG,CAAC,CAAC;YACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE;gBAAE,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;YAC3F,OAAO,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,aAAa,CAAC;QAClD,CAAC;QAED,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;YAC7B,MAAM,GAAG,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAC1C,GAAG,CAAC,SAAS,GAAG,YAAY,CAAC;YAC7B,GAAG,CAAC,KAAK,CAAC,eAAe,GAAG,cAAc,CAAC,IAAI,CAAC,MAAM,IAAI,SAAS,CAAC,CAAC;YAErE,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAC9C,OAAO,CAAC,SAAS,GAAG,eAAe,CAAC;YACpC,OAAO,CAAC,WAAW,GAAG,GAAG,IAAI,CAAC,MAAM,MAAM,IAAI,CAAC,IAAI,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC;YAElG,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;YACzB,SAAS,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,MAAM,EAAE,IAAI;IAC3C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,mBAAmB,kBAAkB,CAAC,MAAM,CAAC,SAAS,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC1G,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QACzB,OAAO,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAC1B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,GAAG,CAAC,CAAC;QAC7C,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC","sourcesContent":["export function initBlameView(container) {\n return function renderBlame(blameData, options: Record<string, any> = {}) {\n if (!blameData || !blameData.lines) {\n container.hidden = true;\n return;\n }\n container.hidden = false;\n container.innerHTML = '';\n \n // Hash author to color\n function getAuthorColor(author) {\n let hash = 0;\n for (let i = 0; i < author.length; i++) hash = author.charCodeAt(i) + ((hash << 5) - hash);\n return `hsl(${Math.abs(hash) % 360}, 60%, 50%)`;\n }\n\n blameData.lines.forEach(line => {\n const div = document.createElement('div');\n div.className = 'blame-line';\n div.style.backgroundColor = getAuthorColor(line.author || 'Unknown');\n \n const tooltip = document.createElement('div');\n tooltip.className = 'blame-tooltip';\n tooltip.textContent = `${line.author} - ${line.date || ''} (${(line.sha || '').substring(0, 7)})`;\n \n div.appendChild(tooltip);\n container.appendChild(div);\n });\n };\n}\n\nexport async function fetchBlame(scanId, path) {\n try {\n const res = await fetch(`/api/blame?scan=${encodeURIComponent(scanId)}&path=${encodeURIComponent(path)}`);\n if (!res.ok) return null;\n return await res.json();\n } catch (err) {\n console.error('Failed to fetch blame:', err);\n return null;\n }\n}\n"]}
|
package/public/js/codeTab.js
CHANGED
|
@@ -8,210 +8,205 @@
|
|
|
8
8
|
//
|
|
9
9
|
// The back/forward stack and the "which file should I show" decision live in
|
|
10
10
|
// state.js, where they are pure and tested. What is left here is DOM.
|
|
11
|
-
|
|
12
11
|
import { roleOf } from '/shared/analyzer/graph.js';
|
|
13
12
|
import { escapeHtml } from './html.js';
|
|
14
13
|
import { highlightCode, langOf } from './highlight.js';
|
|
15
14
|
import { initViewer, showInViewer, monacoLangOf, revealLineInViewer } from './codeViewer.js';
|
|
16
15
|
import { fetchBlame, initBlameView } from './blameView.js';
|
|
17
|
-
import {
|
|
18
|
-
state, focusFile, defaultCodePath, pushCodeHistory, codeHistoryTarget,
|
|
19
|
-
} from './state.js';
|
|
16
|
+
import { state, focusFile, defaultCodePath, pushCodeHistory, codeHistoryTarget, } from './state.js';
|
|
20
17
|
import { readRepoFile } from './repoFiles.js';
|
|
21
|
-
|
|
22
18
|
const MAX_FALLBACK_LINES = 3000;
|
|
23
|
-
|
|
24
19
|
let host = null;
|
|
25
20
|
let renderBlameGutter = null;
|
|
26
21
|
let hooks = {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
22
|
+
onDeepDive: (_path) => { },
|
|
23
|
+
onSyncInspector: (..._args) => { },
|
|
24
|
+
onRenderSidebar: (..._args) => { },
|
|
25
|
+
onOpenFile: (..._args) => { },
|
|
26
|
+
onToast: (..._args) => { },
|
|
27
|
+
getTheme: () => 'light',
|
|
28
|
+
blameGutter: null,
|
|
33
29
|
};
|
|
34
|
-
|
|
35
|
-
let codeSeq = 0; // render generations — a slow read never overwrites a newer one
|
|
30
|
+
let codeSeq = 0; // render generations — a slow read never overwrites a newer one
|
|
36
31
|
let viewerFailed = false; // Monaco failed to load → hand-rolled fallback
|
|
37
32
|
let pendingReveal = null; // a line a search result asked for, waiting for its file
|
|
38
|
-
|
|
39
33
|
// A search result knows which line it matched. The reveal has to wait until the
|
|
40
34
|
// text is on screen, and it must not leak onto the *next* file you open — which
|
|
41
35
|
// is why it is taken once, at the top of `renderCode`, rather than living in
|
|
42
36
|
// `state` where it would outlive the file it was meant for.
|
|
43
37
|
export function revealLineInCode(line) {
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
const target = Math.floor(Number(line));
|
|
39
|
+
pendingReveal = Number.isFinite(target) && target > 0 ? target : null;
|
|
46
40
|
}
|
|
47
|
-
|
|
48
41
|
// Monaco is the real answer; without it, the fallback is a single scrolling
|
|
49
42
|
// `<pre>`, so the best we can do is put the line near the top. Approximate, and
|
|
50
43
|
// honest about being approximate — the file is still the right file.
|
|
51
44
|
function applyReveal(alt, line) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
45
|
+
if (!line)
|
|
46
|
+
return;
|
|
47
|
+
if (!viewerFailed) {
|
|
48
|
+
revealLineInViewer(line);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const shell = alt.querySelector('.code-shell');
|
|
52
|
+
if (!shell)
|
|
53
|
+
return;
|
|
54
|
+
const gutter = shell.querySelector('.code-gutter');
|
|
55
|
+
const total = gutter ? (gutter.textContent || '').split('\n').length : 0;
|
|
56
|
+
if (!total)
|
|
57
|
+
return;
|
|
58
|
+
const perLine = shell.scrollHeight / total;
|
|
59
|
+
shell.scrollTop = Math.max(0, (line - 2) * perLine);
|
|
64
60
|
}
|
|
65
|
-
|
|
66
61
|
export function initCodeTab(options) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
host.addEventListener('click', (event) => {
|
|
74
|
-
const b = event.target.closest('button');
|
|
75
|
-
if (!b) return;
|
|
76
|
-
if (b.dataset.codeopen) return openCodeFile(b.dataset.codeopen);
|
|
77
|
-
if (b.dataset.codenav) return codeNav(Number(b.dataset.codenav));
|
|
78
|
-
if (b.dataset.codedive !== undefined) return (hooks.onDeepDive || hooks.onOpenFile)(state.code.path); // empty attribute is falsy — test undefined
|
|
79
|
-
if (b.dataset.codeblame !== undefined) {
|
|
80
|
-
if (!hooks.blameGutter) return;
|
|
81
|
-
if (!hooks.blameGutter.hidden) {
|
|
82
|
-
hooks.blameGutter.hidden = true;
|
|
83
|
-
b.classList.remove('is-active');
|
|
84
|
-
} else {
|
|
85
|
-
hooks.onToast('Fetching git blame...');
|
|
86
|
-
fetchBlame(state.scanId, state.code.path).then((data) => {
|
|
87
|
-
if (data && data.lines && data.lines.length) {
|
|
88
|
-
renderBlameGutter(data);
|
|
89
|
-
hooks.blameGutter.hidden = false;
|
|
90
|
-
b.classList.add('is-active');
|
|
91
|
-
hooks.onToast(`Blame loaded for ${data.lines.length} lines`);
|
|
92
|
-
} else {
|
|
93
|
-
hooks.onToast(data?.reason || 'No blame available for this file.');
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
if (b.dataset.codecopy !== undefined) {
|
|
100
|
-
const text = state.code.cache[state.code.path];
|
|
101
|
-
if (text !== undefined) {
|
|
102
|
-
navigator.clipboard.writeText(text)
|
|
103
|
-
.then(() => hooks.onToast('Copied to the clipboard.'))
|
|
104
|
-
.catch(() => hooks.onToast('Could not copy to the clipboard.'));
|
|
105
|
-
}
|
|
62
|
+
host = options.host;
|
|
63
|
+
hooks = { ...hooks, ...options };
|
|
64
|
+
if (options.blameGutter) {
|
|
65
|
+
renderBlameGutter = initBlameView(options.blameGutter);
|
|
106
66
|
}
|
|
107
|
-
|
|
67
|
+
host.addEventListener('click', (event) => {
|
|
68
|
+
const b = event.target.closest('button');
|
|
69
|
+
if (!b)
|
|
70
|
+
return;
|
|
71
|
+
if (b.dataset.codeopen)
|
|
72
|
+
return openCodeFile(b.dataset.codeopen);
|
|
73
|
+
if (b.dataset.codenav)
|
|
74
|
+
return codeNav(Number(b.dataset.codenav));
|
|
75
|
+
if (b.dataset.codedive !== undefined)
|
|
76
|
+
return (hooks.onDeepDive || hooks.onOpenFile)(state.code.path); // empty attribute is falsy — test undefined
|
|
77
|
+
if (b.dataset.codeblame !== undefined) {
|
|
78
|
+
if (!hooks.blameGutter)
|
|
79
|
+
return;
|
|
80
|
+
if (!hooks.blameGutter.hidden) {
|
|
81
|
+
hooks.blameGutter.hidden = true;
|
|
82
|
+
b.classList.remove('is-active');
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
hooks.onToast('Fetching git blame...');
|
|
86
|
+
fetchBlame(state.scanId, state.code.path).then((data) => {
|
|
87
|
+
if (data && data.lines && data.lines.length) {
|
|
88
|
+
renderBlameGutter(data);
|
|
89
|
+
hooks.blameGutter.hidden = false;
|
|
90
|
+
b.classList.add('is-active');
|
|
91
|
+
hooks.onToast(`Blame loaded for ${data.lines.length} lines`);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
hooks.onToast(data?.reason || 'No blame available for this file.');
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (b.dataset.codecopy !== undefined) {
|
|
101
|
+
const text = state.code.cache[state.code.path];
|
|
102
|
+
if (text !== undefined) {
|
|
103
|
+
navigator.clipboard.writeText(text)
|
|
104
|
+
.then(() => hooks.onToast('Copied to the clipboard.'))
|
|
105
|
+
.catch(() => hooks.onToast('Could not copy to the clipboard.'));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
});
|
|
108
109
|
}
|
|
109
|
-
|
|
110
110
|
// In-tab navigation (the import chips) keeps the sidebar and inspector in step,
|
|
111
111
|
// so the rest of the app follows along rather than pointing at the old file.
|
|
112
112
|
function openCodeFile(path) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
113
|
+
state.code.path = path;
|
|
114
|
+
focusFile(path);
|
|
115
|
+
hooks.onSyncInspector();
|
|
116
|
+
hooks.onRenderSidebar();
|
|
117
|
+
renderCode();
|
|
118
118
|
}
|
|
119
|
-
|
|
120
119
|
function codeNav(delta) {
|
|
121
|
-
|
|
122
|
-
|
|
120
|
+
const path = codeHistoryTarget(delta);
|
|
121
|
+
if (path)
|
|
122
|
+
openCodeFile(path);
|
|
123
123
|
}
|
|
124
|
-
|
|
125
124
|
export async function renderCode() {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
host.innerHTML = `<div class="code-page">
|
|
125
|
+
const seq = ++codeSeq;
|
|
126
|
+
const path = defaultCodePath();
|
|
127
|
+
// Taken once and cleared, so a reveal belongs only to the render that followed
|
|
128
|
+
// the request for it — never to the next file you happen to open.
|
|
129
|
+
const revealLine = pendingReveal;
|
|
130
|
+
pendingReveal = null;
|
|
131
|
+
if (!path) {
|
|
132
|
+
host.innerHTML = '<div class="code-empty">Nothing to preview — this repo has no readable files.</div>';
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
state.code.path = path;
|
|
136
|
+
pushCodeHistory(path);
|
|
137
|
+
// The shell is built once: the Monaco container must persist across file
|
|
138
|
+
// switches, or the editor instance would be destroyed on every render.
|
|
139
|
+
if (!host.querySelector('.code-page')) {
|
|
140
|
+
host.innerHTML = `<div class="code-page">
|
|
143
141
|
<div class="code-head" id="codeHead"></div>
|
|
144
142
|
<div id="codeLinks"></div>
|
|
145
143
|
<div class="code-monaco" id="codeMonaco" hidden></div>
|
|
146
144
|
<div id="codeAlt"></div>
|
|
147
145
|
</div>`;
|
|
148
|
-
}
|
|
149
|
-
const headEl = host.querySelector('#codeHead');
|
|
150
|
-
const linksEl = host.querySelector('#codeLinks');
|
|
151
|
-
const monacoEl = host.querySelector('#codeMonaco');
|
|
152
|
-
const alt = host.querySelector('#codeAlt');
|
|
153
|
-
|
|
154
|
-
let text = state.code.cache[path];
|
|
155
|
-
if (text === undefined) {
|
|
156
|
-
monacoEl.hidden = true;
|
|
157
|
-
alt.innerHTML = '<div class="code-empty">Reading ' + escapeHtml(path) + '…</div>';
|
|
158
|
-
try {
|
|
159
|
-
text = await readRepoFile(path);
|
|
160
|
-
} catch (err) {
|
|
161
|
-
if (seq !== codeSeq) return;
|
|
162
|
-
alt.innerHTML = '<div class="code-empty">Could not read that file: ' + escapeHtml(err.message) + '</div>';
|
|
163
|
-
return;
|
|
164
146
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
147
|
+
const headEl = host.querySelector('#codeHead');
|
|
148
|
+
const linksEl = host.querySelector('#codeLinks');
|
|
149
|
+
const monacoEl = host.querySelector('#codeMonaco');
|
|
150
|
+
const alt = host.querySelector('#codeAlt');
|
|
151
|
+
let text = state.code.cache[path];
|
|
152
|
+
if (text === undefined) {
|
|
153
|
+
monacoEl.hidden = true;
|
|
154
|
+
alt.innerHTML = '<div class="code-empty">Reading ' + escapeHtml(path) + '…</div>';
|
|
155
|
+
try {
|
|
156
|
+
text = await readRepoFile(path);
|
|
157
|
+
}
|
|
158
|
+
catch (err) {
|
|
159
|
+
if (seq !== codeSeq)
|
|
160
|
+
return;
|
|
161
|
+
alt.innerHTML = '<div class="code-empty">Could not read that file: ' + escapeHtml(err.message) + '</div>';
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (seq !== codeSeq)
|
|
165
|
+
return;
|
|
166
|
+
state.code.cache[path] = text;
|
|
167
|
+
}
|
|
168
|
+
const { facts } = state;
|
|
169
|
+
const parsed = facts.fanIn[path] !== undefined;
|
|
170
|
+
const name = path.split('/').pop();
|
|
171
|
+
const ext = (name.match(/\.([A-Za-z0-9]+)$/) || [, ''])[1].toLowerCase();
|
|
172
|
+
const isBinary = text.slice(0, 8000).includes('\0');
|
|
173
|
+
renderHead(headEl, { path, name, ext, text, parsed, isBinary });
|
|
174
|
+
linksEl.innerHTML = parsed ? importChips(path) : '';
|
|
175
|
+
if (isBinary) {
|
|
176
|
+
monacoEl.hidden = true;
|
|
177
|
+
alt.innerHTML = '<div class="code-empty">Binary file — nothing to preview.</div>';
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
// Monaco first; the hand-rolled highlighter stands by if it can't load.
|
|
181
|
+
if (!viewerFailed) {
|
|
182
|
+
monacoEl.hidden = false;
|
|
183
|
+
const ok = await initViewer(monacoEl, hooks.getTheme());
|
|
184
|
+
if (seq !== codeSeq)
|
|
185
|
+
return;
|
|
186
|
+
if (ok) {
|
|
187
|
+
alt.innerHTML = '';
|
|
188
|
+
showInViewer(text, monacoLangOf(path), hooks.getTheme());
|
|
189
|
+
applyReveal(alt, revealLine);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
viewerFailed = true;
|
|
193
|
+
monacoEl.hidden = true;
|
|
194
194
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
198
|
-
renderFallback(alt, text, path);
|
|
199
|
-
applyReveal(alt, revealLine);
|
|
195
|
+
renderFallback(alt, text, path);
|
|
196
|
+
applyReveal(alt, revealLine);
|
|
200
197
|
}
|
|
201
|
-
|
|
202
198
|
// Navigation, identity, actions.
|
|
203
199
|
function renderHead(headEl, { path, name, ext, text, parsed, isBinary }) {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
headEl.innerHTML = `
|
|
200
|
+
const { facts } = state;
|
|
201
|
+
const canBack = state.code.idx > 0;
|
|
202
|
+
const canFwd = state.code.idx < state.code.history.length - 1;
|
|
203
|
+
const meta = [
|
|
204
|
+
(ext || 'text').toUpperCase(),
|
|
205
|
+
`${text.split('\n').length.toLocaleString()} lines`,
|
|
206
|
+
`${(new Blob([text]).size / 1024).toFixed(1)} KB`,
|
|
207
|
+
parsed ? `${roleOf(path, facts)} · ${facts.fanIn[path]} dependents · pulls in ${facts.fanOut[path]}` : 'not parsed',
|
|
208
|
+
].join(' · ');
|
|
209
|
+
headEl.innerHTML = `
|
|
215
210
|
<div class="code-nav">
|
|
216
211
|
<button class="code-navbtn" data-codenav="-1" ${canBack ? '' : 'disabled'} title="Previous file">←</button>
|
|
217
212
|
<button class="code-navbtn" data-codenav="1" ${canFwd ? '' : 'disabled'} title="Next file">→</button>
|
|
@@ -227,30 +222,30 @@ function renderHead(headEl, { path, name, ext, text, parsed, isBinary }) {
|
|
|
227
222
|
<button class="code-navbtn" data-codedive>Deep-dive →</button>
|
|
228
223
|
</div>`;
|
|
229
224
|
}
|
|
230
|
-
|
|
231
225
|
// The file's neighbours, both directions, as one-click jumps.
|
|
232
226
|
function importChips(path) {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
227
|
+
const { facts } = state;
|
|
228
|
+
const chip = (p) => `<button class="code-chip" data-codeopen="${escapeHtml(p)}" title="${escapeHtml(p)}">${escapeHtml(p.split('/').pop())}</button>`;
|
|
229
|
+
const pulls = (facts.importsOf[path] || []).map(chip).join('');
|
|
230
|
+
const leans = (facts.importers[path] || []).map(chip).join('');
|
|
231
|
+
if (!pulls && !leans)
|
|
232
|
+
return '';
|
|
233
|
+
return '<div class="code-links">'
|
|
234
|
+
+ (pulls ? `<span class="code-links-label">pulls in</span>${pulls}` : '')
|
|
235
|
+
+ (leans ? `<span class="code-links-label">leaned on by</span>${leans}` : '')
|
|
236
|
+
+ '</div>';
|
|
242
237
|
}
|
|
243
|
-
|
|
244
238
|
// Without Monaco: a gutter, a highlighted body, and a cap, because pasting a
|
|
245
239
|
// 40,000-line bundle into innerHTML locks the tab.
|
|
246
240
|
function renderFallback(alt, text, path) {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
241
|
+
const all = text.split('\n');
|
|
242
|
+
const capped = all.length > MAX_FALLBACK_LINES;
|
|
243
|
+
const lines = capped ? all.slice(0, MAX_FALLBACK_LINES) : all;
|
|
244
|
+
const gutter = lines.map((_, i) => i + 1).join('\n');
|
|
245
|
+
const note = capped
|
|
246
|
+
? `<div class="code-note">Showing the first ${MAX_FALLBACK_LINES.toLocaleString()} of ${all.length.toLocaleString()} lines.</div>`
|
|
247
|
+
: '';
|
|
248
|
+
alt.innerHTML = `${note}<div class="code-shell"><pre class="code-gutter">${gutter}</pre>`
|
|
249
|
+
+ `<pre class="code-body"><code>${highlightCode(lines.join('\n'), langOf(path))}</code></pre></div>`;
|
|
256
250
|
}
|
|
251
|
+
//# sourceMappingURL=codeTab.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codeTab.js","sourceRoot":"","sources":["../../src/public/js/codeTab.ts"],"names":[],"mappings":"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","sourcesContent":["// The Code tab: one file at a time, with its imports as chips you can click.\n//\n// Two viewers, one behind the other. Monaco is loaded from the app's own\n// `vendor/` folder and used if it comes up; if it does not, a hand-rolled\n// highlighter takes over for the rest of the session. Neither is required for\n// the page to be useful — the header, the facts and the import chips are drawn\n// from the graph before any file text arrives.\n//\n// The back/forward stack and the \"which file should I show\" decision live in\n// state.js, where they are pure and tested. What is left here is DOM.\n\nimport { roleOf } from '/shared/analyzer/graph.js';\nimport { escapeHtml } from './html.js';\nimport { highlightCode, langOf } from './highlight.js';\nimport { initViewer, showInViewer, monacoLangOf, revealLineInViewer } from './codeViewer.js';\nimport { fetchBlame, initBlameView } from './blameView.js';\nimport {\n state, focusFile, defaultCodePath, pushCodeHistory, codeHistoryTarget,\n} from './state.js';\nimport { readRepoFile } from './repoFiles.js';\n\nconst MAX_FALLBACK_LINES = 3000;\n\nlet host = null;\nlet renderBlameGutter = null;\nlet hooks = {\n onDeepDive: (_path: string) => {},\n onSyncInspector: (..._args: unknown[]) => {},\n onRenderSidebar: (..._args: unknown[]) => {},\n onOpenFile: (..._args: unknown[]) => {},\n onToast: (..._args: unknown[]) => {},\n getTheme: () => 'light',\n blameGutter: null,\n};\n\nlet codeSeq = 0; // render generations — a slow read never overwrites a newer one\nlet viewerFailed = false; // Monaco failed to load → hand-rolled fallback\nlet pendingReveal = null; // a line a search result asked for, waiting for its file\n\n// A search result knows which line it matched. The reveal has to wait until the\n// text is on screen, and it must not leak onto the *next* file you open — which\n// is why it is taken once, at the top of `renderCode`, rather than living in\n// `state` where it would outlive the file it was meant for.\nexport function revealLineInCode(line) {\n const target = Math.floor(Number(line));\n pendingReveal = Number.isFinite(target) && target > 0 ? target : null;\n}\n\n// Monaco is the real answer; without it, the fallback is a single scrolling\n// `<pre>`, so the best we can do is put the line near the top. Approximate, and\n// honest about being approximate — the file is still the right file.\nfunction applyReveal(alt, line) {\n if (!line) return;\n if (!viewerFailed) {\n revealLineInViewer(line);\n return;\n }\n const shell = alt.querySelector('.code-shell');\n if (!shell) return;\n const gutter = shell.querySelector('.code-gutter');\n const total = gutter ? (gutter.textContent || '').split('\\n').length : 0;\n if (!total) return;\n const perLine = shell.scrollHeight / total;\n shell.scrollTop = Math.max(0, (line - 2) * perLine);\n}\n\nexport function initCodeTab(options) {\n host = options.host;\n hooks = { ...hooks, ...options };\n if (options.blameGutter) {\n renderBlameGutter = initBlameView(options.blameGutter);\n }\n\n host.addEventListener('click', (event) => {\n const b = event.target.closest('button');\n if (!b) return;\n if (b.dataset.codeopen) return openCodeFile(b.dataset.codeopen);\n if (b.dataset.codenav) return codeNav(Number(b.dataset.codenav));\n if (b.dataset.codedive !== undefined) return (hooks.onDeepDive || hooks.onOpenFile)(state.code.path); // empty attribute is falsy — test undefined\n if (b.dataset.codeblame !== undefined) {\n if (!hooks.blameGutter) return;\n if (!hooks.blameGutter.hidden) {\n hooks.blameGutter.hidden = true;\n b.classList.remove('is-active');\n } else {\n hooks.onToast('Fetching git blame...');\n fetchBlame(state.scanId, state.code.path).then((data) => {\n if (data && data.lines && data.lines.length) {\n renderBlameGutter(data);\n hooks.blameGutter.hidden = false;\n b.classList.add('is-active');\n hooks.onToast(`Blame loaded for ${data.lines.length} lines`);\n } else {\n hooks.onToast(data?.reason || 'No blame available for this file.');\n }\n });\n }\n return;\n }\n if (b.dataset.codecopy !== undefined) {\n const text = state.code.cache[state.code.path];\n if (text !== undefined) {\n navigator.clipboard.writeText(text)\n .then(() => hooks.onToast('Copied to the clipboard.'))\n .catch(() => hooks.onToast('Could not copy to the clipboard.'));\n }\n }\n });\n}\n\n// In-tab navigation (the import chips) keeps the sidebar and inspector in step,\n// so the rest of the app follows along rather than pointing at the old file.\nfunction openCodeFile(path) {\n state.code.path = path;\n focusFile(path);\n hooks.onSyncInspector();\n hooks.onRenderSidebar();\n renderCode();\n}\n\nfunction codeNav(delta) {\n const path = codeHistoryTarget(delta);\n if (path) openCodeFile(path);\n}\n\nexport async function renderCode() {\n const seq = ++codeSeq;\n const path = defaultCodePath();\n // Taken once and cleared, so a reveal belongs only to the render that followed\n // the request for it — never to the next file you happen to open.\n const revealLine = pendingReveal;\n pendingReveal = null;\n if (!path) {\n host.innerHTML = '<div class=\"code-empty\">Nothing to preview — this repo has no readable files.</div>';\n return;\n }\n state.code.path = path;\n pushCodeHistory(path);\n\n // The shell is built once: the Monaco container must persist across file\n // switches, or the editor instance would be destroyed on every render.\n if (!host.querySelector('.code-page')) {\n host.innerHTML = `<div class=\"code-page\">\n <div class=\"code-head\" id=\"codeHead\"></div>\n <div id=\"codeLinks\"></div>\n <div class=\"code-monaco\" id=\"codeMonaco\" hidden></div>\n <div id=\"codeAlt\"></div>\n </div>`;\n }\n const headEl = host.querySelector('#codeHead');\n const linksEl = host.querySelector('#codeLinks');\n const monacoEl = host.querySelector('#codeMonaco');\n const alt = host.querySelector('#codeAlt');\n\n let text = state.code.cache[path];\n if (text === undefined) {\n monacoEl.hidden = true;\n alt.innerHTML = '<div class=\"code-empty\">Reading ' + escapeHtml(path) + '…</div>';\n try {\n text = await readRepoFile(path);\n } catch (err) {\n if (seq !== codeSeq) return;\n alt.innerHTML = '<div class=\"code-empty\">Could not read that file: ' + escapeHtml(err.message) + '</div>';\n return;\n }\n if (seq !== codeSeq) return;\n state.code.cache[path] = text;\n }\n\n const { facts } = state;\n const parsed = facts.fanIn[path] !== undefined;\n const name = path.split('/').pop();\n const ext = (name.match(/\\.([A-Za-z0-9]+)$/) || [, ''])[1].toLowerCase();\n const isBinary = text.slice(0, 8000).includes('\\0');\n\n renderHead(headEl, { path, name, ext, text, parsed, isBinary });\n linksEl.innerHTML = parsed ? importChips(path) : '';\n\n if (isBinary) {\n monacoEl.hidden = true;\n alt.innerHTML = '<div class=\"code-empty\">Binary file — nothing to preview.</div>';\n return;\n }\n\n // Monaco first; the hand-rolled highlighter stands by if it can't load.\n if (!viewerFailed) {\n monacoEl.hidden = false;\n const ok = await initViewer(monacoEl, hooks.getTheme());\n if (seq !== codeSeq) return;\n if (ok) {\n alt.innerHTML = '';\n showInViewer(text, monacoLangOf(path), hooks.getTheme());\n applyReveal(alt, revealLine);\n return;\n }\n viewerFailed = true;\n monacoEl.hidden = true;\n }\n renderFallback(alt, text, path);\n applyReveal(alt, revealLine);\n}\n\n// Navigation, identity, actions.\nfunction renderHead(headEl, { path, name, ext, text, parsed, isBinary }) {\n const { facts } = state;\n const canBack = state.code.idx > 0;\n const canFwd = state.code.idx < state.code.history.length - 1;\n const meta = [\n (ext || 'text').toUpperCase(),\n `${text.split('\\n').length.toLocaleString()} lines`,\n `${(new Blob([text]).size / 1024).toFixed(1)} KB`,\n parsed ? `${roleOf(path, facts)} · ${facts.fanIn[path]} dependents · pulls in ${facts.fanOut[path]}` : 'not parsed',\n ].join(' · ');\n\n headEl.innerHTML = `\n <div class=\"code-nav\">\n <button class=\"code-navbtn\" data-codenav=\"-1\" ${canBack ? '' : 'disabled'} title=\"Previous file\">←</button>\n <button class=\"code-navbtn\" data-codenav=\"1\" ${canFwd ? '' : 'disabled'} title=\"Next file\">→</button>\n </div>\n <div class=\"code-title\">\n <h2>${escapeHtml(name)}</h2>\n <div class=\"code-path\">${escapeHtml(path)}</div>\n <div class=\"code-meta\">${escapeHtml(meta)}</div>\n </div>\n <div class=\"code-actions\">\n <button class=\"code-navbtn\" data-codeblame ${isBinary ? 'disabled' : ''} title=\"Toggle Git blame annotations\">Blame</button>\n <button class=\"code-navbtn\" data-codecopy ${isBinary ? 'disabled' : ''}>Copy</button>\n <button class=\"code-navbtn\" data-codedive>Deep-dive →</button>\n </div>`;\n}\n\n// The file's neighbours, both directions, as one-click jumps.\nfunction importChips(path) {\n const { facts } = state;\n const chip = (p) => `<button class=\"code-chip\" data-codeopen=\"${escapeHtml(p)}\" title=\"${escapeHtml(p)}\">${escapeHtml(p.split('/').pop())}</button>`;\n const pulls = (facts.importsOf[path] || []).map(chip).join('');\n const leans = (facts.importers[path] || []).map(chip).join('');\n if (!pulls && !leans) return '';\n return '<div class=\"code-links\">'\n + (pulls ? `<span class=\"code-links-label\">pulls in</span>${pulls}` : '')\n + (leans ? `<span class=\"code-links-label\">leaned on by</span>${leans}` : '')\n + '</div>';\n}\n\n// Without Monaco: a gutter, a highlighted body, and a cap, because pasting a\n// 40,000-line bundle into innerHTML locks the tab.\nfunction renderFallback(alt, text, path) {\n const all = text.split('\\n');\n const capped = all.length > MAX_FALLBACK_LINES;\n const lines = capped ? all.slice(0, MAX_FALLBACK_LINES) : all;\n const gutter = lines.map((_, i) => i + 1).join('\\n');\n const note = capped\n ? `<div class=\"code-note\">Showing the first ${MAX_FALLBACK_LINES.toLocaleString()} of ${all.length.toLocaleString()} lines.</div>`\n : '';\n alt.innerHTML = `${note}<div class=\"code-shell\"><pre class=\"code-gutter\">${gutter}</pre>`\n + `<pre class=\"code-body\"><code>${highlightCode(lines.join('\\n'), langOf(path))}</code></pre></div>`;\n}\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function monacoLangOf(path: string): string;
|
|
2
|
+
export declare function initViewer(container: HTMLElement, theme: string): Promise<boolean>;
|
|
3
|
+
export declare function showInViewer(text: string, lang: string, theme: string): void;
|
|
4
|
+
export declare function setViewerTheme(theme: string): void;
|
|
5
|
+
export declare function revealLineInViewer(line: unknown): void;
|