pkgviz 0.7.7 → 0.8.1

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 (367) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +2 -1
  3. package/.next/build-manifest.json +15 -24
  4. package/.next/fallback-build-manifest.json +15 -0
  5. package/.next/images-manifest.json +14 -3
  6. package/.next/next-minimal-server.js.nft.json +1 -1
  7. package/.next/next-server.js.nft.json +1 -1
  8. package/.next/prerender-manifest.json +52 -16
  9. package/.next/required-server-files.js +349 -0
  10. package/.next/required-server-files.json +106 -75
  11. package/.next/routes-manifest.json +16 -6
  12. package/.next/server/app/_global-error/page/app-paths-manifest.json +3 -0
  13. package/.next/server/app/_global-error/page/build-manifest.json +20 -0
  14. package/.next/server/app/_global-error/page/next-font-manifest.json +6 -0
  15. package/.next/server/app/_global-error/page/server-reference-manifest.json +4 -0
  16. package/.next/server/app/_global-error/page.js +9 -0
  17. package/.next/server/app/_global-error/page.js.map +5 -0
  18. package/.next/server/app/_global-error/page.js.nft.json +1 -0
  19. package/.next/server/app/_global-error/page_client-reference-manifest.js +3 -0
  20. package/.next/server/app/_global-error.html +1 -0
  21. package/.next/server/app/_global-error.meta +22 -0
  22. package/.next/server/app/_global-error.rsc +15 -0
  23. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +20 -0
  24. package/.next/server/app/_global-error.segments/_full.segment.rsc +15 -0
  25. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -0
  26. package/.next/server/app/_not-found/page/app-paths-manifest.json +3 -0
  27. package/.next/server/app/_not-found/page/build-manifest.json +20 -0
  28. package/.next/server/app/_not-found/page/next-font-manifest.json +11 -0
  29. package/.next/server/app/_not-found/page/react-loadable-manifest.json +1 -0
  30. package/.next/server/app/_not-found/page/server-reference-manifest.json +4 -0
  31. package/.next/server/app/_not-found/page.js +13 -2
  32. package/.next/server/app/_not-found/page.js.map +5 -0
  33. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  34. package/.next/server/app/_not-found/page_client-reference-manifest.js +3 -1
  35. package/.next/server/app/_not-found.html +1 -1
  36. package/.next/server/app/_not-found.meta +19 -0
  37. package/.next/server/app/_not-found.rsc +18 -19
  38. package/.next/server/app/_not-found.segments/_full.segment.rsc +18 -0
  39. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +24 -0
  40. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -0
  41. package/.next/server/app/favicon.ico/route/app-paths-manifest.json +3 -0
  42. package/.next/server/app/favicon.ico/route/build-manifest.json +12 -0
  43. package/.next/server/app/favicon.ico/route.js +6 -1
  44. package/.next/server/app/favicon.ico/route.js.map +5 -0
  45. package/.next/server/app/favicon.ico/route.js.nft.json +1 -1
  46. package/.next/server/app/page/app-paths-manifest.json +3 -0
  47. package/.next/server/app/page/build-manifest.json +20 -0
  48. package/.next/server/app/page/next-font-manifest.json +11 -0
  49. package/.next/server/app/page/react-loadable-manifest.json +1 -0
  50. package/.next/server/app/page/server-reference-manifest.json +93 -0
  51. package/.next/server/app/page.js +16 -13
  52. package/.next/server/app/page.js.map +5 -0
  53. package/.next/server/app/page.js.nft.json +1 -1
  54. package/.next/server/app/page_client-reference-manifest.js +3 -1
  55. package/.next/server/app-paths-manifest.json +2 -1
  56. package/.next/server/chunks/[externals]__0l8ei7u._.js +3 -0
  57. package/.next/server/chunks/[externals]__0l8ei7u._.js.map +1 -0
  58. package/.next/server/chunks/[root-of-the-server]__1to-yfd._.js +160 -0
  59. package/.next/server/chunks/[root-of-the-server]__1to-yfd._.js.map +1 -0
  60. package/.next/server/chunks/[turbopack]_runtime.js +807 -0
  61. package/.next/server/chunks/[turbopack]_runtime.js.map +10 -0
  62. package/.next/server/chunks/_next-internal_server_app_favicon_ico_route_actions_0g2jjls.js +3 -0
  63. package/.next/server/chunks/_next-internal_server_app_favicon_ico_route_actions_0g2jjls.js.map +1 -0
  64. package/.next/server/chunks/ssr/[root-of-the-server]__0agsrep._.js +28 -0
  65. package/.next/server/chunks/ssr/[root-of-the-server]__0agsrep._.js.map +1 -0
  66. package/.next/server/chunks/ssr/[root-of-the-server]__0f_e7c8._.js +33 -0
  67. package/.next/server/chunks/ssr/[root-of-the-server]__0f_e7c8._.js.map +1 -0
  68. package/.next/server/chunks/ssr/[root-of-the-server]__0yqn68e._.js +3 -0
  69. package/.next/server/chunks/ssr/[root-of-the-server]__0yqn68e._.js.map +1 -0
  70. package/.next/server/chunks/ssr/[root-of-the-server]__112mz-6._.js +14 -0
  71. package/.next/server/chunks/ssr/[root-of-the-server]__112mz-6._.js.map +1 -0
  72. package/.next/server/chunks/ssr/[root-of-the-server]__11_76b7._.js +3 -0
  73. package/.next/server/chunks/ssr/[root-of-the-server]__11_76b7._.js.map +1 -0
  74. package/.next/server/chunks/ssr/[root-of-the-server]__12ovu0c._.js +3 -0
  75. package/.next/server/chunks/ssr/[root-of-the-server]__12ovu0c._.js.map +1 -0
  76. package/.next/server/chunks/ssr/[root-of-the-server]__16pmw__._.js +3 -0
  77. package/.next/server/chunks/ssr/[root-of-the-server]__16pmw__._.js.map +1 -0
  78. package/.next/server/chunks/ssr/[root-of-the-server]__1f2jx51._.js +33 -0
  79. package/.next/server/chunks/ssr/[root-of-the-server]__1f2jx51._.js.map +1 -0
  80. package/.next/server/chunks/ssr/[root-of-the-server]__1rn09vt._.js +3 -0
  81. package/.next/server/chunks/ssr/[root-of-the-server]__1rn09vt._.js.map +1 -0
  82. package/.next/server/chunks/ssr/[root-of-the-server]__20e4gkp._.js +3 -0
  83. package/.next/server/chunks/ssr/[root-of-the-server]__20e4gkp._.js.map +1 -0
  84. package/.next/server/chunks/ssr/[turbopack]_runtime.js +807 -0
  85. package/.next/server/chunks/ssr/[turbopack]_runtime.js.map +10 -0
  86. package/.next/server/chunks/ssr/_1acy_2s._.js +158 -0
  87. package/.next/server/chunks/ssr/_1acy_2s._.js.map +1 -0
  88. package/.next/server/chunks/ssr/_1rh2tf9._.js +367 -0
  89. package/.next/server/chunks/ssr/_1rh2tf9._.js.map +1 -0
  90. package/.next/server/chunks/ssr/_next-internal_server_app__global-error_page_actions_0zi5s8-.js +3 -0
  91. package/.next/server/chunks/ssr/_next-internal_server_app__global-error_page_actions_0zi5s8-.js.map +1 -0
  92. package/.next/server/chunks/ssr/_next-internal_server_app__not-found_page_actions_0pt47yr.js +3 -0
  93. package/.next/server/chunks/ssr/_next-internal_server_app__not-found_page_actions_0pt47yr.js.map +1 -0
  94. package/.next/server/chunks/ssr/node_modules_01xbj_9._.js +33 -0
  95. package/.next/server/chunks/ssr/node_modules_01xbj_9._.js.map +1 -0
  96. package/.next/server/chunks/ssr/node_modules_next_dist_1c5ky4f._.js +3 -0
  97. package/.next/server/chunks/ssr/node_modules_next_dist_1c5ky4f._.js.map +1 -0
  98. package/.next/server/chunks/ssr/node_modules_next_dist_1n3w9lb._.js +6 -0
  99. package/.next/server/chunks/ssr/node_modules_next_dist_1n3w9lb._.js.map +1 -0
  100. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_0wpq8j3._.js +3 -0
  101. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_0wpq8j3._.js.map +1 -0
  102. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_forbidden_0symwr9.js +3 -0
  103. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_forbidden_0symwr9.js.map +1 -0
  104. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_global-error_0q-w892.js +3 -0
  105. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_global-error_0q-w892.js.map +1 -0
  106. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_unauthorized_0l_sp0x.js +3 -0
  107. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_unauthorized_0l_sp0x.js.map +1 -0
  108. package/.next/server/chunks/ssr/src_app_loading_tsx_01g_-m0._.js +3 -0
  109. package/.next/server/chunks/ssr/src_app_loading_tsx_01g_-m0._.js.map +1 -0
  110. package/.next/server/middleware-build-manifest.js +24 -1
  111. package/.next/server/middleware-manifest.json +2 -2
  112. package/.next/server/next-font-manifest.js +1 -1
  113. package/.next/server/next-font-manifest.json +15 -1
  114. package/.next/server/pages/404.html +1 -1
  115. package/.next/server/pages/500.html +1 -1
  116. package/.next/server/pages-manifest.json +2 -4
  117. package/.next/server/prefetch-hints.json +25 -0
  118. package/.next/server/server-reference-manifest.js +1 -1
  119. package/.next/server/server-reference-manifest.json +94 -1
  120. package/.next/static/chunks/0_j-_aavigxqr.js +345 -0
  121. package/.next/static/chunks/19mx3mg6lkumu.js +1 -0
  122. package/.next/static/chunks/1las_6j17xa9p.js +1 -0
  123. package/.next/static/chunks/1xk6snnh6e5_j.css +3 -0
  124. package/.next/static/chunks/2-rtuqsgzmno4.js +22 -0
  125. package/.next/static/chunks/27t_qfc-3_lzs.js +1 -0
  126. package/.next/static/chunks/310vm2bl3xxpt.js +31 -0
  127. package/.next/static/chunks/3fntmmi971322.js +1 -0
  128. package/.next/static/chunks/turbopack-1b6uko1cu_h42.js +1 -0
  129. package/.next/static/media/4fa387ec64143e14-s.2tuy5pz7dlieh.woff2 +0 -0
  130. package/.next/static/media/53b9e256198e5412-s.390ncx5urfkfu.woff2 +0 -0
  131. package/.next/static/media/5ce348bf30bf5439-s.31988l_ccedte.woff2 +0 -0
  132. package/.next/static/media/6306c77e7c8268e4-s.2dbetqa9o8jxf.woff2 +0 -0
  133. package/.next/static/media/7178b3e590c64307-s.21jp631_3pja2.woff2 +0 -0
  134. package/.next/static/media/797e433ab948586e-s.p.0r6juujl39pe6.woff2 +0 -0
  135. package/.next/static/media/7d817b4c03b0c5f1-s.1uyisp29ctx0d.woff2 +0 -0
  136. package/.next/static/media/8a480f0b521d4e75-s.1qq4vpdcun5oj.woff2 +0 -0
  137. package/.next/static/media/bbc41e54d2fcbd21-s.1rgnod-3esatf.woff2 +0 -0
  138. package/.next/static/media/caa3a2e1cccd8315-s.p.0wgildi0cnwt9.woff2 +0 -0
  139. package/.next/static/media/favicon.2246eezznj2ab.ico +0 -0
  140. package/.next/static/media/fef07dbb0973bf53-s.3p2_lha1f2xer.woff2 +0 -0
  141. package/.next/static/qznDSVYlkQxVdRx-TE_Wk/_buildManifest.js +11 -0
  142. package/.next/static/qznDSVYlkQxVdRx-TE_Wk/_clientMiddlewareManifest.js +1 -0
  143. package/README.md +176 -4
  144. package/bin/pkgviz.ts +57 -29
  145. package/package.json +57 -36
  146. package/src/app/actions/audit.actions.ts +7 -49
  147. package/src/app/globals.css +0 -2
  148. package/src/app/layout.tsx +3 -2
  149. package/src/app/loading.tsx +8 -0
  150. package/src/app/page.tsx +16 -2
  151. package/src/app/utils/buildGraph.ts +99 -100
  152. package/src/app/utils/getParsedFileStructure.ts +128 -54
  153. package/src/app/utils/inspectParserLanguageAsync.ts +39 -0
  154. package/src/app/utils/markCyclicPackages.ts +45 -185
  155. package/src/app/utils/parser/cpp/parseCppFile.ts +68 -86
  156. package/src/app/utils/parser/delphi/parseFile.ts +36 -120
  157. package/src/app/utils/parser/java/findEntryPoint.ts +2 -1
  158. package/src/app/utils/parser/java/parseJavaFile.ts +33 -45
  159. package/src/app/utils/parser/kotlin/parseFile.ts +34 -87
  160. package/src/app/utils/parser/python/parseFile.ts +30 -100
  161. package/src/app/utils/parser/typescript/parseFile.ts +17 -52
  162. package/src/app/utils/selectParserLanguage.ts +39 -0
  163. package/src/cli/formatAuditRuleFailures.ts +21 -0
  164. package/src/cli/runAuditAsync.ts +41 -0
  165. package/src/components/Breadcrumb.tsx +5 -4
  166. package/src/components/ExportPanel.tsx +53 -0
  167. package/src/components/Header.tsx +1 -0
  168. package/src/components/Loader.tsx +8 -2
  169. package/src/components/ProjectLoadError.tsx +15 -0
  170. package/src/components/SettingsPanel.tsx +184 -0
  171. package/src/components/Switch.tsx +9 -17
  172. package/src/components/ThemeToggle.tsx +2 -1
  173. package/src/components/ToggleSwitch.tsx +36 -0
  174. package/src/components/sidebar/Sidebar.tsx +14 -0
  175. package/src/components/sidebar/SidebarBadge.tsx +25 -0
  176. package/src/components/sidebar/SidebarRow.tsx +14 -0
  177. package/src/components/sidebar/SidebarSection.tsx +16 -0
  178. package/src/components/sidebar/SidebarTabs.tsx +58 -0
  179. package/src/contexts/SettingsContext.tsx +19 -20
  180. package/src/features/audit/adapters/inbound/react/AuditRuleList.tsx +76 -0
  181. package/src/features/audit/adapters/inbound/react/AuditRulePanel.tsx +30 -0
  182. package/src/features/audit/adapters/inbound/react/CycleInspector.tsx +116 -0
  183. package/src/features/audit/adapters/inbound/react/CyclicDependenciesRuleDetails.tsx +124 -0
  184. package/src/features/audit/adapters/inbound/react/useCycleSelection.ts +47 -0
  185. package/src/features/audit/application/use-cases/createAuditFromSnapshot.ts +28 -0
  186. package/src/features/audit/application/use-cases/resolveSelectedCycleIds.ts +18 -0
  187. package/src/features/audit/composition/createAuditAsync.ts +11 -0
  188. package/src/features/audit/domain/evaluateAuditRules.ts +42 -0
  189. package/src/features/audit/domain/hasBlockingAuditRuleFailure.ts +6 -0
  190. package/src/features/audit/domain/resolveAuditConfiguration.ts +27 -0
  191. package/src/features/audit/utils/cycleVisualization.ts +86 -0
  192. package/src/features/dependency-analysis/adapters/outbound/dependency-graph/analyzeDependencyImportsAsync.ts +172 -0
  193. package/src/features/dependency-analysis/adapters/outbound/dependency-graph/analyzeTypeScriptImportsAsync.ts +6 -0
  194. package/src/features/graph-view/adapters/inbound/react/DependencyGraphView.tsx +184 -0
  195. package/src/features/graph-view/adapters/inbound/react/GraphZoomControls.tsx +48 -0
  196. package/src/features/graph-view/adapters/inbound/react/applyGraphInteractionPresentation.ts +35 -0
  197. package/src/features/graph-view/adapters/inbound/react/createGraphViewModel.ts +240 -0
  198. package/src/features/graph-view/adapters/inbound/react/createGraphViewStyles.ts +37 -0
  199. package/src/features/graph-view/adapters/inbound/react/useGraphFocus.ts +104 -0
  200. package/src/features/graph-view/adapters/inbound/react/useGraphInteractions.ts +50 -0
  201. package/src/features/graph-view/adapters/inbound/react/useGraphProjection.ts +71 -0
  202. package/src/features/graph-view/adapters/inbound/react/useGraphViewport.ts +48 -0
  203. package/src/features/graph-view/domain/getDependencyHighlightClasses.ts +39 -0
  204. package/src/features/graph-view/domain/reduceGraphInteraction.ts +23 -0
  205. package/src/features/graph-view/utils/createCompoundOpacityIndex.ts +38 -0
  206. package/src/features/graph-view/utils/projectVisibleGraph.ts +109 -0
  207. package/src/features/graph-view/utils/readNodeDefinitionId.ts +7 -0
  208. package/src/features/graph-view/utils/removeEmptyStructuralNodes.ts +27 -0
  209. package/src/features/project-analysis/adapters/outbound/filesystem/readProjectSnapshotAsync.ts +12 -0
  210. package/src/features/project-analysis/application/use-cases/createProjectSnapshotReader.ts +29 -0
  211. package/src/features/project-analysis/composition/loadProjectOverviewAsync.ts +14 -0
  212. package/src/features/project-analysis/composition/loadProjectSnapshotAsync.ts +12 -0
  213. package/src/features/project-tree/adapters/inbound/react/ProjectTreePanel.tsx +52 -0
  214. package/src/features/project-tree/adapters/inbound/react/useProjectTreeExpansion.ts +46 -0
  215. package/src/features/project-tree/application/use-cases/buildProjectTree.ts +61 -0
  216. package/src/features/project-tree/application/use-cases/resolveProjectTreeNavigation.ts +13 -0
  217. package/src/features/project-tree/utils/findProjectTreeNode.ts +14 -0
  218. package/src/features/project-tree/utils/findProjectTreeNodeByGraphPackage.ts +21 -0
  219. package/src/features/project-tree/utils/getProjectTreeAncestorIds.ts +26 -0
  220. package/src/features/settings/utils/readSettingsEnvironment.ts +53 -0
  221. package/src/i18n/en.ts +21 -2
  222. package/src/i18n/i18n.ts +2 -3
  223. package/src/layouts/breadthfirst/style.ts +1 -0
  224. package/src/layouts/circle/style.ts +1 -0
  225. package/src/layouts/concentric/style.ts +1 -0
  226. package/src/layouts/elk/layout.ts +1 -3
  227. package/src/layouts/elk/style.ts +1 -0
  228. package/src/layouts/getWeightBuckets.ts +3 -1
  229. package/src/layouts/grid/style.ts +1 -0
  230. package/src/layouts/index.ts +0 -4
  231. package/src/layouts/style.ts +172 -25
  232. package/src/screens/home/Home.tsx +73 -25
  233. package/src/screens/home/HomeGraph.tsx +43 -0
  234. package/src/screens/home/HomeSidebar.tsx +129 -0
  235. package/src/shared/types/index.ts +0 -9
  236. package/src/shared/utils/getProjectName.ts +4 -1
  237. package/src/shared/utils/parseProjectPath.ts +1 -0
  238. package/src/shared/utils/toPosix.ts +1 -1
  239. package/src/types/audit.ts +76 -0
  240. package/src/types/auditVisualization.ts +22 -0
  241. package/src/types/graphInteraction.ts +9 -0
  242. package/src/types/parserSelection.ts +11 -0
  243. package/src/types/projectAnalysis.ts +20 -0
  244. package/src/types/projectAnalysisActionResult.ts +2 -0
  245. package/src/types/projectTree.ts +7 -0
  246. package/src/utils/filter/filterByPackagePrefix.ts +25 -7
  247. package/src/utils/filter/filterEmptyPackages.ts +28 -29
  248. package/src/utils/filter/filterSubPackagesFromDepth.ts +20 -17
  249. package/src/utils/filter/filterVendorPackages.ts +1 -1
  250. package/src/utils/filter/isIntrinsicGraphNode.ts +8 -0
  251. package/src/utils/filter/toggleCompoundNodes.ts +41 -31
  252. package/src/utils/runProjectAnalysisActionAsync.ts +14 -0
  253. package/tsconfig.json +11 -3
  254. package/.next/app-build-manifest.json +0 -29
  255. package/.next/cache/.previewinfo +0 -1
  256. package/.next/cache/.rscinfo +0 -1
  257. package/.next/cache/.tsbuildinfo +0 -1
  258. package/.next/cache/chrome-devtools-workspace-uuid +0 -1
  259. package/.next/cache/eslint/.cache_6t30dc +0 -1
  260. package/.next/cache/webpack/client-production/0.pack +0 -4
  261. package/.next/cache/webpack/client-production/1.pack +0 -0
  262. package/.next/cache/webpack/client-production/10.pack +0 -0
  263. package/.next/cache/webpack/client-production/11.pack +0 -0
  264. package/.next/cache/webpack/client-production/12.pack +0 -0
  265. package/.next/cache/webpack/client-production/13.pack +0 -0
  266. package/.next/cache/webpack/client-production/14.pack +0 -0
  267. package/.next/cache/webpack/client-production/15.pack +0 -0
  268. package/.next/cache/webpack/client-production/16.pack +0 -0
  269. package/.next/cache/webpack/client-production/2.pack +0 -0
  270. package/.next/cache/webpack/client-production/3.pack +0 -0
  271. package/.next/cache/webpack/client-production/4.pack +0 -0
  272. package/.next/cache/webpack/client-production/5.pack +0 -0
  273. package/.next/cache/webpack/client-production/6.pack +0 -0
  274. package/.next/cache/webpack/client-production/7.pack +0 -0
  275. package/.next/cache/webpack/client-production/8.pack +0 -0
  276. package/.next/cache/webpack/client-production/9.pack +0 -0
  277. package/.next/cache/webpack/client-production/index.pack +0 -0
  278. package/.next/cache/webpack/client-production/index.pack.old +0 -0
  279. package/.next/cache/webpack/edge-server-production/0.pack +0 -0
  280. package/.next/cache/webpack/edge-server-production/index.pack +0 -0
  281. package/.next/cache/webpack/edge-server-production/index.pack.old +0 -0
  282. package/.next/cache/webpack/server-production/0.pack +0 -0
  283. package/.next/cache/webpack/server-production/1.pack +0 -0
  284. package/.next/cache/webpack/server-production/10.pack +0 -4
  285. package/.next/cache/webpack/server-production/11.pack +0 -0
  286. package/.next/cache/webpack/server-production/12.pack +0 -0
  287. package/.next/cache/webpack/server-production/13.pack +0 -0
  288. package/.next/cache/webpack/server-production/14.pack +0 -0
  289. package/.next/cache/webpack/server-production/15.pack +0 -0
  290. package/.next/cache/webpack/server-production/16.pack +0 -0
  291. package/.next/cache/webpack/server-production/17.pack +0 -0
  292. package/.next/cache/webpack/server-production/18.pack +0 -4
  293. package/.next/cache/webpack/server-production/2.pack +0 -0
  294. package/.next/cache/webpack/server-production/3.pack +0 -0
  295. package/.next/cache/webpack/server-production/4.pack +0 -0
  296. package/.next/cache/webpack/server-production/5.pack +0 -0
  297. package/.next/cache/webpack/server-production/6.pack +0 -0
  298. package/.next/cache/webpack/server-production/7.pack +0 -0
  299. package/.next/cache/webpack/server-production/8.pack +0 -0
  300. package/.next/cache/webpack/server-production/9.pack +0 -0
  301. package/.next/cache/webpack/server-production/index.pack +0 -0
  302. package/.next/cache/webpack/server-production/index.pack.old +0 -0
  303. package/.next/diagnostics/build-diagnostics.json +0 -6
  304. package/.next/diagnostics/framework.json +0 -1
  305. package/.next/server/app/index.html +0 -1
  306. package/.next/server/app/index.meta +0 -7
  307. package/.next/server/app/index.rsc +0 -20
  308. package/.next/server/chunks/548.js +0 -6
  309. package/.next/server/chunks/610.js +0 -7
  310. package/.next/server/chunks/985.js +0 -22
  311. package/.next/server/middleware-react-loadable-manifest.js +0 -1
  312. package/.next/server/pages/_app.js +0 -1
  313. package/.next/server/pages/_app.js.nft.json +0 -1
  314. package/.next/server/pages/_document.js +0 -1
  315. package/.next/server/pages/_document.js.nft.json +0 -1
  316. package/.next/server/pages/_error.js +0 -19
  317. package/.next/server/pages/_error.js.nft.json +0 -1
  318. package/.next/server/webpack-runtime.js +0 -1
  319. package/.next/static/_YC2p40ZiYT2Gcw-h_tjC/_buildManifest.js +0 -1
  320. package/.next/static/chunks/4bd1b696-cf72ae8a39fa05aa.js +0 -1
  321. package/.next/static/chunks/680-55ad17895c8fb70b.js +0 -1
  322. package/.next/static/chunks/90542734-29e255269788f1bd.js +0 -1
  323. package/.next/static/chunks/91dbc596-b9cdccd3f5cba95d.js +0 -1
  324. package/.next/static/chunks/964-b440f7af22c41ca5.js +0 -1
  325. package/.next/static/chunks/app/_not-found/page-11e4fea8e290f304.js +0 -1
  326. package/.next/static/chunks/app/layout-8aae7fba5ed8afb3.js +0 -1
  327. package/.next/static/chunks/app/page-91450b1230da8bca.js +0 -1
  328. package/.next/static/chunks/framework-bc35dade6ff9684e.js +0 -1
  329. package/.next/static/chunks/main-9e86d333c1e02dd1.js +0 -1
  330. package/.next/static/chunks/main-app-69a9ff75ff3465ca.js +0 -1
  331. package/.next/static/chunks/pages/_app-0a0020ddd67f79cf.js +0 -1
  332. package/.next/static/chunks/pages/_error-03529f2c21436739.js +0 -1
  333. package/.next/static/chunks/webpack-7adfafc806738767.js +0 -1
  334. package/.next/static/css/ec31779168107a11.css +0 -3
  335. package/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
  336. package/.next/static/media/747892c23ea88013-s.woff2 +0 -0
  337. package/.next/static/media/8d697b304b401681-s.woff2 +0 -0
  338. package/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
  339. package/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
  340. package/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
  341. package/.next/trace +0 -2
  342. package/.next/types/app/layout.ts +0 -84
  343. package/.next/types/app/page.ts +0 -84
  344. package/.next/types/cache-life.d.ts +0 -141
  345. package/.next/types/package.json +0 -1
  346. package/src/app/actions/graph.actions.ts +0 -25
  347. package/src/app/utils/parser/cpp/extractCppPackageFromImport.ts +0 -18
  348. package/src/app/utils/parser/delphi/extractPackageFromImport.ts +0 -21
  349. package/src/app/utils/parser/java/extractJavaPackageFromImport.ts +0 -39
  350. package/src/app/utils/parser/java/getIntrinsicPackagesRecursive.ts +0 -33
  351. package/src/app/utils/parser/kotlin/extractPackageFromImport.ts +0 -19
  352. package/src/app/utils/parser/python/extractPythonPackageFromImport.ts +0 -18
  353. package/src/app/utils/parser/typescript/extractTypeScriptPackageFromImport.ts +0 -18
  354. package/src/components/Cytoscape.tsx +0 -23
  355. package/src/components/Setting.tsx +0 -17
  356. package/src/components/Settings.tsx +0 -189
  357. package/src/components/ZoomInput.tsx +0 -94
  358. package/src/components/useCytoscape.ts +0 -343
  359. package/src/layouts/getLayoutStyle.ts +0 -19
  360. package/src/shared/utils/detectLanguage.ts +0 -255
  361. package/src/shared/utils/getJsonAsync.ts +0 -13
  362. package/src/shared/utils/parseEnv.ts +0 -91
  363. package/src/store/useLocalStorage.ts +0 -29
  364. package/src/utils/hasChildren.ts +0 -7
  365. /package/.next/{react-loadable-manifest.json → server/app/_global-error/page/react-loadable-manifest.json} +0 -0
  366. /package/.next/static/chunks/{polyfills-42372ed130431b0a.js → 0cz1d0mv5g_q7.js} +0 -0
  367. /package/.next/static/{_YC2p40ZiYT2Gcw-h_tjC → qznDSVYlkQxVdRx-TE_Wk}/_ssgManifest.js +0 -0
@@ -1,48 +1,96 @@
1
1
  'use client';
2
- import type { ElementsDefinition } from 'cytoscape';
2
+ import { useState } from 'react';
3
3
 
4
- import { useEffect, useState } from 'react';
5
- import { getGraphAction } from '@/app/actions/graph.actions';
6
4
  import Breadcrumb from '@/components/Breadcrumb';
7
5
  import Header from '@/components/Header';
8
- import Loader from '@/components/Loader';
9
- import Settings from '@/components/Settings';
10
- import { Cytoscape } from '@/components/Cytoscape';
6
+ import ProjectLoadError from '@/components/ProjectLoadError';
11
7
  import { SettingsProvider } from '@/contexts/SettingsContext';
8
+ import { useCycleSelection } from '@/features/audit/adapters/inbound/react/useCycleSelection';
9
+ import { resolveProjectTreeNavigation } from '@/features/project-tree/application/use-cases/resolveProjectTreeNavigation';
10
+ import { findProjectTreeNodeByGraphPackage } from '@/features/project-tree/utils/findProjectTreeNodeByGraphPackage';
11
+ import { HomeGraph } from '@/screens/home/HomeGraph';
12
+ import { HomeSidebar } from '@/screens/home/HomeSidebar';
13
+ import type { Audit } from '@/types/audit';
14
+ import type { CycleInspection } from '@/types/auditVisualization';
15
+ import type { ProjectOverview } from '@/types/projectAnalysis';
16
+ import type { ProjectAnalysisActionResult } from '@/types/projectAnalysisActionResult';
17
+ import type { ProjectTreeNode } from '@/types/projectTree';
12
18
 
13
- export default function HomeScreen() {
19
+ /*** Renders the PKGViz home screen and composes project navigation, diagnostics, and the graph. */
20
+ export default function HomeScreen({ project }: HomeScreenProps) {
14
21
  const [currentPackage, setCurrentPackage] = useState<string>('');
15
- const [packageGraph, setPackageGraph] = useState<ElementsDefinition | null>(null);
22
+ const packageGraph = project.ok ? project.value.graph : null;
23
+ const projectTree = project.ok ? project.value.tree : [];
24
+ const [selectedTreeId, setSelectedTreeId] = useState<string | null>(null);
25
+ const auditEvaluation = project.ok ? project.value.evaluation : null;
26
+ const projectError = project.ok ? null : project.error;
27
+ const cycleSelection = useCycleSelection(auditEvaluation?.cyclicPackages ?? EMPTY_CYCLES);
28
+ const [cycleInspection, setCycleInspection] = useState<CycleInspection | null>(null);
16
29
 
17
- useEffect(() => {
18
- if (!packageGraph) {
19
- getGraphAction().then(setPackageGraph);
20
- }
21
- }, [packageGraph]);
30
+ /*** Navigates graph scope and mirrors the matching package selection in the project tree. */
31
+ const navigateToPackage = (path: string) => {
32
+ const packageName = normalizeGraphPackage(path);
33
+ const matchingTreeNode = findProjectTreeNodeByGraphPackage(projectTree, packageName);
34
+ setCurrentPackage(packageName);
35
+ setSelectedTreeId(matchingTreeNode?.id ?? null);
36
+ };
37
+
38
+ /*** Navigates only into packages with graph descendants; selecting a leaf keeps the current view. */
39
+ const selectProjectTreeNode = (node: ProjectTreeNode) => {
40
+ setSelectedTreeId(node.id);
41
+ setCurrentPackage(
42
+ resolveProjectTreeNavigation(
43
+ node,
44
+ packageGraph?.nodes.map(candidate => String(candidate.data.id ?? '')) ?? [],
45
+ currentPackage
46
+ )
47
+ );
48
+ };
22
49
 
23
50
  return (
24
51
  <>
25
52
  <Header title="nav.packages">
26
- <Breadcrumb
27
- path={currentPackage.replace(/\./g, '/')}
28
- onNavigate={(path: string) => setCurrentPackage(path.replace(/\//g, '.'))}
29
- />
53
+ <Breadcrumb path={currentPackage.replace(/\./g, '/')} onNavigate={navigateToPackage} />
30
54
  </Header>
31
-
32
55
  <SettingsProvider>
33
- <main data-testid="main" className="flex flex-1 flex-row dark:bg-[#171717]">
34
- <Settings />
35
- {packageGraph ? (
36
- <Cytoscape
56
+ <main
57
+ data-testid="main"
58
+ className="flex min-h-0 min-w-0 flex-1 flex-row overflow-hidden dark:bg-[#171717]"
59
+ >
60
+ <HomeSidebar
61
+ evaluation={auditEvaluation}
62
+ projectTree={projectTree}
63
+ selectedTreeId={selectedTreeId}
64
+ onProjectTreeSelect={selectProjectTreeNode}
65
+ cycleSelection={cycleSelection}
66
+ inspectedCycleId={cycleInspection?.id ?? null}
67
+ onCycleInspectionChange={setCycleInspection}
68
+ />
69
+ {projectError ? (
70
+ <ProjectLoadError message={projectError} />
71
+ ) : (
72
+ <HomeGraph
37
73
  currentPackage={currentPackage}
38
- setCurrentPackage={setCurrentPackage}
74
+ cycleHighlights={cycleSelection.highlights}
75
+ cycleInspection={cycleInspection}
39
76
  packageGraph={packageGraph}
77
+ setCurrentPackage={navigateToPackage}
78
+ onCloseInspection={() => setCycleInspection(null)}
40
79
  />
41
- ) : (
42
- <Loader />
43
80
  )}
44
81
  </main>
45
82
  </SettingsProvider>
46
83
  </>
47
84
  );
48
85
  }
86
+
87
+ const EMPTY_CYCLES: NonNullable<Audit['evaluation']>['cyclicPackages'] = [];
88
+
89
+ interface HomeScreenProps {
90
+ readonly project: ProjectAnalysisActionResult<ProjectOverview>;
91
+ }
92
+
93
+ /*** Normalizes graph navigation paths to the package-id representation used by Cytoscape. */
94
+ function normalizeGraphPackage(path: string): string {
95
+ return path.replaceAll('/', '.').replace(/^\.+|\.+$/g, '');
96
+ }
@@ -0,0 +1,43 @@
1
+ 'use client';
2
+ import type { ElementsDefinition } from 'cytoscape';
3
+ import React from 'react';
4
+
5
+ import Loader from '@/components/Loader';
6
+ import { CycleInspector } from '@/features/audit/adapters/inbound/react/CycleInspector';
7
+ import { DependencyGraphView } from '@/features/graph-view/adapters/inbound/react/DependencyGraphView';
8
+ import type { CycleHighlight, CycleInspection } from '@/types/auditVisualization';
9
+
10
+ /*** Renders the graph surface together with its optional cycle inspector overlay. */
11
+ export function HomeGraph({
12
+ currentPackage,
13
+ cycleHighlights,
14
+ cycleInspection,
15
+ packageGraph,
16
+ setCurrentPackage,
17
+ onCloseInspection,
18
+ }: HomeGraphProps) {
19
+ if (!packageGraph) return <Loader />;
20
+
21
+ return (
22
+ <DependencyGraphView
23
+ currentPackage={currentPackage}
24
+ setCurrentPackage={setCurrentPackage}
25
+ packageGraph={packageGraph}
26
+ cycleHighlights={cycleHighlights}
27
+ overlay={
28
+ cycleInspection === null ? null : (
29
+ <CycleInspector inspection={cycleInspection} onClose={onCloseInspection} />
30
+ )
31
+ }
32
+ />
33
+ );
34
+ }
35
+
36
+ interface HomeGraphProps {
37
+ readonly currentPackage: string;
38
+ readonly cycleHighlights: readonly CycleHighlight[];
39
+ readonly cycleInspection: CycleInspection | null;
40
+ readonly packageGraph: ElementsDefinition | null;
41
+ readonly setCurrentPackage: (path: string) => void;
42
+ readonly onCloseInspection: () => void;
43
+ }
@@ -0,0 +1,129 @@
1
+ 'use client';
2
+ import React from 'react';
3
+
4
+ import { ExportPanel } from '@/components/ExportPanel';
5
+ import { SettingsPanel } from '@/components/SettingsPanel';
6
+ import { Sidebar } from '@/components/sidebar/Sidebar';
7
+ import { SidebarTabs } from '@/components/sidebar/SidebarTabs';
8
+ import { AuditRulePanel } from '@/features/audit/adapters/inbound/react/AuditRulePanel';
9
+ import { ProjectTreePanel } from '@/features/project-tree/adapters/inbound/react/ProjectTreePanel';
10
+ import { t } from '@/i18n/i18n';
11
+ import type { Audit } from '@/types/audit';
12
+ import type { CycleInspection, CycleSelection } from '@/types/auditVisualization';
13
+ import type { ProjectTreeNode } from '@/types/projectTree';
14
+
15
+ /*** Composes Tree, Rules, and Export above persistent graph settings. */
16
+ export function HomeSidebar(props: HomeSidebarProps) {
17
+ const [activeTool, setActiveTool] = React.useState<string | null>('tree');
18
+
19
+ /*** Closes the evidence panel without changing the user's cycle visualization choices. */
20
+ const selectTool = (value: string) => {
21
+ if (activeTool === 'rules' && value !== 'rules') {
22
+ props.onCycleInspectionChange(null);
23
+ }
24
+ setActiveTool(value);
25
+ };
26
+
27
+ return (
28
+ <Sidebar>
29
+ <SidebarToolTabs
30
+ activeTool={activeTool}
31
+ evaluation={props.evaluation}
32
+ cycleSelection={props.cycleSelection}
33
+ inspectedCycleId={props.inspectedCycleId}
34
+ onCycleInspectionChange={props.onCycleInspectionChange}
35
+ onProjectTreeSelect={props.onProjectTreeSelect}
36
+ onValueChange={selectTool}
37
+ projectTree={props.projectTree}
38
+ selectedTreeId={props.selectedTreeId}
39
+ />
40
+ <div className="shrink-0">
41
+ <SettingsPanel />
42
+ </div>
43
+ </Sidebar>
44
+ );
45
+ }
46
+
47
+ /*** Renders project-tree navigation together with secondary Rules and Export tools. */
48
+ function SidebarToolTabs({
49
+ activeTool,
50
+ evaluation,
51
+ cycleSelection,
52
+ inspectedCycleId,
53
+ onCycleInspectionChange,
54
+ onProjectTreeSelect,
55
+ onValueChange,
56
+ projectTree,
57
+ selectedTreeId,
58
+ }: SidebarToolTabsProps) {
59
+ const violatedRuleCount = evaluation?.rules.filter(rule => rule.status === 'failed').length ?? 0;
60
+ const findingCount =
61
+ evaluation?.rules
62
+ .filter(rule => rule.status === 'failed')
63
+ .reduce(
64
+ (count, rule) =>
65
+ count +
66
+ (rule.id === 'cyclic-dependencies'
67
+ ? evaluation.cyclicPackages.length
68
+ : rule.details.length),
69
+ 0
70
+ ) ?? 0;
71
+
72
+ return (
73
+ <SidebarTabs
74
+ ariaLabel={t('sidebar.tools')}
75
+ value={activeTool}
76
+ onValueChange={onValueChange}
77
+ tabs={[
78
+ {
79
+ id: 'tree',
80
+ label: t('settings.tree'),
81
+ content: (
82
+ <ProjectTreePanel
83
+ nodes={projectTree}
84
+ selectedId={selectedTreeId}
85
+ onSelect={onProjectTreeSelect}
86
+ />
87
+ ),
88
+ },
89
+ {
90
+ id: 'rules',
91
+ label: `${t('settings.rules')} · ${findingCount} ${t('audit.findings')}`,
92
+ disabled: violatedRuleCount === 0,
93
+ content:
94
+ evaluation === null ? null : (
95
+ <AuditRulePanel
96
+ evaluation={evaluation}
97
+ cycleSelection={cycleSelection}
98
+ inspectedCycleId={inspectedCycleId}
99
+ onCycleInspectionChange={onCycleInspectionChange}
100
+ />
101
+ ),
102
+ },
103
+ { id: 'export', label: t('settings.export'), content: <ExportPanel /> },
104
+ ]}
105
+ />
106
+ );
107
+ }
108
+
109
+ interface HomeSidebarProps {
110
+ readonly inspectedCycleId: string | null;
111
+ readonly evaluation: Audit['evaluation'] | null;
112
+ readonly projectTree: readonly ProjectTreeNode[];
113
+ readonly selectedTreeId: string | null;
114
+ readonly onProjectTreeSelect: (node: ProjectTreeNode) => void;
115
+ readonly cycleSelection: CycleSelection;
116
+ readonly onCycleInspectionChange: (inspection: CycleInspection | null) => void;
117
+ }
118
+
119
+ interface SidebarToolTabsProps {
120
+ readonly inspectedCycleId: string | null;
121
+ readonly activeTool: string | null;
122
+ readonly evaluation: Audit['evaluation'] | null;
123
+ readonly cycleSelection: CycleSelection;
124
+ readonly onCycleInspectionChange: (inspection: CycleInspection | null) => void;
125
+ readonly onProjectTreeSelect: (node: ProjectTreeNode) => void;
126
+ readonly onValueChange: (value: string) => void;
127
+ readonly projectTree: readonly ProjectTreeNode[];
128
+ readonly selectedTreeId: string | null;
129
+ }
@@ -15,15 +15,6 @@ export enum Language {
15
15
  Unknown = 'unknown',
16
16
  }
17
17
 
18
- /**
19
- * Language Detection Result
20
- */
21
- export interface LanguageDetectionResult {
22
- language: Language;
23
- confidence: number;
24
- indicators: string[];
25
- }
26
-
27
18
  //////////////////////////////////////////////////////////////////////////
28
19
  // Parser Types
29
20
 
@@ -1,3 +1,6 @@
1
1
  import { parseProjectPath } from '@/shared/utils/parseProjectPath';
2
+ import { toPosix } from '@/shared/utils/toPosix';
2
3
 
3
- export const getProjectName = () => parseProjectPath().split('/').pop() || '{unknown}';
4
+ /*** Returns the project name for an explicit or configured project path. */
5
+ export const getProjectName = (projectPath: string = parseProjectPath()) =>
6
+ toPosix(projectPath).split('/').pop() || '{unknown}';
@@ -1,5 +1,6 @@
1
1
  import { toPosix } from '@/shared/utils/toPosix';
2
2
 
3
+ /*** Returns the configured project path in POSIX form. */
3
4
  export const parseProjectPath = () => {
4
5
  const projectPath = process.env.NEXT_PUBLIC_PROJECT_PATH;
5
6
  if (!projectPath) throw new Error('Missing ENV: NEXT_PUBLIC_PROJECT_PATH');
@@ -1,4 +1,4 @@
1
- /**
1
+ /***
2
2
  * Converts Windows-style backslashes in a file path to POSIX-style forward slashes.
3
3
  * @example 'C:\\Users\\User\\Documents\\Project' => 'C:/Users/User/Documents/Project'
4
4
  */
@@ -0,0 +1,76 @@
1
+ import type { ParsedDirectory } from '@/shared/types';
2
+ import type { ParserSelection } from '@/types/parserSelection';
3
+
4
+ type AuditRuleMode = 'audit' | 'block' | 'off';
5
+ type AuditRulePolicy = 'advisory' | 'blocking';
6
+ type AuditRuleStatus = 'failed' | 'passed';
7
+
8
+ export interface AuditRuleConfiguration {
9
+ readonly id: string;
10
+ readonly mode: AuditRuleMode;
11
+ }
12
+
13
+ export interface AuditConfiguration {
14
+ readonly failOnRuleViolation: boolean;
15
+ readonly rules: readonly AuditRuleConfiguration[];
16
+ }
17
+
18
+ export interface ResolveAuditConfigurationInput {
19
+ readonly failOnRuleViolation?: boolean;
20
+ readonly rules?: readonly AuditRuleConfiguration[];
21
+ }
22
+
23
+ export interface ImportEvidence {
24
+ readonly filePath: string;
25
+ readonly fileClass: string;
26
+ readonly importName: string;
27
+ readonly isIntrinsic?: boolean;
28
+ }
29
+
30
+ export interface CycleEdgeEvidence {
31
+ readonly from: string;
32
+ readonly to: string;
33
+ readonly via: readonly ImportEvidence[];
34
+ }
35
+
36
+ export interface PackageCycleDetail {
37
+ readonly packages: readonly string[];
38
+ readonly edges: readonly CycleEdgeEvidence[];
39
+ }
40
+
41
+ export interface AuditRuleResult<TEvidence = unknown> {
42
+ readonly id: string;
43
+ readonly status: AuditRuleStatus;
44
+ readonly policy: AuditRulePolicy;
45
+ readonly message: string;
46
+ readonly details: readonly string[];
47
+ readonly evidence: TEvidence;
48
+ }
49
+
50
+ export interface CyclicDependenciesEvidence {
51
+ readonly cycles: readonly PackageCycleDetail[];
52
+ }
53
+
54
+ interface AuditEvaluation {
55
+ readonly cyclicPackages: readonly PackageCycleDetail[];
56
+ readonly rules: readonly AuditRuleResult[];
57
+ }
58
+
59
+ interface AuditMeta {
60
+ readonly timeEnd: number;
61
+ readonly timeStart: number;
62
+ readonly language: ParserSelection;
63
+ readonly projectName: string;
64
+ }
65
+
66
+ export interface Audit {
67
+ readonly configuration: AuditConfiguration;
68
+ readonly evaluation: AuditEvaluation;
69
+ readonly meta: AuditMeta;
70
+ readonly files: ParsedDirectory;
71
+ }
72
+
73
+ export interface EvaluateAuditRulesInput {
74
+ readonly configuration: AuditConfiguration;
75
+ readonly cyclicPackages: readonly PackageCycleDetail[];
76
+ }
@@ -0,0 +1,22 @@
1
+ import type { PackageCycleDetail } from '@/types/audit';
2
+
3
+ export interface CycleHighlight {
4
+ readonly id: string;
5
+ readonly color: string;
6
+ readonly cycle: PackageCycleDetail;
7
+ }
8
+
9
+ export interface CycleInspection extends CycleHighlight {
10
+ readonly label: string;
11
+ }
12
+
13
+ export interface CycleFocus {
14
+ readonly currentPackage: string;
15
+ readonly packageDepth: number;
16
+ }
17
+
18
+ export interface CycleSelection {
19
+ readonly highlights: readonly CycleHighlight[];
20
+ readonly selectedIds: readonly string[];
21
+ readonly setSelected: (id: string, selected: boolean) => void;
22
+ }
@@ -0,0 +1,9 @@
1
+ export interface GraphInteractionState {
2
+ readonly hoveredNodeId: string | null;
3
+ readonly selectedNodeIds: readonly string[];
4
+ }
5
+
6
+ export interface GraphInteractionEvent {
7
+ readonly id: string;
8
+ readonly type: 'pointer-enter' | 'pointer-leave' | 'select' | 'unselect';
9
+ }
@@ -0,0 +1,11 @@
1
+ import type { DetectedLanguage } from '@ankhorage/project-detector/types';
2
+
3
+ import type { Language } from '../shared/types';
4
+
5
+ /** pkgviz's parser choice, not a generic project's single language or a probability. */
6
+ export interface ParserSelection {
7
+ readonly language: Language;
8
+ readonly score: number;
9
+ readonly indicators: readonly string[];
10
+ readonly candidates: readonly DetectedLanguage[];
11
+ }
@@ -0,0 +1,20 @@
1
+ import type { ElementsDefinition } from 'cytoscape';
2
+
3
+ import type { ParsedDirectory } from '@/shared/types';
4
+ import type { Audit } from '@/types/audit';
5
+ import type { ParserSelection } from '@/types/parserSelection';
6
+ import type { ProjectTreeNode } from '@/types/projectTree';
7
+
8
+ export interface ProjectSnapshot {
9
+ readonly files: ParsedDirectory;
10
+ readonly graph: ElementsDefinition;
11
+ readonly language: ParserSelection;
12
+ readonly projectPath: string;
13
+ readonly timeStart: number;
14
+ }
15
+
16
+ export interface ProjectOverview {
17
+ readonly graph: ElementsDefinition;
18
+ readonly tree: readonly ProjectTreeNode[];
19
+ readonly evaluation: Audit['evaluation'];
20
+ }
@@ -0,0 +1,2 @@
1
+ export type ProjectAnalysisActionResult<T> =
2
+ { readonly ok: true; readonly value: T } | { readonly ok: false; readonly error: string };
@@ -0,0 +1,7 @@
1
+ export interface ProjectTreeNode {
2
+ readonly children?: readonly ProjectTreeNode[];
3
+ readonly graphPackage: string;
4
+ readonly id: string;
5
+ readonly kind: 'directory' | 'file';
6
+ readonly label: string;
7
+ }
@@ -1,16 +1,34 @@
1
+ import { isIntrinsicGraphNode } from '@/utils/filter/isIntrinsicGraphNode';
2
+
3
+ /***
4
+ * Filters project descendants while retaining their adjacent external dependency endpoints.
5
+ * @performance Use endpoint sets to retain adjacent vendors without per-vendor edge scans.
6
+ */
1
7
  export function filterByPackagePrefix(
2
8
  allElements: cytoscape.ElementsDefinition,
3
9
  packagePrefix: string
4
10
  ): cytoscape.ElementsDefinition {
5
- // PackageView entrypoint, no prefix
6
- if (!packagePrefix) return allElements;
11
+ const normalizedPrefix = packagePrefix.replace(/\.+$/, '');
12
+ if (!normalizedPrefix) return allElements;
7
13
 
8
- // Active filtering (subpackage view)
9
- const pkgPrefix = packagePrefix.endsWith('.') ? packagePrefix : packagePrefix + '.';
10
- const allowedNodes = allElements.nodes.filter(node => {
11
- return (node.data.id as string).startsWith(pkgPrefix);
14
+ const descendantPrefix = normalizedPrefix + '.';
15
+ const projectNodes = allElements.nodes.filter(node => {
16
+ const id = node.data.id ?? '';
17
+ return isIntrinsicGraphNode(node) && id.startsWith(descendantPrefix);
12
18
  });
13
-
19
+ const projectIds = new Set(projectNodes.map(node => node.data.id));
20
+ const connectedIds = new Set(
21
+ allElements.edges.flatMap(edge =>
22
+ projectIds.has(edge.data.source) || projectIds.has(edge.data.target)
23
+ ? [edge.data.source, edge.data.target]
24
+ : []
25
+ )
26
+ );
27
+ const allowedNodes = allElements.nodes.filter(
28
+ node =>
29
+ projectIds.has(node.data.id) ||
30
+ (!isIntrinsicGraphNode(node) && connectedIds.has(String(node.data.id)))
31
+ );
14
32
  const allowedNodeIds = new Set(allowedNodes.map(node => node.data.id));
15
33
  const allowedEdges = allElements.edges.filter(
16
34
  edge => allowedNodeIds.has(edge.data.source) && allowedNodeIds.has(edge.data.target)
@@ -1,36 +1,35 @@
1
- import { ElementsDefinition } from 'cytoscape';
1
+ import type { ElementsDefinition } from 'cytoscape';
2
2
 
3
- /**
4
- * Returns root package if only one inside, or '' (root folder)
5
- */
6
- function getRootPackage(elements: ElementsDefinition) {
7
- const rootPackages = elements.nodes.filter(n => {
8
- return !n.data.id?.includes('.');
9
- });
10
- return rootPackages.length > 1 ? '' : (rootPackages[0].data.id as string);
11
- }
3
+ import { isIntrinsicGraphNode } from '@/utils/filter/isIntrinsicGraphNode';
12
4
 
13
- /**
14
- * Filter empty packages from graph (skip to next interesting package)
5
+ /***
6
+ * Skips a unique chain of structural project packages, stopping before real dependency endpoints.
7
+ * @performance Use full-graph indexes: navigation must not depend on depth projection or vendors.
8
+ * Preserve real isolated leaves and branching packages rather than silently filtering them away.
15
9
  */
16
10
  export function filterEmptyPackages(currentPackage: string, elements: ElementsDefinition): string {
17
- const nodes = elements.nodes.map(n => n.data.id!); // Non-null assertion
18
-
19
- if (!currentPackage) return getRootPackage(elements);
20
-
21
- while (true) {
22
- const childPackages = nodes.filter(
23
- id =>
24
- id.startsWith(currentPackage + '.') &&
25
- id.split('.').length === currentPackage.split('.').length + 1
26
- );
27
-
28
- if (childPackages.length === 1) {
29
- currentPackage = childPackages[0];
30
- } else {
31
- break;
32
- }
11
+ const children = new Map<string, string[]>();
12
+ for (const node of elements.nodes.filter(isIntrinsicGraphNode)) {
13
+ const id = String(node.data.id ?? '');
14
+ if (!id) continue;
15
+ const boundary = id.lastIndexOf('.');
16
+ const parent = boundary < 0 ? '' : id.slice(0, boundary);
17
+ const siblings = children.get(parent) ?? [];
18
+ siblings.push(id);
19
+ children.set(parent, siblings);
33
20
  }
21
+ const connected = new Set(elements.edges.flatMap(edge => [edge.data.source, edge.data.target]));
22
+ return descend(currentPackage, children, connected);
23
+ }
34
24
 
35
- return currentPackage;
25
+ /*** Descends only when the next package is a relationship-free structural container. */
26
+ function descend(
27
+ scope: string,
28
+ children: ReadonlyMap<string, readonly string[]>,
29
+ connected: ReadonlySet<string>
30
+ ): string {
31
+ const candidates = children.get(scope) ?? [];
32
+ const next = candidates[0];
33
+ if (candidates.length !== 1 || !next || connected.has(next) || !children.has(next)) return scope;
34
+ return descend(next, children, connected);
36
35
  }