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
@@ -1,93 +1,47 @@
1
1
  'use server';
2
- import type { ParsedFile, MethodCall, MethodDefinition, ImportDefinition } from '@/shared/types';
3
-
4
- import fs from 'node:fs';
5
2
  import path from 'node:path';
6
- import { extractPackageFromImport } from '@/app/utils/parser/kotlin/extractPackageFromImport';
7
-
8
- /**
9
- * Extracts package declaration from Kotlin content.
10
- */
11
- function extractPackage(content: string): string {
12
- const packageMatch = content.match(/^\s*package\s+([\w.]+)/m);
13
- return packageMatch ? packageMatch[1] : '';
14
- }
15
3
 
16
- /**
17
- * Extracts import statements from Kotlin code.
18
- */
19
- function extractImports(content: string): ImportDefinition[] {
20
- const imports: ImportDefinition[] = [];
21
- const importRegex = /^\s*import\s+([\w.]+(?:\.\*)?)/gm;
4
+ import { readTextFileWithinRoot } from '@ankhorage/utility/node/fs';
22
5
 
23
- let match;
24
- while ((match = importRegex.exec(content)) !== null) {
25
- const importPath = match[1];
26
- const pkg = extractPackageFromImport(importPath);
27
-
28
- // Check if it's an intrinsic/standard library import
29
- const isIntrinsic =
30
- importPath.startsWith('kotlin.') ||
31
- importPath.startsWith('java.') ||
32
- importPath.startsWith('javax.');
33
-
34
- imports.push({
35
- name: importPath,
36
- pkg,
37
- isIntrinsic,
38
- });
39
- }
6
+ import type { ImportDefinition, MethodCall, MethodDefinition, ParsedFile } from '@/shared/types';
7
+ import { toPosix } from '@/shared/utils/toPosix';
40
8
 
41
- return imports;
9
+ /*** Extracts package declaration from Kotlin content. */
10
+ function extractPackage(content: string): string {
11
+ const packageMatch = /^\s*package\s+([\w.]+)/m.exec(content);
12
+ return packageMatch ? packageMatch[1] : '';
42
13
  }
43
14
 
44
- /**
45
- * Extracts class, object, data class, or sealed class name from Kotlin content.
46
- */
15
+ /*** Extracts class, object, data class, or sealed class name from Kotlin content. */
47
16
  function extractClassName(content: string, fileName: string): string {
48
- // Try to find class/object/interface declaration
49
- const classMatch = content.match(
50
- /(?:^|\n)\s*(?:data\s+|sealed\s+|abstract\s+|open\s+)?(?:class|object|interface)\s+([A-Za-z0-9_]+)/m
51
- );
17
+ const classMatch =
18
+ /(?:^|\n)\s*(?:data\s+|sealed\s+|abstract\s+|open\s+)?(?:class|object|interface)\s+([A-Za-z0-9_]+)/m.exec(
19
+ content
20
+ );
52
21
 
53
- if (classMatch) {
54
- return classMatch[1];
55
- }
56
-
57
- // Fallback to filename without extension
22
+ if (classMatch) return classMatch[1];
58
23
  return path.basename(fileName, path.extname(fileName));
59
24
  }
60
25
 
61
- /**
62
- * Extracts method/function definitions from Kotlin content.
63
- */
26
+ /*** Extracts method/function definitions from Kotlin content. */
64
27
  function extractMethodDefinitions(content: string): MethodDefinition[] {
65
28
  const methods: MethodDefinition[] = [];
66
-
67
- // Match function definitions: fun methodName(params): ReturnType or suspend fun methodName
68
29
  const methodRegex =
69
30
  /(?:^|\n)\s*(?:(private|protected|public|internal)\s+)?(?:suspend\s+)?fun\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*$$([^)]*)$$(?:\s*:\s*([^{=\n]+))?/gm;
70
31
 
71
32
  let match;
72
33
  while ((match = methodRegex.exec(content)) !== null) {
73
34
  const visibility = (match[1] || 'public') as
74
- | 'public'
75
- | 'protected'
76
- | 'private'
77
- | 'internal'
78
- | 'default';
35
+ 'public' | 'protected' | 'private' | 'internal' | 'default';
79
36
  const name = match[2];
80
37
  const paramsStr = match[3];
81
38
  const returnType = match[4]?.trim() || 'Unit';
82
-
83
- // Parse parameters
84
39
  const params = paramsStr
85
40
  .split(',')
86
41
  .map(p => p.trim())
87
42
  .filter(p => p)
88
43
  .map(p => {
89
- // Extract parameter name (before colon)
90
- const paramMatch = p.match(/([a-zA-Z_][a-zA-Z0-9_]*)\s*:/);
44
+ const paramMatch = /([a-zA-Z_][a-zA-Z0-9_]*)\s*:/.exec(p);
91
45
  return paramMatch ? paramMatch[1] : p;
92
46
  });
93
47
 
@@ -102,46 +56,39 @@ function extractMethodDefinitions(content: string): MethodDefinition[] {
102
56
  return methods;
103
57
  }
104
58
 
105
- /**
106
- * Extract method calls from Kotlin content.
107
- */
59
+ /*** Extracts method calls from Kotlin content. */
108
60
  function extractMethodCalls(content: string): MethodCall[] {
109
61
  const calls: MethodCall[] = [];
110
-
111
- // Match: object.method( or variable.method(
112
62
  const callRegex = /([a-zA-Z_][a-zA-Z0-9_]*)\.([a-zA-Z_][a-zA-Z0-9_]*)\s*\(/g;
113
63
 
114
64
  let match;
115
65
  while ((match = callRegex.exec(content)) !== null) {
116
66
  const callee = match[1];
117
67
  const method = match[2];
118
-
119
68
  calls.push({ callee, method });
120
69
  }
121
70
 
122
71
  return calls;
123
72
  }
124
73
 
125
- /**
126
- * Parses a Kotlin file and returns metadata useful for diagram generation.
127
- */
128
- export async function parseKotlinFile(fullPath: string, projectRoot: string): Promise<ParsedFile> {
129
- const content = fs.readFileSync(fullPath, 'utf-8');
130
- const fileName = path.basename(fullPath);
131
-
132
- const packageName = extractPackage(content);
133
- const className = extractClassName(content, fileName);
134
- const imports = extractImports(content);
135
- const methods = extractMethodDefinitions(content);
136
- const calls = extractMethodCalls(content);
137
- const relativePath = path.relative(projectRoot, fullPath);
74
+ /*** Parses Kotlin class/method/call metadata while consuming canonical dependency imports. */
75
+ export async function parseKotlinFile(
76
+ fullPath: string,
77
+ projectRoot: string,
78
+ imports: readonly ImportDefinition[]
79
+ ): Promise<ParsedFile> {
80
+ const { content, path: resolvedPath } = readTextFileWithinRoot({
81
+ rootPath: projectRoot,
82
+ filePath: fullPath,
83
+ });
84
+ const fileName = path.basename(resolvedPath);
138
85
 
139
86
  return {
140
- className,
141
- package: packageName,
142
- imports,
143
- methods,
144
- calls,
145
- path: relativePath,
87
+ className: extractClassName(content, fileName),
88
+ package: extractPackage(content),
89
+ imports: [...imports],
90
+ methods: extractMethodDefinitions(content),
91
+ calls: extractMethodCalls(content),
92
+ path: toPosix(path.relative(projectRoot, resolvedPath)),
146
93
  };
147
94
  }
@@ -1,89 +1,29 @@
1
1
  'use server';
2
- import type { ParsedFile, MethodCall, MethodDefinition, ImportDefinition } from '@/shared/types';
3
-
4
- import fs from 'node:fs';
5
2
  import path from 'node:path';
6
- import { extractPythonPackageFromImport } from '@/app/utils/parser/python/extractPythonPackageFromImport';
7
3
 
8
- /**
9
- * Extracts module path from Python __init__.py structure.
10
- */
11
- function extractModulePath(filePath: string, projectRoot: string): string {
12
- const relativePath = path.relative(projectRoot, filePath);
13
- const parts = relativePath.split(path.sep);
4
+ import { readTextFileWithinRoot } from '@ankhorage/utility/node/fs';
14
5
 
15
- // Remove the filename
16
- parts.pop();
6
+ import type { ImportDefinition, MethodCall, MethodDefinition, ParsedFile } from '@/shared/types';
7
+ import { toPosix } from '@/shared/utils/toPosix';
17
8
 
18
- // Join with dots for Python module notation
9
+ /*** Extracts module path from Python source structure. */
10
+ function extractModulePath(filePath: string, projectRoot: string): string {
11
+ const relativePath = toPosix(path.relative(projectRoot, filePath));
12
+ const parts = relativePath.split('/');
13
+ parts.pop();
19
14
  return parts.join('.');
20
15
  }
21
16
 
22
- /**
23
- * Extracts import statements from Python code.
24
- */
25
- function extractImports(content: string): ImportDefinition[] {
26
- const imports: ImportDefinition[] = [];
27
-
28
- // Match: import module
29
- // Match: import module as alias
30
- // Match: from module import something
31
- const importRegex =
32
- /(?:^|\n)\s*(?:from\s+([\w.]+)\s+)?import\s+([\w\s,*]+?)(?:\s+as\s+\w+)?(?:\s|$|#)/gm;
33
-
34
- let match;
35
- while ((match = importRegex.exec(content)) !== null) {
36
- const fromModule = match[1];
37
- const importedItems = match[2];
38
-
39
- if (fromModule) {
40
- // from X import Y
41
- const pkg = extractPythonPackageFromImport(fromModule);
42
- const isIntrinsic = fromModule.startsWith('.');
43
-
44
- imports.push({
45
- name: fromModule,
46
- pkg,
47
- isIntrinsic,
48
- });
49
- } else {
50
- // import X, Y, Z
51
- const mods = importedItems.split(',').map(m => m.trim());
52
- for (const mod of mods) {
53
- const pkg = extractPythonPackageFromImport(mod);
54
- imports.push({
55
- name: mod,
56
- pkg,
57
- isIntrinsic: false,
58
- });
59
- }
60
- }
61
- }
62
-
63
- return imports;
64
- }
65
-
66
- /**
67
- * Extracts the class name from Python content.
68
- */
17
+ /*** Extracts the class name from Python content. */
69
18
  function extractClassName(content: string, fileName: string): string {
70
- // Try to find class declaration
71
- const classMatch = content.match(/^class\s+([A-Za-z0-9_]+)/m);
72
- if (classMatch) {
73
- return classMatch[1];
74
- }
75
-
76
- // Fallback to filename without extension
19
+ const classMatch = /^class\s+([A-Za-z0-9_]+)/m.exec(content);
20
+ if (classMatch) return classMatch[1];
77
21
  return path.basename(fileName, path.extname(fileName));
78
22
  }
79
23
 
80
- /**
81
- * Extracts method/function definitions from Python content.
82
- */
24
+ /*** Extracts method/function definitions from Python content. */
83
25
  function extractMethodDefinitions(content: string): MethodDefinition[] {
84
26
  const methods: MethodDefinition[] = [];
85
-
86
- // Match function definitions: def method_name(params): or async def method_name(params):
87
27
  const methodRegex =
88
28
  /(?:^|\n)\s*(async\s+)?def\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*$$([^)]*)$$\s*(?:->([^:]+))?:/gm;
89
29
 
@@ -92,14 +32,11 @@ function extractMethodDefinitions(content: string): MethodDefinition[] {
92
32
  const name = match[2];
93
33
  const paramsStr = match[3];
94
34
  const returnType = match[4]?.trim() || 'None';
95
-
96
- // Parse parameters
97
35
  const params = paramsStr
98
36
  .split(',')
99
37
  .map(p => p.trim())
100
38
  .filter(p => p && p !== 'self' && p !== 'cls');
101
39
 
102
- // Determine visibility (Python convention: _ prefix = protected, __ prefix = private)
103
40
  let visibility: 'public' | 'protected' | 'private' | 'default' = 'public';
104
41
  if (name.startsWith('__') && !name.endsWith('__')) {
105
42
  visibility = 'private';
@@ -118,13 +55,9 @@ function extractMethodDefinitions(content: string): MethodDefinition[] {
118
55
  return methods;
119
56
  }
120
57
 
121
- /**
122
- * Extract method calls from Python content.
123
- */
58
+ /*** Extracts method calls from Python content. */
124
59
  function extractMethodCalls(content: string): MethodCall[] {
125
60
  const calls: MethodCall[] = [];
126
-
127
- // Match: object.method( or self.method(
128
61
  const callRegex = /([a-zA-Z_][a-zA-Z0-9_]*)\.([a-zA-Z_][a-zA-Z0-9_]*)\s*\(/g;
129
62
 
130
63
  let match;
@@ -132,7 +65,6 @@ function extractMethodCalls(content: string): MethodCall[] {
132
65
  const callee = match[1];
133
66
  const method = match[2];
134
67
 
135
- // Skip common built-in methods to reduce noise
136
68
  if (
137
69
  ['append', 'extend', 'pop', 'remove', 'join', 'split', 'strip'].includes(method) &&
138
70
  ['str', 'list', 'dict', 'set'].includes(callee)
@@ -146,26 +78,24 @@ function extractMethodCalls(content: string): MethodCall[] {
146
78
  return calls;
147
79
  }
148
80
 
149
- /**
150
- * Parses a Python file and returns metadata useful for diagram generation.
151
- */
152
- export async function parsePythonFile(fullPath: string, projectRoot: string): Promise<ParsedFile> {
153
- const content = fs.readFileSync(fullPath, 'utf-8');
154
- const fileName = path.basename(fullPath);
155
-
156
- const className = extractClassName(content, fileName);
157
- const modulePath = extractModulePath(fullPath, projectRoot);
158
- const imports = extractImports(content);
159
- const methods = extractMethodDefinitions(content);
160
- const calls = extractMethodCalls(content);
161
- const relativePath = path.relative(projectRoot, fullPath);
81
+ /*** Parses Python metadata while consuming canonical dependency imports. */
82
+ export async function parsePythonFile(
83
+ fullPath: string,
84
+ projectRoot: string,
85
+ imports: readonly ImportDefinition[]
86
+ ): Promise<ParsedFile> {
87
+ const { content, path: resolvedPath } = readTextFileWithinRoot({
88
+ rootPath: projectRoot,
89
+ filePath: fullPath,
90
+ });
91
+ const fileName = path.basename(resolvedPath);
162
92
 
163
93
  return {
164
- className,
165
- package: modulePath,
166
- imports,
167
- methods,
168
- calls,
169
- path: relativePath,
94
+ className: extractClassName(content, fileName),
95
+ package: extractModulePath(resolvedPath, projectRoot),
96
+ imports: [...imports],
97
+ methods: extractMethodDefinitions(content),
98
+ calls: extractMethodCalls(content),
99
+ path: toPosix(path.relative(projectRoot, resolvedPath)),
170
100
  };
171
101
  }
@@ -1,57 +1,16 @@
1
- import type { ParsedFile, MethodCall, MethodDefinition, ImportDefinition } from '@/shared/types';
2
-
3
1
  import fs from 'node:fs/promises';
4
- import { basename, relative, resolve } from 'node:path';
5
- import ts from 'typescript';
6
- import { extractTypeScriptPackageFromImport } from '@/app/utils/parser/typescript/extractTypeScriptPackageFromImport';
7
- import { toPosix } from '@/shared/utils/toPosix';
8
- import { parseProjectPath } from '@/shared/utils/parseProjectPath';
9
-
10
- /**
11
- * Extracts import statements from TypeScript code.
12
- */
13
- function extractImports(content: string, filename: string): ImportDefinition[] {
14
- const sourceFile = ts.createSourceFile('temp.ts', content, ts.ScriptTarget.Latest, true);
15
- const imports: ImportDefinition[] = [];
16
-
17
- sourceFile.forEachChild(node => {
18
- if (!ts.isImportDeclaration(node)) return;
19
-
20
- const fullPath = toPosix(filename).split('/').slice(0, -1).join('/');
21
- const moduleSpecifier = (node.moduleSpecifier as ts.StringLiteral).text;
22
-
23
- function resolveImportPath(curDir: string, specifier: string) {
24
- const root = parseProjectPath();
2
+ import { basename, relative } from 'node:path';
25
3
 
26
- if (specifier.startsWith('./') || specifier.startsWith('../'))
27
- return {
28
- isIntrinsic: true,
29
- resolvedPath: resolve(curDir, specifier).slice(root.length + 1),
30
- };
31
-
32
- if (specifier.startsWith('@/'))
33
- return {
34
- isIntrinsic: true,
35
- resolvedPath: specifier.replace(/^@/, 'src'),
36
- };
37
-
38
- return { isIntrinsic: false, resolvedPath: specifier };
39
- }
40
-
41
- const { resolvedPath, isIntrinsic } = resolveImportPath(fullPath, moduleSpecifier);
42
-
43
- const pkg = extractTypeScriptPackageFromImport(resolvedPath);
44
- imports.push({ name: pkg, pkg, isIntrinsic });
45
- });
4
+ import ts from 'typescript';
46
5
 
47
- return imports;
48
- }
6
+ import type { ImportDefinition, MethodCall, MethodDefinition, ParsedFile } from '@/shared/types';
7
+ import { toPosix } from '@/shared/utils/toPosix';
49
8
 
50
- /**
9
+ /***
51
10
  * Extracts the class name from the content and filename fallback.
52
11
  */
53
12
  function extractClassName(content: string, fileName: string): string {
54
- const classMatch = content.match(/class\s+(\w+)/);
13
+ const classMatch = /class\s+(\w+)/.exec(content);
55
14
  if (classMatch) {
56
15
  return classMatch[1];
57
16
  }
@@ -59,13 +18,14 @@ function extractClassName(content: string, fileName: string): string {
59
18
  return basename(fileName, '.ts');
60
19
  }
61
20
 
62
- /**
21
+ /***
63
22
  * Extracts method definitions from TypeScript content.
64
23
  */
65
24
  function extractMethodDefinitions(content: string): MethodDefinition[] {
66
25
  const sourceFile = ts.createSourceFile('temp.ts', content, ts.ScriptTarget.Latest, true);
67
26
  const methods: MethodDefinition[] = [];
68
27
 
28
+ /*** Visits syntax nodes while collecting parser metadata. */
69
29
  function visit(node: ts.Node) {
70
30
  if (ts.isMethodDeclaration(node) && node.name) {
71
31
  const name = node.name.getText();
@@ -88,13 +48,14 @@ function extractMethodDefinitions(content: string): MethodDefinition[] {
88
48
  return methods;
89
49
  }
90
50
 
91
- /**
51
+ /***
92
52
  * Extracts method calls from TypeScript content.
93
53
  */
94
54
  function extractMethodCalls(content: string): MethodCall[] {
95
55
  const sourceFile = ts.createSourceFile('temp.ts', content, ts.ScriptTarget.Latest, true);
96
56
  const calls: MethodCall[] = [];
97
57
 
58
+ /*** Visits syntax nodes while collecting parser metadata. */
98
59
  function visit(node: ts.Node) {
99
60
  if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression)) {
100
61
  const callee = node.expression.expression.getText();
@@ -109,10 +70,14 @@ function extractMethodCalls(content: string): MethodCall[] {
109
70
  return calls;
110
71
  }
111
72
 
112
- /**
73
+ /***
113
74
  * Parses a TypeScript file and returns metadata useful for diagram generation.
114
75
  */
115
- export async function parseFile(fullPath: string, projectRoot: string): Promise<ParsedFile> {
76
+ export async function parseFile(
77
+ fullPath: string,
78
+ projectRoot: string,
79
+ imports: readonly ImportDefinition[]
80
+ ): Promise<ParsedFile> {
116
81
  const posixFullPath = toPosix(fullPath);
117
82
  const content = await fs.readFile(posixFullPath, 'utf-8');
118
83
  const relativePath = toPosix(relative(projectRoot, posixFullPath));
@@ -121,7 +86,7 @@ export async function parseFile(fullPath: string, projectRoot: string): Promise<
121
86
 
122
87
  return {
123
88
  className: extractClassName(content, fullPath),
124
- imports: extractImports(content, fullPath),
89
+ imports: [...imports],
125
90
  methods: extractMethodDefinitions(content),
126
91
  calls: extractMethodCalls(content),
127
92
  package: segmentedPath.join('.'),
@@ -0,0 +1,39 @@
1
+ import type { ProjectDetection } from '@ankhorage/project-detector/types';
2
+
3
+ import { Language } from '../../shared/types';
4
+ import type { ParserSelection } from '../../types/parserSelection';
5
+
6
+ /*** Select a supported parser by evidence strength, evidence count, then stable parser order. */
7
+ export function selectParserLanguage(detection: ProjectDetection): ParserSelection {
8
+ const supported = [
9
+ Language.TypeScript,
10
+ Language.Java,
11
+ Language.Cpp,
12
+ Language.Python,
13
+ Language.Delphi,
14
+ Language.Kotlin,
15
+ ];
16
+ const candidates = supported
17
+ .flatMap(language => {
18
+ const detected = detection.languages.find(candidate => candidate.id === language);
19
+ return detected ? [{ language, detected }] : [];
20
+ })
21
+ .sort(
22
+ (left, right) =>
23
+ right.detected.score - left.detected.score ||
24
+ right.detected.evidence.length - left.detected.evidence.length ||
25
+ supported.indexOf(left.language) - supported.indexOf(right.language)
26
+ );
27
+ const selected = candidates[0];
28
+ if (!selected) {
29
+ throw new Error(
30
+ `No supported parser detected. Found: ${detection.languages.map(language => language.id).join(', ') || 'unknown'}. Supported: ${supported.join(', ')}.`
31
+ );
32
+ }
33
+ return {
34
+ language: selected.language,
35
+ score: selected.detected.score,
36
+ indicators: selected.detected.evidence,
37
+ candidates: detection.languages,
38
+ };
39
+ }
@@ -0,0 +1,21 @@
1
+ import type { AuditRuleResult } from '@/types/audit';
2
+
3
+ /*** Formats blocking audit-rule failures for terminal and CI output. */
4
+ export function formatAuditRuleFailures(
5
+ results: readonly AuditRuleResult[],
6
+ artifactPath: string
7
+ ): string {
8
+ const failures = results.filter(
9
+ result => result.policy === 'blocking' && result.status === 'failed'
10
+ );
11
+ const ruleLines = failures.flatMap(result => {
12
+ const details =
13
+ result.details.length > 0
14
+ ? result.details.map(detail => ` ${detail}`)
15
+ : [` ${result.message}`];
16
+
17
+ return [`✗ ${result.id}`, ...details, ''];
18
+ });
19
+
20
+ return ['PKGViz audit failed', '', ...ruleLines, `Audit: ${artifactPath}`].join('\n');
21
+ }
@@ -0,0 +1,41 @@
1
+ import { resolveFileSystemPathWithinRoot, writeFileWithinRoot } from '@ankhorage/utility/node/fs';
2
+
3
+ import { createAuditAsync } from '@/features/audit/composition/createAuditAsync';
4
+ import { hasBlockingAuditRuleFailure } from '@/features/audit/domain/hasBlockingAuditRuleFailure';
5
+ import type { Audit, ResolveAuditConfigurationInput } from '@/types/audit';
6
+
7
+ /*** Creates, writes, and evaluates an audit while retaining the artifact on rule failure. */
8
+ export async function runAuditAsync(input: RunAuditInput): Promise<RunAuditResult> {
9
+ const audit = await createAuditAsync(input.projectPath, input.configuration);
10
+ const body = input.pretty ? JSON.stringify(audit, null, 2) : JSON.stringify(audit);
11
+
12
+ await writeFileWithinRoot({
13
+ rootPath: input.projectPath,
14
+ filePath: input.outputPath,
15
+ body: new TextEncoder().encode(body),
16
+ exclusive: false,
17
+ });
18
+
19
+ const artifactPath = resolveFileSystemPathWithinRoot(input.projectPath, input.outputPath);
20
+ const shouldFail =
21
+ audit.configuration.failOnRuleViolation && hasBlockingAuditRuleFailure(audit.evaluation.rules);
22
+
23
+ return {
24
+ audit,
25
+ artifactPath,
26
+ exitCode: shouldFail ? 2 : 0,
27
+ };
28
+ }
29
+
30
+ interface RunAuditInput {
31
+ readonly projectPath: string;
32
+ readonly outputPath: string;
33
+ readonly pretty: boolean;
34
+ readonly configuration?: ResolveAuditConfigurationInput;
35
+ }
36
+
37
+ interface RunAuditResult {
38
+ readonly audit: Audit;
39
+ readonly artifactPath: string;
40
+ readonly exitCode: 0 | 2;
41
+ }
@@ -1,10 +1,11 @@
1
1
  'use client';
2
- import React from 'react';
3
2
  import { ChevronRight, Home } from 'lucide-react';
4
3
  import Link from 'next/link';
4
+ import React from 'react';
5
5
 
6
+ /*** Renders package navigation breadcrumbs without empty path segments. */
6
7
  export default function Breadcrumb({ path, onNavigate }: BreadcrumbProps) {
7
- const parts = path.split('/') || [''];
8
+ const parts = path.split('/').filter(Boolean);
8
9
 
9
10
  return (
10
11
  <nav className="flex items-center space-x-1 text-sm">
@@ -13,10 +14,10 @@ export default function Breadcrumb({ path, onNavigate }: BreadcrumbProps) {
13
14
  </Link>
14
15
 
15
16
  {parts.map((part, index) => {
16
- const currentPath = parts.length ? parts.slice(0, index + 1).join('.') : '';
17
+ const currentPath = parts.slice(0, index + 1).join('/');
17
18
 
18
19
  return (
19
- <div key={index} className="flex items-center">
20
+ <div key={currentPath} className="flex items-center">
20
21
  <ChevronRight className="h-4 w-4 text-foreground opacity-20" />
21
22
  <Link href="#" onClick={() => onNavigate(currentPath)} className="ml-1 text-foreground">
22
23
  {part}
@@ -0,0 +1,53 @@
1
+ 'use client';
2
+ import { DownloadIcon } from 'lucide-react';
3
+ import React from 'react';
4
+
5
+ import { downloadAuditJsonAction, downloadAuditXmlAction } from '@/app/actions/audit.actions';
6
+ import { SidebarRow } from '@/components/sidebar/SidebarRow';
7
+
8
+ /*** Renders secondary audit-export actions inside the Export sidebar tab. */
9
+ export function ExportPanel() {
10
+ return (
11
+ <div className="pt-3">
12
+ <SidebarRow>
13
+ <ExportButton
14
+ format="JSON"
15
+ mimeType="application/json"
16
+ onExport={downloadAuditJsonAction}
17
+ />
18
+ </SidebarRow>
19
+ <SidebarRow>
20
+ <ExportButton format="XML" mimeType="application/xml" onExport={downloadAuditXmlAction} />
21
+ </SidebarRow>
22
+ </div>
23
+ );
24
+ }
25
+
26
+ /*** Downloads one serialized audit format. */
27
+ function ExportButton({ format, mimeType, onExport }: ExportButtonProps) {
28
+ return (
29
+ <button
30
+ type="button"
31
+ onClick={async () => {
32
+ const { data, filename } = await onExport();
33
+ const blob = new Blob([data], { type: mimeType });
34
+ const url = URL.createObjectURL(blob);
35
+ const anchor = document.createElement('a');
36
+ anchor.href = url;
37
+ anchor.download = filename;
38
+ anchor.click();
39
+ URL.revokeObjectURL(url);
40
+ }}
41
+ className="flex cursor-pointer items-center text-xs hover:text-blue-600 dark:hover:text-blue-400"
42
+ >
43
+ <DownloadIcon size={10} className="mr-1.5" />
44
+ <span>{format}</span>
45
+ </button>
46
+ );
47
+ }
48
+
49
+ interface ExportButtonProps {
50
+ readonly format: string;
51
+ readonly mimeType: string;
52
+ readonly onExport: () => Promise<{ data: string; filename: string }>;
53
+ }
@@ -4,6 +4,7 @@ import ThemeToggle from '@/components/ThemeToggle';
4
4
  import { t } from '@/i18n/i18n';
5
5
  import { getProjectName } from '@/shared/utils/getProjectName';
6
6
 
7
+ /*** Renders the application header. */
7
8
  export default function Header({ children, title }: HeaderProps) {
8
9
  const projectName = getProjectName();
9
10