pkgviz 0.7.7 → 0.8.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 (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/19mx3mg6lkumu.js +1 -0
  121. package/.next/static/chunks/1las_6j17xa9p.js +1 -0
  122. package/.next/static/chunks/1xk6snnh6e5_j.css +3 -0
  123. package/.next/static/chunks/2-rtuqsgzmno4.js +22 -0
  124. package/.next/static/chunks/27t_qfc-3_lzs.js +1 -0
  125. package/.next/static/chunks/2sswp23h6zh08.js +345 -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/rjdzHqzPw2GCNhDbjcu0-/_buildManifest.js +11 -0
  142. package/.next/static/rjdzHqzPw2GCNhDbjcu0-/_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 +94 -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 → rjdzHqzPw2GCNhDbjcu0-}/_ssgManifest.js +0 -0
@@ -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
  }
@@ -1,6 +1,6 @@
1
1
  import type { EdgeDefinition, ElementsDefinition } from 'cytoscape';
2
2
 
3
- /**
3
+ /***
4
4
  * Compute the minimal set of "root" packages that have no ancestor in the list.
5
5
  * Example: ['x.y', 'x.y.z', 'a', 'a.c.x'] => ['a', 'x.y']
6
6
  */
@@ -16,7 +16,7 @@ function findRoots(packages: string[]): string[] {
16
16
  return roots;
17
17
  }
18
18
 
19
- /**
19
+ /***
20
20
  * Ascend from a package to its nearest ancestor that is in the `roots` set.
21
21
  */
22
22
  function nearestRoot(pkg: string, roots: Set<string>): string {
@@ -31,7 +31,7 @@ function nearestRoot(pkg: string, roots: Set<string>): string {
31
31
  return pkg;
32
32
  }
33
33
 
34
- /**
34
+ /***
35
35
  * Given a root and a leaf pkg, return the visible ancestor at `maxDepth`
36
36
  * under the root, preferring the deepest existing package <= target depth.
37
37
  *
@@ -59,7 +59,7 @@ function visibleAncestorForDepth(
59
59
  return root; // fallback
60
60
  }
61
61
 
62
- /**
62
+ /***
63
63
  * Global maximum depth across all roots.
64
64
  * Depth is counted relative to the nearest root: root=1, root.child=2, etc.
65
65
  */
@@ -79,7 +79,7 @@ export function getMaxDepth(elements: ElementsDefinition): number {
79
79
  return maxDepth;
80
80
  }
81
81
 
82
- /**
82
+ /***
83
83
  * Maximum depth per root, e.g. { 'a': 3, 'x.y': 2 }.
84
84
  */
85
85
  export function getMaxDepthByRoot(elements: ElementsDefinition): Record<string, number> {
@@ -96,19 +96,17 @@ export function getMaxDepthByRoot(elements: ElementsDefinition): Record<string,
96
96
  return result;
97
97
  }
98
98
 
99
- /**
99
+ /***
100
100
  * Filters sub-packages so only the desired number of levels under each root are shown.
101
- *
102
- * @param elements - Cytoscape elements
103
- * @param allowSelfLoops - Keep self loops after lifting/aggregation
104
- * @param maxDepth - Number of levels to keep under each root (1 = roots only, 2 = +children, etc.)
101
+ * @performance Aggregate weights and origin IDs in local maps without repeatedly copying growing
102
+ * evidence arrays. Inputs remain immutable; a large lifted bundle must stay linear in edge count.
105
103
  */
106
104
  export function filterSubPackagesByDepth(
107
105
  elements: ElementsDefinition,
108
- allowSelfLoops: boolean = false,
109
- maxDepth: number = 1
106
+ allowSelfLoops = false,
107
+ maxDepth = 1
110
108
  ): ElementsDefinition {
111
- const allPackages = elements.nodes.map(n => n.data.id as string);
109
+ const allPackages = elements.nodes.map(n => n.data.id!);
112
110
  const existingSet = new Set(allPackages);
113
111
 
114
112
  // 1) Identify minimal roots (no ancestor present)
@@ -125,14 +123,15 @@ export function filterSubPackagesByDepth(
125
123
 
126
124
  // 3) Visible nodes = unique set of chosen ancestors
127
125
  const visibleNodeIds = new Set<string>(pkgToVisible.values());
128
- const filteredNodes = elements.nodes.filter(n => visibleNodeIds.has(n.data.id as string));
126
+ const filteredNodes = elements.nodes.filter(n => visibleNodeIds.has(n.data.id!));
129
127
 
130
128
  // 4) Lift & aggregate edges to visible ancestors (sum weights)
131
129
  const edgeMap = new Map<string, EdgeDefinition>();
130
+ const edgeOrigins = new Map<string, string[]>();
132
131
 
133
132
  for (const e of elements.edges) {
134
- const rawSource = e.data.source as string;
135
- const rawTarget = e.data.target as string;
133
+ const rawSource = e.data.source;
134
+ const rawTarget = e.data.target;
136
135
 
137
136
  const liftedSource = pkgToVisible.get(rawSource) ?? rawSource;
138
137
  const liftedTarget = pkgToVisible.get(rawTarget) ?? rawTarget;
@@ -145,13 +144,17 @@ export function filterSubPackagesByDepth(
145
144
  }
146
145
 
147
146
  const key = `${liftedSource}->${liftedTarget}`;
147
+ const origins = edgeOrigins.get(key) ?? [];
148
+ origins.push(e.data.id ?? `${rawSource}->${rawTarget}`);
149
+ edgeOrigins.set(key, origins);
148
150
  if (!edgeMap.has(key)) {
149
151
  // clone with lifted endpoints; keep your metadata; (optionally set a stable id)
150
152
  edgeMap.set(key, {
151
153
  ...e,
152
154
  data: {
153
155
  ...e.data,
154
- // id: key, // uncomment if you want stable, deduped edge ids
156
+ id: key,
157
+ originalEdgeIds: origins,
155
158
  source: liftedSource,
156
159
  target: liftedTarget,
157
160
  // initialize aggregated weight
@@ -1,6 +1,6 @@
1
1
  import type { ElementsDefinition } from 'cytoscape';
2
2
 
3
- /**
3
+ /***
4
4
  * Filters vendor packages by known package prefix
5
5
  */
6
6
  export function filterVendorPackages(elements: ElementsDefinition): ElementsDefinition {
@@ -0,0 +1,8 @@
1
+ import type { NodeDefinition } from 'cytoscape';
2
+
3
+ /*** Identifies project nodes using the graph builder's classification, not namespace spelling. */
4
+ export function isIntrinsicGraphNode(node: NodeDefinition): boolean {
5
+ if (typeof node.data.isIntrinsic === 'boolean') return node.data.isIntrinsic;
6
+ const classes = Array.isArray(node.classes) ? node.classes : (node.classes ?? '').split(/\s+/);
7
+ return !classes.includes('isVendor');
8
+ }