codebase-onboarder 0.6.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.
Files changed (448) hide show
  1. package/README.md +174 -46
  2. package/bin/build-if-source.js +23 -0
  3. package/cli/commands.d.ts +26 -0
  4. package/cli/commands.js +836 -811
  5. package/cli/commands.js.map +1 -0
  6. package/cli/explorer/advanced.d.ts +14 -0
  7. package/cli/explorer/advanced.js +321 -329
  8. package/cli/explorer/advanced.js.map +1 -0
  9. package/cli/explorer/app.d.ts +1 -0
  10. package/cli/explorer/app.js +384 -313
  11. package/cli/explorer/app.js.map +1 -0
  12. package/cli/explorer/assistant.d.ts +9 -0
  13. package/cli/explorer/assistant.js +58 -0
  14. package/cli/explorer/assistant.js.map +1 -0
  15. package/cli/explorer/commands.d.ts +17 -0
  16. package/cli/explorer/commands.js +368 -302
  17. package/cli/explorer/commands.js.map +1 -0
  18. package/cli/explorer/featureViews.d.ts +124 -0
  19. package/cli/explorer/featureViews.js +179 -0
  20. package/cli/explorer/featureViews.js.map +1 -0
  21. package/cli/explorer/github.d.ts +21 -0
  22. package/cli/explorer/github.js +42 -44
  23. package/cli/explorer/github.js.map +1 -0
  24. package/cli/explorer/graphs.d.ts +7 -0
  25. package/cli/explorer/graphs.js +90 -95
  26. package/cli/explorer/graphs.js.map +1 -0
  27. package/cli/explorer/picker.d.ts +22 -0
  28. package/cli/explorer/picker.js +150 -0
  29. package/cli/explorer/picker.js.map +1 -0
  30. package/cli/explorer/report.d.ts +85 -0
  31. package/cli/explorer/report.js +60 -0
  32. package/cli/explorer/report.js.map +1 -0
  33. package/cli/explorer/session.d.ts +449 -0
  34. package/cli/explorer/session.js +143 -144
  35. package/cli/explorer/session.js.map +1 -0
  36. package/cli/explorer/views.d.ts +19 -0
  37. package/cli/explorer/views.js +465 -482
  38. package/cli/explorer/views.js.map +1 -0
  39. package/cli/explorer/wrap.d.ts +1 -0
  40. package/cli/explorer/wrap.js +28 -44
  41. package/cli/explorer/wrap.js.map +1 -0
  42. package/cli/main.d.ts +1 -0
  43. package/cli/main.js +214 -161
  44. package/cli/main.js.map +1 -0
  45. package/cli/prompt.d.ts +5 -0
  46. package/cli/prompt.js +84 -80
  47. package/cli/prompt.js.map +1 -0
  48. package/cli/scanOptions.d.ts +2 -0
  49. package/cli/scanOptions.js +11 -0
  50. package/cli/scanOptions.js.map +1 -0
  51. package/cli/ui.d.ts +33 -0
  52. package/cli/ui.js +35 -44
  53. package/cli/ui.js.map +1 -0
  54. package/cli/wizard.d.ts +187 -0
  55. package/cli/wizard.js +304 -284
  56. package/cli/wizard.js.map +1 -0
  57. package/package.json +15 -4
  58. package/public/app.d.ts +1 -0
  59. package/public/app.js +1057 -1009
  60. package/public/app.js.map +1 -0
  61. package/public/browser.d.ts +68 -0
  62. package/public/browser.js +2 -0
  63. package/public/browser.js.map +1 -0
  64. package/public/index.html +30 -13
  65. package/public/js/about.d.ts +6 -0
  66. package/public/js/about.js +152 -172
  67. package/public/js/about.js.map +1 -0
  68. package/public/js/aiDraft.d.ts +3 -0
  69. package/public/js/aiDraft.js +116 -124
  70. package/public/js/aiDraft.js.map +1 -0
  71. package/public/js/analysisPanel.d.ts +7 -0
  72. package/public/js/analysisPanel.js +166 -166
  73. package/public/js/analysisPanel.js.map +1 -0
  74. package/public/js/analysisReport.d.ts +38 -0
  75. package/public/js/analysisReport.js +105 -110
  76. package/public/js/analysisReport.js.map +1 -0
  77. package/public/js/api.d.ts +26 -0
  78. package/public/js/api.js +176 -167
  79. package/public/js/api.js.map +1 -0
  80. package/public/js/atlas.d.ts +6 -0
  81. package/public/js/atlas.js +50 -58
  82. package/public/js/atlas.js.map +1 -0
  83. package/public/js/blameView.d.ts +2 -0
  84. package/public/js/blameView.js +36 -37
  85. package/public/js/blameView.js.map +1 -0
  86. package/public/js/codeTab.d.ts +3 -0
  87. package/public/js/codeTab.js +175 -180
  88. package/public/js/codeTab.js.map +1 -0
  89. package/public/js/codeViewer.d.ts +5 -0
  90. package/public/js/codeViewer.js +162 -150
  91. package/public/js/codeViewer.js.map +1 -0
  92. package/public/js/components/FileChip.d.ts +9 -0
  93. package/public/js/components/FileChip.js +45 -49
  94. package/public/js/components/FileChip.js.map +1 -0
  95. package/public/js/components/MetricSparkline.d.ts +7 -0
  96. package/public/js/components/MetricSparkline.js +35 -44
  97. package/public/js/components/MetricSparkline.js.map +1 -0
  98. package/public/js/components/RiskBadge.d.ts +9 -0
  99. package/public/js/components/RiskBadge.js +55 -63
  100. package/public/js/components/RiskBadge.js.map +1 -0
  101. package/public/js/deepAnalysisView.d.ts +99 -0
  102. package/public/js/deepAnalysisView.js +282 -302
  103. package/public/js/deepAnalysisView.js.map +1 -0
  104. package/public/js/diagramPane.d.ts +8 -0
  105. package/public/js/diagramPane.js +133 -135
  106. package/public/js/diagramPane.js.map +1 -0
  107. package/public/js/diffView.d.ts +6 -0
  108. package/public/js/diffView.js +222 -209
  109. package/public/js/diffView.js.map +1 -0
  110. package/public/js/docsView.d.ts +2 -0
  111. package/public/js/docsView.js +441 -442
  112. package/public/js/docsView.js.map +1 -0
  113. package/public/js/dom.d.ts +189 -0
  114. package/public/js/dom.js +5 -0
  115. package/public/js/dom.js.map +1 -0
  116. package/public/js/fileSourceBrowser.d.ts +5 -0
  117. package/public/js/fileSourceBrowser.js +33 -41
  118. package/public/js/fileSourceBrowser.js.map +1 -0
  119. package/public/js/flameGraph.d.ts +5 -0
  120. package/public/js/flameGraph.js +62 -72
  121. package/public/js/flameGraph.js.map +1 -0
  122. package/public/js/forceGraph.d.ts +10 -0
  123. package/public/js/forceGraph.js +581 -556
  124. package/public/js/forceGraph.js.map +1 -0
  125. package/public/js/heatmap.d.ts +4 -0
  126. package/public/js/heatmap.js +142 -164
  127. package/public/js/heatmap.js.map +1 -0
  128. package/public/js/highlight.d.ts +2 -0
  129. package/public/js/highlight.js +116 -107
  130. package/public/js/highlight.js.map +1 -0
  131. package/public/js/html.d.ts +2 -0
  132. package/public/js/html.js +14 -44
  133. package/public/js/html.js.map +1 -0
  134. package/public/js/insightsView.d.ts +5 -0
  135. package/public/js/insightsView.js +93 -111
  136. package/public/js/insightsView.js.map +1 -0
  137. package/public/js/inspector.d.ts +37 -0
  138. package/public/js/inspector.js +416 -445
  139. package/public/js/inspector.js.map +1 -0
  140. package/public/js/llm.d.ts +113 -0
  141. package/public/js/llm.js +233 -272
  142. package/public/js/llm.js.map +1 -0
  143. package/public/js/mapView.d.ts +3 -0
  144. package/public/js/mapView.js +121 -120
  145. package/public/js/mapView.js.map +1 -0
  146. package/public/js/markdown.d.ts +3 -0
  147. package/public/js/markdown.js +84 -91
  148. package/public/js/markdown.js.map +1 -0
  149. package/public/js/mindmap.d.ts +32 -0
  150. package/public/js/mindmap.js +244 -259
  151. package/public/js/mindmap.js.map +1 -0
  152. package/public/js/mobilePanels.d.ts +5 -0
  153. package/public/js/mobilePanels.js +50 -0
  154. package/public/js/mobilePanels.js.map +1 -0
  155. package/public/js/repoFiles.d.ts +12 -0
  156. package/public/js/repoFiles.js +28 -27
  157. package/public/js/repoFiles.js.map +1 -0
  158. package/public/js/reviewView.d.ts +28 -0
  159. package/public/js/reviewView.js +256 -0
  160. package/public/js/reviewView.js.map +1 -0
  161. package/public/js/sbomView.d.ts +3 -0
  162. package/public/js/sbomView.js +59 -67
  163. package/public/js/sbomView.js.map +1 -0
  164. package/public/js/scanCache.d.ts +16 -0
  165. package/public/js/scanCache.js +67 -65
  166. package/public/js/scanCache.js.map +1 -0
  167. package/public/js/search.d.ts +7 -0
  168. package/public/js/search.js +868 -800
  169. package/public/js/search.js.map +1 -0
  170. package/public/js/searchLocal.d.ts +42 -0
  171. package/public/js/searchLocal.js +87 -0
  172. package/public/js/searchLocal.js.map +1 -0
  173. package/public/js/serverSettings.d.ts +5 -0
  174. package/public/js/serverSettings.js +153 -164
  175. package/public/js/serverSettings.js.map +1 -0
  176. package/public/js/state.d.ts +798 -0
  177. package/public/js/state.js +114 -122
  178. package/public/js/state.js.map +1 -0
  179. package/public/js/tour.d.ts +6 -0
  180. package/public/js/tour.js +5 -7
  181. package/public/js/tour.js.map +1 -0
  182. package/public/js/transitions.d.ts +2 -0
  183. package/public/js/transitions.js +9 -10
  184. package/public/js/transitions.js.map +1 -0
  185. package/public/js/tree.d.ts +12 -0
  186. package/public/js/tree.js +157 -154
  187. package/public/js/tree.js.map +1 -0
  188. package/public/js/workflowsView.d.ts +3 -0
  189. package/public/js/workflowsView.js +15 -22
  190. package/public/js/workflowsView.js.map +1 -0
  191. package/public/search.css +495 -0
  192. package/public/styles.css +163 -346
  193. package/public/workbench.css +166 -0
  194. package/server/apiAuth.d.ts +3 -0
  195. package/server/apiAuth.js +18 -20
  196. package/server/apiAuth.js.map +1 -0
  197. package/server/apiDiff.d.ts +2 -0
  198. package/server/apiDiff.js +20 -18
  199. package/server/apiDiff.js.map +1 -0
  200. package/server/apiDocs.d.ts +2 -0
  201. package/server/apiDocs.js +38 -40
  202. package/server/apiDocs.js.map +1 -0
  203. package/server/apiFile.d.ts +1 -0
  204. package/server/apiFile.js +14 -17
  205. package/server/apiFile.js.map +1 -0
  206. package/server/apiGitBlame.d.ts +2 -0
  207. package/server/apiGitBlame.js +50 -51
  208. package/server/apiGitBlame.js.map +1 -0
  209. package/server/apiMcp.d.ts +4 -0
  210. package/server/apiMcp.js +64 -66
  211. package/server/apiMcp.js.map +1 -0
  212. package/server/apiReview.d.ts +2 -0
  213. package/server/apiReview.js +45 -0
  214. package/server/apiReview.js.map +1 -0
  215. package/server/apiScan.d.ts +5 -0
  216. package/server/apiScan.js +90 -71
  217. package/server/apiScan.js.map +1 -0
  218. package/server/apiSearch.d.ts +33 -0
  219. package/server/apiSearch.js +184 -200
  220. package/server/apiSearch.js.map +1 -0
  221. package/server/apiSettings.d.ts +4 -0
  222. package/server/apiSettings.js +84 -85
  223. package/server/apiSettings.js.map +1 -0
  224. package/server/apiTools.d.ts +3 -0
  225. package/server/apiTools.js +55 -56
  226. package/server/apiTools.js.map +1 -0
  227. package/server/auth.d.ts +5 -0
  228. package/server/auth.js +54 -51
  229. package/server/auth.js.map +1 -0
  230. package/server/config.d.ts +42 -0
  231. package/server/config.js +189 -194
  232. package/server/config.js.map +1 -0
  233. package/server/daemon.d.ts +12 -0
  234. package/server/daemon.js +124 -114
  235. package/server/daemon.js.map +1 -0
  236. package/server/fileSourceNode.d.ts +2 -0
  237. package/server/fileSourceNode.js +34 -36
  238. package/server/fileSourceNode.js.map +1 -0
  239. package/server/gitClone.d.ts +9 -0
  240. package/server/gitClone.js +59 -61
  241. package/server/gitClone.js.map +1 -0
  242. package/server/gitDiff.d.ts +36 -0
  243. package/server/gitDiff.js +271 -169
  244. package/server/gitDiff.js.map +1 -0
  245. package/server/gitHistory.d.ts +12 -0
  246. package/server/gitHistory.js +80 -80
  247. package/server/gitHistory.js.map +1 -0
  248. package/server/gitRemote.d.ts +12 -0
  249. package/server/gitRemote.js +37 -38
  250. package/server/gitRemote.js.map +1 -0
  251. package/server/htmlText.d.ts +4 -0
  252. package/server/htmlText.js +16 -23
  253. package/server/htmlText.js.map +1 -0
  254. package/server/http.d.ts +5 -0
  255. package/server/http.js +27 -30
  256. package/server/http.js.map +1 -0
  257. package/server/httpGuards.d.ts +2 -0
  258. package/server/httpGuards.js +47 -43
  259. package/server/httpGuards.js.map +1 -0
  260. package/server/https.d.ts +34 -0
  261. package/server/https.js +121 -111
  262. package/server/https.js.map +1 -0
  263. package/server/index.d.ts +40 -0
  264. package/server/index.js +139 -147
  265. package/server/index.js.map +1 -0
  266. package/server/layout.d.ts +26 -0
  267. package/server/layout.js +59 -64
  268. package/server/layout.js.map +1 -0
  269. package/server/llmProxy.d.ts +3 -0
  270. package/server/llmProxy.js +137 -135
  271. package/server/llmProxy.js.map +1 -0
  272. package/server/logger.d.ts +38 -0
  273. package/server/logger.js +198 -211
  274. package/server/logger.js.map +1 -0
  275. package/server/mcp/analysis.d.ts +29 -0
  276. package/server/mcp/analysis.js +99 -120
  277. package/server/mcp/analysis.js.map +1 -0
  278. package/server/mcp/http.d.ts +9 -0
  279. package/server/mcp/http.js +128 -137
  280. package/server/mcp/http.js.map +1 -0
  281. package/server/mcp/runner.d.ts +68 -0
  282. package/server/mcp/runner.js +208 -218
  283. package/server/mcp/runner.js.map +1 -0
  284. package/server/mcp/server.d.ts +29 -0
  285. package/server/mcp/server.js +166 -179
  286. package/server/mcp/server.js.map +1 -0
  287. package/server/mcp/standalone.d.ts +1 -0
  288. package/server/mcp/standalone.js +8 -10
  289. package/server/mcp/standalone.js.map +1 -0
  290. package/server/mcp/tools.d.ts +2020 -0
  291. package/server/mcp/tools.js +523 -574
  292. package/server/mcp/tools.js.map +1 -0
  293. package/server/paths.d.ts +3 -0
  294. package/server/paths.js +17 -15
  295. package/server/paths.js.map +1 -0
  296. package/server/pidfile.d.ts +9 -0
  297. package/server/pidfile.js +43 -45
  298. package/server/pidfile.js.map +1 -0
  299. package/server/review.d.ts +5 -0
  300. package/server/review.js +35 -0
  301. package/server/review.js.map +1 -0
  302. package/server/router.d.ts +33 -0
  303. package/server/router.js +191 -197
  304. package/server/router.js.map +1 -0
  305. package/server/scanRequest.d.ts +3 -0
  306. package/server/scanRequest.js +36 -0
  307. package/server/scanRequest.js.map +1 -0
  308. package/server/searchIndex.d.ts +17 -0
  309. package/server/searchIndex.js +83 -80
  310. package/server/searchIndex.js.map +1 -0
  311. package/server/sessions.d.ts +14 -0
  312. package/server/sessions.js +62 -70
  313. package/server/sessions.js.map +1 -0
  314. package/server/startup.d.ts +118 -0
  315. package/server/startup.js +143 -148
  316. package/server/startup.js.map +1 -0
  317. package/server/static.d.ts +6 -0
  318. package/server/static.js +28 -31
  319. package/server/static.js.map +1 -0
  320. package/server/tools/install.d.ts +4 -0
  321. package/server/tools/install.js +176 -185
  322. package/server/tools/install.js.map +1 -0
  323. package/server/tools/parse.d.ts +8 -0
  324. package/server/tools/parse.js +112 -114
  325. package/server/tools/parse.js.map +1 -0
  326. package/server/tools/platform.d.ts +9 -0
  327. package/server/tools/platform.js +49 -47
  328. package/server/tools/platform.js.map +1 -0
  329. package/server/tools/registry.d.ts +137 -0
  330. package/server/tools/registry.js +173 -172
  331. package/server/tools/registry.js.map +1 -0
  332. package/server/tools/scan.d.ts +34 -0
  333. package/server/tools/scan.js +89 -98
  334. package/server/tools/scan.js.map +1 -0
  335. package/server/tools.d.ts +34 -0
  336. package/server/tools.js +94 -107
  337. package/server/tools.js.map +1 -0
  338. package/server/tunnel.d.ts +29 -0
  339. package/server/tunnel.js +61 -66
  340. package/server/tunnel.js.map +1 -0
  341. package/shared/analyzer/docs.d.ts +16 -0
  342. package/shared/analyzer/docs.js +99 -93
  343. package/shared/analyzer/docs.js.map +1 -0
  344. package/shared/analyzer/explainLocal.d.ts +4 -0
  345. package/shared/analyzer/explainLocal.js +122 -142
  346. package/shared/analyzer/explainLocal.js.map +1 -0
  347. package/shared/analyzer/github.d.ts +37 -0
  348. package/shared/analyzer/github.js +41 -43
  349. package/shared/analyzer/github.js.map +1 -0
  350. package/shared/analyzer/graph.d.ts +41 -0
  351. package/shared/analyzer/graph.js +393 -400
  352. package/shared/analyzer/graph.js.map +1 -0
  353. package/shared/analyzer/health.d.ts +33 -0
  354. package/shared/analyzer/health.js +197 -193
  355. package/shared/analyzer/health.js.map +1 -0
  356. package/shared/analyzer/history.d.ts +29 -0
  357. package/shared/analyzer/history.js +110 -111
  358. package/shared/analyzer/history.js.map +1 -0
  359. package/shared/analyzer/jsonConfig.d.ts +2 -0
  360. package/shared/analyzer/jsonConfig.js +61 -0
  361. package/shared/analyzer/jsonConfig.js.map +1 -0
  362. package/shared/analyzer/languages/csharp.d.ts +26 -0
  363. package/shared/analyzer/languages/csharp.js +83 -88
  364. package/shared/analyzer/languages/csharp.js.map +1 -0
  365. package/shared/analyzer/languages/generic.d.ts +23 -0
  366. package/shared/analyzer/languages/generic.js +94 -105
  367. package/shared/analyzer/languages/generic.js.map +1 -0
  368. package/shared/analyzer/languages/go.d.ts +24 -0
  369. package/shared/analyzer/languages/go.js +45 -54
  370. package/shared/analyzer/languages/go.js.map +1 -0
  371. package/shared/analyzer/languages/index.d.ts +6 -0
  372. package/shared/analyzer/languages/index.js +19 -20
  373. package/shared/analyzer/languages/index.js.map +1 -0
  374. package/shared/analyzer/languages/java.d.ts +20 -0
  375. package/shared/analyzer/languages/java.js +73 -78
  376. package/shared/analyzer/languages/java.js.map +1 -0
  377. package/shared/analyzer/languages/javascript.d.ts +12 -0
  378. package/shared/analyzer/languages/javascript.js +258 -209
  379. package/shared/analyzer/languages/javascript.js.map +1 -0
  380. package/shared/analyzer/languages/python.d.ts +23 -0
  381. package/shared/analyzer/languages/python.js +92 -100
  382. package/shared/analyzer/languages/python.js.map +1 -0
  383. package/shared/analyzer/languages/rust.d.ts +17 -0
  384. package/shared/analyzer/languages/rust.js +96 -98
  385. package/shared/analyzer/languages/rust.js.map +1 -0
  386. package/shared/analyzer/languages/typescript.d.ts +11 -0
  387. package/shared/analyzer/languages/typescript.js +117 -116
  388. package/shared/analyzer/languages/typescript.js.map +1 -0
  389. package/shared/analyzer/licenses.d.ts +18 -0
  390. package/shared/analyzer/licenses.js +130 -133
  391. package/shared/analyzer/licenses.js.map +1 -0
  392. package/shared/analyzer/metrics.d.ts +20 -0
  393. package/shared/analyzer/metrics.js +112 -104
  394. package/shared/analyzer/metrics.js.map +1 -0
  395. package/shared/analyzer/pathUtil.d.ts +10 -0
  396. package/shared/analyzer/pathUtil.js +29 -35
  397. package/shared/analyzer/pathUtil.js.map +1 -0
  398. package/shared/analyzer/patterns.d.ts +11 -0
  399. package/shared/analyzer/patterns.js +231 -253
  400. package/shared/analyzer/patterns.js.map +1 -0
  401. package/shared/analyzer/scan.d.ts +62 -0
  402. package/shared/analyzer/scan.js +451 -442
  403. package/shared/analyzer/scan.js.map +1 -0
  404. package/shared/analyzer/scanControl.d.ts +11 -0
  405. package/shared/analyzer/scanControl.js +62 -0
  406. package/shared/analyzer/scanControl.js.map +1 -0
  407. package/shared/analyzer/security.d.ts +18 -0
  408. package/shared/analyzer/security.js +159 -159
  409. package/shared/analyzer/security.js.map +1 -0
  410. package/shared/analyzer/services.d.ts +5 -0
  411. package/shared/analyzer/services.js +141 -138
  412. package/shared/analyzer/services.js.map +1 -0
  413. package/shared/analyzer/stack.d.ts +6 -0
  414. package/shared/analyzer/stack.js +134 -141
  415. package/shared/analyzer/stack.js.map +1 -0
  416. package/shared/analyzer/tour.d.ts +2 -0
  417. package/shared/analyzer/tour.js +45 -53
  418. package/shared/analyzer/tour.js.map +1 -0
  419. package/shared/analyzer/util.d.ts +8 -0
  420. package/shared/analyzer/util.js +130 -76
  421. package/shared/analyzer/util.js.map +1 -0
  422. package/shared/analyzer/workflows.d.ts +8 -0
  423. package/shared/analyzer/workflows.js +139 -134
  424. package/shared/analyzer/workflows.js.map +1 -0
  425. package/shared/contracts.d.ts +250 -0
  426. package/shared/contracts.js +2 -0
  427. package/shared/contracts.js.map +1 -0
  428. package/shared/diagram/aiFacts.d.ts +35 -0
  429. package/shared/diagram/aiFacts.js +102 -105
  430. package/shared/diagram/aiFacts.js.map +1 -0
  431. package/shared/diagram/aiMermaid.d.ts +5 -0
  432. package/shared/diagram/aiMermaid.js +46 -45
  433. package/shared/diagram/aiMermaid.js.map +1 -0
  434. package/shared/diagram/atlas.d.ts +16 -0
  435. package/shared/diagram/atlas.js +51 -60
  436. package/shared/diagram/atlas.js.map +1 -0
  437. package/shared/diagram/mermaid.d.ts +43 -0
  438. package/shared/diagram/mermaid.js +348 -370
  439. package/shared/diagram/mermaid.js.map +1 -0
  440. package/shared/review/contracts.d.ts +95 -0
  441. package/shared/review/contracts.js +2 -0
  442. package/shared/review/contracts.js.map +1 -0
  443. package/shared/review/review.d.ts +10 -0
  444. package/shared/review/review.js +184 -0
  445. package/shared/review/review.js.map +1 -0
  446. package/shared/search/query.d.ts +32 -0
  447. package/shared/search/query.js +395 -388
  448. package/shared/search/query.js.map +1 -0
@@ -1,41 +1,40 @@
1
1
  export function initBlameView(container) {
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
-
10
- // Hash author to color
11
- function getAuthorColor(author) {
12
- let hash = 0;
13
- for (let i = 0; i < author.length; i++) hash = author.charCodeAt(i) + ((hash << 5) - hash);
14
- return `hsl(${Math.abs(hash) % 360}, 60%, 50%)`;
15
- }
16
-
17
- blameData.lines.forEach(line => {
18
- const div = document.createElement('div');
19
- div.className = 'blame-line';
20
- div.style.backgroundColor = getAuthorColor(line.author || 'Unknown');
21
-
22
- const tooltip = document.createElement('div');
23
- tooltip.className = 'blame-tooltip';
24
- tooltip.textContent = `${line.author} - ${line.date || ''} (${(line.sha || '').substring(0, 7)})`;
25
-
26
- div.appendChild(tooltip);
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
- try {
34
- const res = await fetch(`/api/blame?scan=${encodeURIComponent(scanId)}&path=${encodeURIComponent(path)}`);
35
- if (!res.ok) return null;
36
- return await res.json();
37
- } catch (err) {
38
- console.error('Failed to fetch blame:', err);
39
- return null;
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"]}
@@ -0,0 +1,3 @@
1
+ export declare function revealLineInCode(line: any): void;
2
+ export declare function initCodeTab(options: any): void;
3
+ export declare function renderCode(): Promise<void>;
@@ -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
- onSyncInspector: () => {},
28
- onRenderSidebar: () => {},
29
- onOpenFile: () => {},
30
- onToast: () => {},
31
- getTheme: () => 'light',
32
- blameGutter: null,
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
- const target = Math.floor(Number(line));
45
- pendingReveal = Number.isFinite(target) && target > 0 ? target : null;
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
- if (!line) return;
53
- if (!viewerFailed) {
54
- revealLineInViewer(line);
55
- return;
56
- }
57
- const shell = alt.querySelector('.code-shell');
58
- if (!shell) return;
59
- const gutter = shell.querySelector('.code-gutter');
60
- const total = gutter ? (gutter.textContent || '').split('\n').length : 0;
61
- if (!total) return;
62
- const perLine = shell.scrollHeight / total;
63
- shell.scrollTop = Math.max(0, (line - 2) * perLine);
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
- host = options.host;
68
- hooks = { ...hooks, ...options };
69
- if (options.blameGutter) {
70
- renderBlameGutter = initBlameView(options.blameGutter);
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
- state.code.path = path;
114
- focusFile(path);
115
- hooks.onSyncInspector();
116
- hooks.onRenderSidebar();
117
- renderCode();
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
- const path = codeHistoryTarget(delta);
122
- if (path) openCodeFile(path);
120
+ const path = codeHistoryTarget(delta);
121
+ if (path)
122
+ openCodeFile(path);
123
123
  }
124
-
125
124
  export async function renderCode() {
126
- const seq = ++codeSeq;
127
- const path = defaultCodePath();
128
- // Taken once and cleared, so a reveal belongs only to the render that followed
129
- // the request for it — never to the next file you happen to open.
130
- const revealLine = pendingReveal;
131
- pendingReveal = null;
132
- if (!path) {
133
- host.innerHTML = '<div class="code-empty">Nothing to preview — this repo has no readable files.</div>';
134
- return;
135
- }
136
- state.code.path = path;
137
- pushCodeHistory(path);
138
-
139
- // The shell is built once: the Monaco container must persist across file
140
- // switches, or the editor instance would be destroyed on every render.
141
- if (!host.querySelector('.code-page')) {
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
- if (seq !== codeSeq) return;
166
- state.code.cache[path] = text;
167
- }
168
-
169
- const { facts } = state;
170
- const parsed = facts.fanIn[path] !== undefined;
171
- const name = path.split('/').pop();
172
- const ext = (name.match(/\.([A-Za-z0-9]+)$/) || [, ''])[1].toLowerCase();
173
- const isBinary = text.slice(0, 8000).includes('\0');
174
-
175
- renderHead(headEl, { path, name, ext, text, parsed, isBinary });
176
- linksEl.innerHTML = parsed ? importChips(path) : '';
177
-
178
- if (isBinary) {
179
- monacoEl.hidden = true;
180
- alt.innerHTML = '<div class="code-empty">Binary file — nothing to preview.</div>';
181
- return;
182
- }
183
-
184
- // Monaco first; the hand-rolled highlighter stands by if it can't load.
185
- if (!viewerFailed) {
186
- monacoEl.hidden = false;
187
- const ok = await initViewer(monacoEl, hooks.getTheme());
188
- if (seq !== codeSeq) return;
189
- if (ok) {
190
- alt.innerHTML = '';
191
- showInViewer(text, monacoLangOf(path), hooks.getTheme());
192
- applyReveal(alt, revealLine);
193
- return;
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
- viewerFailed = true;
196
- monacoEl.hidden = true;
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
- const { facts } = state;
205
- const canBack = state.code.idx > 0;
206
- const canFwd = state.code.idx < state.code.history.length - 1;
207
- const meta = [
208
- (ext || 'text').toUpperCase(),
209
- `${text.split('\n').length.toLocaleString()} lines`,
210
- `${(new Blob([text]).size / 1024).toFixed(1)} KB`,
211
- parsed ? `${roleOf(path, facts)} · ${facts.fanIn[path]} dependents · pulls in ${facts.fanOut[path]}` : 'not parsed',
212
- ].join(' · ');
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
- const { facts } = state;
234
- const chip = (p) => `<button class="code-chip" data-codeopen="${escapeHtml(p)}" title="${escapeHtml(p)}">${escapeHtml(p.split('/').pop())}</button>`;
235
- const pulls = (facts.importsOf[path] || []).map(chip).join('');
236
- const leans = (facts.importers[path] || []).map(chip).join('');
237
- if (!pulls && !leans) return '';
238
- return '<div class="code-links">'
239
- + (pulls ? `<span class="code-links-label">pulls in</span>${pulls}` : '')
240
- + (leans ? `<span class="code-links-label">leaned on by</span>${leans}` : '')
241
- + '</div>';
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
- const all = text.split('\n');
248
- const capped = all.length > MAX_FALLBACK_LINES;
249
- const lines = capped ? all.slice(0, MAX_FALLBACK_LINES) : all;
250
- const gutter = lines.map((_, i) => i + 1).join('\n');
251
- const note = capped
252
- ? `<div class="code-note">Showing the first ${MAX_FALLBACK_LINES.toLocaleString()} of ${all.length.toLocaleString()} lines.</div>`
253
- : '';
254
- alt.innerHTML = `${note}<div class="code-shell"><pre class="code-gutter">${gutter}</pre>`
255
- + `<pre class="code-body"><code>${highlightCode(lines.join('\n'), langOf(path))}</code></pre></div>`;
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;