codebase-onboarder 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (448) hide show
  1. package/README.md +174 -46
  2. package/bin/build-if-source.js +23 -0
  3. package/cli/commands.d.ts +26 -0
  4. package/cli/commands.js +836 -811
  5. package/cli/commands.js.map +1 -0
  6. package/cli/explorer/advanced.d.ts +14 -0
  7. package/cli/explorer/advanced.js +321 -329
  8. package/cli/explorer/advanced.js.map +1 -0
  9. package/cli/explorer/app.d.ts +1 -0
  10. package/cli/explorer/app.js +384 -313
  11. package/cli/explorer/app.js.map +1 -0
  12. package/cli/explorer/assistant.d.ts +9 -0
  13. package/cli/explorer/assistant.js +58 -0
  14. package/cli/explorer/assistant.js.map +1 -0
  15. package/cli/explorer/commands.d.ts +17 -0
  16. package/cli/explorer/commands.js +368 -302
  17. package/cli/explorer/commands.js.map +1 -0
  18. package/cli/explorer/featureViews.d.ts +124 -0
  19. package/cli/explorer/featureViews.js +179 -0
  20. package/cli/explorer/featureViews.js.map +1 -0
  21. package/cli/explorer/github.d.ts +21 -0
  22. package/cli/explorer/github.js +42 -44
  23. package/cli/explorer/github.js.map +1 -0
  24. package/cli/explorer/graphs.d.ts +7 -0
  25. package/cli/explorer/graphs.js +90 -95
  26. package/cli/explorer/graphs.js.map +1 -0
  27. package/cli/explorer/picker.d.ts +22 -0
  28. package/cli/explorer/picker.js +150 -0
  29. package/cli/explorer/picker.js.map +1 -0
  30. package/cli/explorer/report.d.ts +85 -0
  31. package/cli/explorer/report.js +60 -0
  32. package/cli/explorer/report.js.map +1 -0
  33. package/cli/explorer/session.d.ts +449 -0
  34. package/cli/explorer/session.js +143 -144
  35. package/cli/explorer/session.js.map +1 -0
  36. package/cli/explorer/views.d.ts +19 -0
  37. package/cli/explorer/views.js +465 -482
  38. package/cli/explorer/views.js.map +1 -0
  39. package/cli/explorer/wrap.d.ts +1 -0
  40. package/cli/explorer/wrap.js +28 -44
  41. package/cli/explorer/wrap.js.map +1 -0
  42. package/cli/main.d.ts +1 -0
  43. package/cli/main.js +214 -161
  44. package/cli/main.js.map +1 -0
  45. package/cli/prompt.d.ts +5 -0
  46. package/cli/prompt.js +84 -80
  47. package/cli/prompt.js.map +1 -0
  48. package/cli/scanOptions.d.ts +2 -0
  49. package/cli/scanOptions.js +11 -0
  50. package/cli/scanOptions.js.map +1 -0
  51. package/cli/ui.d.ts +33 -0
  52. package/cli/ui.js +35 -44
  53. package/cli/ui.js.map +1 -0
  54. package/cli/wizard.d.ts +187 -0
  55. package/cli/wizard.js +304 -284
  56. package/cli/wizard.js.map +1 -0
  57. package/package.json +15 -4
  58. package/public/app.d.ts +1 -0
  59. package/public/app.js +1057 -1009
  60. package/public/app.js.map +1 -0
  61. package/public/browser.d.ts +68 -0
  62. package/public/browser.js +2 -0
  63. package/public/browser.js.map +1 -0
  64. package/public/index.html +30 -13
  65. package/public/js/about.d.ts +6 -0
  66. package/public/js/about.js +152 -172
  67. package/public/js/about.js.map +1 -0
  68. package/public/js/aiDraft.d.ts +3 -0
  69. package/public/js/aiDraft.js +116 -124
  70. package/public/js/aiDraft.js.map +1 -0
  71. package/public/js/analysisPanel.d.ts +7 -0
  72. package/public/js/analysisPanel.js +166 -166
  73. package/public/js/analysisPanel.js.map +1 -0
  74. package/public/js/analysisReport.d.ts +38 -0
  75. package/public/js/analysisReport.js +105 -110
  76. package/public/js/analysisReport.js.map +1 -0
  77. package/public/js/api.d.ts +26 -0
  78. package/public/js/api.js +176 -167
  79. package/public/js/api.js.map +1 -0
  80. package/public/js/atlas.d.ts +6 -0
  81. package/public/js/atlas.js +50 -58
  82. package/public/js/atlas.js.map +1 -0
  83. package/public/js/blameView.d.ts +2 -0
  84. package/public/js/blameView.js +36 -37
  85. package/public/js/blameView.js.map +1 -0
  86. package/public/js/codeTab.d.ts +3 -0
  87. package/public/js/codeTab.js +175 -180
  88. package/public/js/codeTab.js.map +1 -0
  89. package/public/js/codeViewer.d.ts +5 -0
  90. package/public/js/codeViewer.js +162 -150
  91. package/public/js/codeViewer.js.map +1 -0
  92. package/public/js/components/FileChip.d.ts +9 -0
  93. package/public/js/components/FileChip.js +45 -49
  94. package/public/js/components/FileChip.js.map +1 -0
  95. package/public/js/components/MetricSparkline.d.ts +7 -0
  96. package/public/js/components/MetricSparkline.js +35 -44
  97. package/public/js/components/MetricSparkline.js.map +1 -0
  98. package/public/js/components/RiskBadge.d.ts +9 -0
  99. package/public/js/components/RiskBadge.js +55 -63
  100. package/public/js/components/RiskBadge.js.map +1 -0
  101. package/public/js/deepAnalysisView.d.ts +99 -0
  102. package/public/js/deepAnalysisView.js +282 -302
  103. package/public/js/deepAnalysisView.js.map +1 -0
  104. package/public/js/diagramPane.d.ts +8 -0
  105. package/public/js/diagramPane.js +133 -135
  106. package/public/js/diagramPane.js.map +1 -0
  107. package/public/js/diffView.d.ts +6 -0
  108. package/public/js/diffView.js +222 -209
  109. package/public/js/diffView.js.map +1 -0
  110. package/public/js/docsView.d.ts +2 -0
  111. package/public/js/docsView.js +441 -442
  112. package/public/js/docsView.js.map +1 -0
  113. package/public/js/dom.d.ts +189 -0
  114. package/public/js/dom.js +5 -0
  115. package/public/js/dom.js.map +1 -0
  116. package/public/js/fileSourceBrowser.d.ts +5 -0
  117. package/public/js/fileSourceBrowser.js +33 -41
  118. package/public/js/fileSourceBrowser.js.map +1 -0
  119. package/public/js/flameGraph.d.ts +5 -0
  120. package/public/js/flameGraph.js +62 -72
  121. package/public/js/flameGraph.js.map +1 -0
  122. package/public/js/forceGraph.d.ts +10 -0
  123. package/public/js/forceGraph.js +581 -556
  124. package/public/js/forceGraph.js.map +1 -0
  125. package/public/js/heatmap.d.ts +4 -0
  126. package/public/js/heatmap.js +142 -164
  127. package/public/js/heatmap.js.map +1 -0
  128. package/public/js/highlight.d.ts +2 -0
  129. package/public/js/highlight.js +116 -107
  130. package/public/js/highlight.js.map +1 -0
  131. package/public/js/html.d.ts +2 -0
  132. package/public/js/html.js +14 -44
  133. package/public/js/html.js.map +1 -0
  134. package/public/js/insightsView.d.ts +5 -0
  135. package/public/js/insightsView.js +93 -111
  136. package/public/js/insightsView.js.map +1 -0
  137. package/public/js/inspector.d.ts +37 -0
  138. package/public/js/inspector.js +416 -445
  139. package/public/js/inspector.js.map +1 -0
  140. package/public/js/llm.d.ts +113 -0
  141. package/public/js/llm.js +233 -272
  142. package/public/js/llm.js.map +1 -0
  143. package/public/js/mapView.d.ts +3 -0
  144. package/public/js/mapView.js +121 -120
  145. package/public/js/mapView.js.map +1 -0
  146. package/public/js/markdown.d.ts +3 -0
  147. package/public/js/markdown.js +84 -91
  148. package/public/js/markdown.js.map +1 -0
  149. package/public/js/mindmap.d.ts +32 -0
  150. package/public/js/mindmap.js +244 -259
  151. package/public/js/mindmap.js.map +1 -0
  152. package/public/js/mobilePanels.d.ts +5 -0
  153. package/public/js/mobilePanels.js +50 -0
  154. package/public/js/mobilePanels.js.map +1 -0
  155. package/public/js/repoFiles.d.ts +12 -0
  156. package/public/js/repoFiles.js +28 -27
  157. package/public/js/repoFiles.js.map +1 -0
  158. package/public/js/reviewView.d.ts +28 -0
  159. package/public/js/reviewView.js +256 -0
  160. package/public/js/reviewView.js.map +1 -0
  161. package/public/js/sbomView.d.ts +3 -0
  162. package/public/js/sbomView.js +59 -67
  163. package/public/js/sbomView.js.map +1 -0
  164. package/public/js/scanCache.d.ts +16 -0
  165. package/public/js/scanCache.js +67 -65
  166. package/public/js/scanCache.js.map +1 -0
  167. package/public/js/search.d.ts +7 -0
  168. package/public/js/search.js +868 -800
  169. package/public/js/search.js.map +1 -0
  170. package/public/js/searchLocal.d.ts +42 -0
  171. package/public/js/searchLocal.js +87 -0
  172. package/public/js/searchLocal.js.map +1 -0
  173. package/public/js/serverSettings.d.ts +5 -0
  174. package/public/js/serverSettings.js +153 -164
  175. package/public/js/serverSettings.js.map +1 -0
  176. package/public/js/state.d.ts +798 -0
  177. package/public/js/state.js +114 -122
  178. package/public/js/state.js.map +1 -0
  179. package/public/js/tour.d.ts +6 -0
  180. package/public/js/tour.js +5 -7
  181. package/public/js/tour.js.map +1 -0
  182. package/public/js/transitions.d.ts +2 -0
  183. package/public/js/transitions.js +9 -10
  184. package/public/js/transitions.js.map +1 -0
  185. package/public/js/tree.d.ts +12 -0
  186. package/public/js/tree.js +157 -154
  187. package/public/js/tree.js.map +1 -0
  188. package/public/js/workflowsView.d.ts +3 -0
  189. package/public/js/workflowsView.js +15 -22
  190. package/public/js/workflowsView.js.map +1 -0
  191. package/public/search.css +495 -0
  192. package/public/styles.css +163 -346
  193. package/public/workbench.css +166 -0
  194. package/server/apiAuth.d.ts +3 -0
  195. package/server/apiAuth.js +18 -20
  196. package/server/apiAuth.js.map +1 -0
  197. package/server/apiDiff.d.ts +2 -0
  198. package/server/apiDiff.js +20 -18
  199. package/server/apiDiff.js.map +1 -0
  200. package/server/apiDocs.d.ts +2 -0
  201. package/server/apiDocs.js +38 -40
  202. package/server/apiDocs.js.map +1 -0
  203. package/server/apiFile.d.ts +1 -0
  204. package/server/apiFile.js +14 -17
  205. package/server/apiFile.js.map +1 -0
  206. package/server/apiGitBlame.d.ts +2 -0
  207. package/server/apiGitBlame.js +50 -51
  208. package/server/apiGitBlame.js.map +1 -0
  209. package/server/apiMcp.d.ts +4 -0
  210. package/server/apiMcp.js +64 -66
  211. package/server/apiMcp.js.map +1 -0
  212. package/server/apiReview.d.ts +2 -0
  213. package/server/apiReview.js +45 -0
  214. package/server/apiReview.js.map +1 -0
  215. package/server/apiScan.d.ts +5 -0
  216. package/server/apiScan.js +90 -71
  217. package/server/apiScan.js.map +1 -0
  218. package/server/apiSearch.d.ts +33 -0
  219. package/server/apiSearch.js +184 -200
  220. package/server/apiSearch.js.map +1 -0
  221. package/server/apiSettings.d.ts +4 -0
  222. package/server/apiSettings.js +84 -85
  223. package/server/apiSettings.js.map +1 -0
  224. package/server/apiTools.d.ts +3 -0
  225. package/server/apiTools.js +55 -56
  226. package/server/apiTools.js.map +1 -0
  227. package/server/auth.d.ts +5 -0
  228. package/server/auth.js +54 -51
  229. package/server/auth.js.map +1 -0
  230. package/server/config.d.ts +42 -0
  231. package/server/config.js +189 -194
  232. package/server/config.js.map +1 -0
  233. package/server/daemon.d.ts +12 -0
  234. package/server/daemon.js +124 -114
  235. package/server/daemon.js.map +1 -0
  236. package/server/fileSourceNode.d.ts +2 -0
  237. package/server/fileSourceNode.js +34 -36
  238. package/server/fileSourceNode.js.map +1 -0
  239. package/server/gitClone.d.ts +9 -0
  240. package/server/gitClone.js +59 -61
  241. package/server/gitClone.js.map +1 -0
  242. package/server/gitDiff.d.ts +36 -0
  243. package/server/gitDiff.js +271 -169
  244. package/server/gitDiff.js.map +1 -0
  245. package/server/gitHistory.d.ts +12 -0
  246. package/server/gitHistory.js +80 -80
  247. package/server/gitHistory.js.map +1 -0
  248. package/server/gitRemote.d.ts +12 -0
  249. package/server/gitRemote.js +37 -38
  250. package/server/gitRemote.js.map +1 -0
  251. package/server/htmlText.d.ts +4 -0
  252. package/server/htmlText.js +16 -23
  253. package/server/htmlText.js.map +1 -0
  254. package/server/http.d.ts +5 -0
  255. package/server/http.js +27 -30
  256. package/server/http.js.map +1 -0
  257. package/server/httpGuards.d.ts +2 -0
  258. package/server/httpGuards.js +47 -43
  259. package/server/httpGuards.js.map +1 -0
  260. package/server/https.d.ts +34 -0
  261. package/server/https.js +121 -111
  262. package/server/https.js.map +1 -0
  263. package/server/index.d.ts +40 -0
  264. package/server/index.js +139 -147
  265. package/server/index.js.map +1 -0
  266. package/server/layout.d.ts +26 -0
  267. package/server/layout.js +59 -64
  268. package/server/layout.js.map +1 -0
  269. package/server/llmProxy.d.ts +3 -0
  270. package/server/llmProxy.js +137 -135
  271. package/server/llmProxy.js.map +1 -0
  272. package/server/logger.d.ts +38 -0
  273. package/server/logger.js +198 -211
  274. package/server/logger.js.map +1 -0
  275. package/server/mcp/analysis.d.ts +29 -0
  276. package/server/mcp/analysis.js +99 -120
  277. package/server/mcp/analysis.js.map +1 -0
  278. package/server/mcp/http.d.ts +9 -0
  279. package/server/mcp/http.js +128 -137
  280. package/server/mcp/http.js.map +1 -0
  281. package/server/mcp/runner.d.ts +68 -0
  282. package/server/mcp/runner.js +208 -218
  283. package/server/mcp/runner.js.map +1 -0
  284. package/server/mcp/server.d.ts +29 -0
  285. package/server/mcp/server.js +166 -179
  286. package/server/mcp/server.js.map +1 -0
  287. package/server/mcp/standalone.d.ts +1 -0
  288. package/server/mcp/standalone.js +8 -10
  289. package/server/mcp/standalone.js.map +1 -0
  290. package/server/mcp/tools.d.ts +2020 -0
  291. package/server/mcp/tools.js +523 -574
  292. package/server/mcp/tools.js.map +1 -0
  293. package/server/paths.d.ts +3 -0
  294. package/server/paths.js +17 -15
  295. package/server/paths.js.map +1 -0
  296. package/server/pidfile.d.ts +9 -0
  297. package/server/pidfile.js +43 -45
  298. package/server/pidfile.js.map +1 -0
  299. package/server/review.d.ts +5 -0
  300. package/server/review.js +35 -0
  301. package/server/review.js.map +1 -0
  302. package/server/router.d.ts +33 -0
  303. package/server/router.js +191 -197
  304. package/server/router.js.map +1 -0
  305. package/server/scanRequest.d.ts +3 -0
  306. package/server/scanRequest.js +36 -0
  307. package/server/scanRequest.js.map +1 -0
  308. package/server/searchIndex.d.ts +17 -0
  309. package/server/searchIndex.js +83 -80
  310. package/server/searchIndex.js.map +1 -0
  311. package/server/sessions.d.ts +14 -0
  312. package/server/sessions.js +62 -70
  313. package/server/sessions.js.map +1 -0
  314. package/server/startup.d.ts +118 -0
  315. package/server/startup.js +143 -148
  316. package/server/startup.js.map +1 -0
  317. package/server/static.d.ts +6 -0
  318. package/server/static.js +28 -31
  319. package/server/static.js.map +1 -0
  320. package/server/tools/install.d.ts +4 -0
  321. package/server/tools/install.js +176 -185
  322. package/server/tools/install.js.map +1 -0
  323. package/server/tools/parse.d.ts +8 -0
  324. package/server/tools/parse.js +112 -114
  325. package/server/tools/parse.js.map +1 -0
  326. package/server/tools/platform.d.ts +9 -0
  327. package/server/tools/platform.js +49 -47
  328. package/server/tools/platform.js.map +1 -0
  329. package/server/tools/registry.d.ts +137 -0
  330. package/server/tools/registry.js +173 -172
  331. package/server/tools/registry.js.map +1 -0
  332. package/server/tools/scan.d.ts +34 -0
  333. package/server/tools/scan.js +89 -98
  334. package/server/tools/scan.js.map +1 -0
  335. package/server/tools.d.ts +34 -0
  336. package/server/tools.js +94 -107
  337. package/server/tools.js.map +1 -0
  338. package/server/tunnel.d.ts +29 -0
  339. package/server/tunnel.js +61 -66
  340. package/server/tunnel.js.map +1 -0
  341. package/shared/analyzer/docs.d.ts +16 -0
  342. package/shared/analyzer/docs.js +99 -93
  343. package/shared/analyzer/docs.js.map +1 -0
  344. package/shared/analyzer/explainLocal.d.ts +4 -0
  345. package/shared/analyzer/explainLocal.js +122 -142
  346. package/shared/analyzer/explainLocal.js.map +1 -0
  347. package/shared/analyzer/github.d.ts +37 -0
  348. package/shared/analyzer/github.js +41 -43
  349. package/shared/analyzer/github.js.map +1 -0
  350. package/shared/analyzer/graph.d.ts +41 -0
  351. package/shared/analyzer/graph.js +393 -400
  352. package/shared/analyzer/graph.js.map +1 -0
  353. package/shared/analyzer/health.d.ts +33 -0
  354. package/shared/analyzer/health.js +197 -193
  355. package/shared/analyzer/health.js.map +1 -0
  356. package/shared/analyzer/history.d.ts +29 -0
  357. package/shared/analyzer/history.js +110 -111
  358. package/shared/analyzer/history.js.map +1 -0
  359. package/shared/analyzer/jsonConfig.d.ts +2 -0
  360. package/shared/analyzer/jsonConfig.js +61 -0
  361. package/shared/analyzer/jsonConfig.js.map +1 -0
  362. package/shared/analyzer/languages/csharp.d.ts +26 -0
  363. package/shared/analyzer/languages/csharp.js +83 -88
  364. package/shared/analyzer/languages/csharp.js.map +1 -0
  365. package/shared/analyzer/languages/generic.d.ts +23 -0
  366. package/shared/analyzer/languages/generic.js +94 -105
  367. package/shared/analyzer/languages/generic.js.map +1 -0
  368. package/shared/analyzer/languages/go.d.ts +24 -0
  369. package/shared/analyzer/languages/go.js +45 -54
  370. package/shared/analyzer/languages/go.js.map +1 -0
  371. package/shared/analyzer/languages/index.d.ts +6 -0
  372. package/shared/analyzer/languages/index.js +19 -20
  373. package/shared/analyzer/languages/index.js.map +1 -0
  374. package/shared/analyzer/languages/java.d.ts +20 -0
  375. package/shared/analyzer/languages/java.js +73 -78
  376. package/shared/analyzer/languages/java.js.map +1 -0
  377. package/shared/analyzer/languages/javascript.d.ts +12 -0
  378. package/shared/analyzer/languages/javascript.js +258 -209
  379. package/shared/analyzer/languages/javascript.js.map +1 -0
  380. package/shared/analyzer/languages/python.d.ts +23 -0
  381. package/shared/analyzer/languages/python.js +92 -100
  382. package/shared/analyzer/languages/python.js.map +1 -0
  383. package/shared/analyzer/languages/rust.d.ts +17 -0
  384. package/shared/analyzer/languages/rust.js +96 -98
  385. package/shared/analyzer/languages/rust.js.map +1 -0
  386. package/shared/analyzer/languages/typescript.d.ts +11 -0
  387. package/shared/analyzer/languages/typescript.js +117 -116
  388. package/shared/analyzer/languages/typescript.js.map +1 -0
  389. package/shared/analyzer/licenses.d.ts +18 -0
  390. package/shared/analyzer/licenses.js +130 -133
  391. package/shared/analyzer/licenses.js.map +1 -0
  392. package/shared/analyzer/metrics.d.ts +20 -0
  393. package/shared/analyzer/metrics.js +112 -104
  394. package/shared/analyzer/metrics.js.map +1 -0
  395. package/shared/analyzer/pathUtil.d.ts +10 -0
  396. package/shared/analyzer/pathUtil.js +29 -35
  397. package/shared/analyzer/pathUtil.js.map +1 -0
  398. package/shared/analyzer/patterns.d.ts +11 -0
  399. package/shared/analyzer/patterns.js +231 -253
  400. package/shared/analyzer/patterns.js.map +1 -0
  401. package/shared/analyzer/scan.d.ts +62 -0
  402. package/shared/analyzer/scan.js +451 -442
  403. package/shared/analyzer/scan.js.map +1 -0
  404. package/shared/analyzer/scanControl.d.ts +11 -0
  405. package/shared/analyzer/scanControl.js +62 -0
  406. package/shared/analyzer/scanControl.js.map +1 -0
  407. package/shared/analyzer/security.d.ts +18 -0
  408. package/shared/analyzer/security.js +159 -159
  409. package/shared/analyzer/security.js.map +1 -0
  410. package/shared/analyzer/services.d.ts +5 -0
  411. package/shared/analyzer/services.js +141 -138
  412. package/shared/analyzer/services.js.map +1 -0
  413. package/shared/analyzer/stack.d.ts +6 -0
  414. package/shared/analyzer/stack.js +134 -141
  415. package/shared/analyzer/stack.js.map +1 -0
  416. package/shared/analyzer/tour.d.ts +2 -0
  417. package/shared/analyzer/tour.js +45 -53
  418. package/shared/analyzer/tour.js.map +1 -0
  419. package/shared/analyzer/util.d.ts +8 -0
  420. package/shared/analyzer/util.js +130 -76
  421. package/shared/analyzer/util.js.map +1 -0
  422. package/shared/analyzer/workflows.d.ts +8 -0
  423. package/shared/analyzer/workflows.js +139 -134
  424. package/shared/analyzer/workflows.js.map +1 -0
  425. package/shared/contracts.d.ts +250 -0
  426. package/shared/contracts.js +2 -0
  427. package/shared/contracts.js.map +1 -0
  428. package/shared/diagram/aiFacts.d.ts +35 -0
  429. package/shared/diagram/aiFacts.js +102 -105
  430. package/shared/diagram/aiFacts.js.map +1 -0
  431. package/shared/diagram/aiMermaid.d.ts +5 -0
  432. package/shared/diagram/aiMermaid.js +46 -45
  433. package/shared/diagram/aiMermaid.js.map +1 -0
  434. package/shared/diagram/atlas.d.ts +16 -0
  435. package/shared/diagram/atlas.js +51 -60
  436. package/shared/diagram/atlas.js.map +1 -0
  437. package/shared/diagram/mermaid.d.ts +43 -0
  438. package/shared/diagram/mermaid.js +348 -370
  439. package/shared/diagram/mermaid.js.map +1 -0
  440. package/shared/review/contracts.d.ts +95 -0
  441. package/shared/review/contracts.js +2 -0
  442. package/shared/review/contracts.js.map +1 -0
  443. package/shared/review/review.d.ts +10 -0
  444. package/shared/review/review.js +184 -0
  445. package/shared/review/review.js.map +1 -0
  446. package/shared/search/query.d.ts +32 -0
  447. package/shared/search/query.js +395 -388
  448. package/shared/search/query.js.map +1 -0
@@ -1,30 +1,81 @@
1
1
  // Small text utilities shared by the language analyzers.
2
-
3
2
  // Blanks out comments while preserving string contents, offsets and line
4
3
  // numbers (every matched character becomes a space except newlines), so
5
4
  // positions reported afterwards still line up with the original source.
6
5
  export function blankComments(source, { block = true, line = true, lineChar = '//' } = {}) {
7
- let out = source;
8
- if (block) {
9
- out = out.replace(/\/\*[\s\S]*?\*\//g, (m) => m.replace(/[^\n]/g, ' '));
10
- }
11
- if (line && lineChar === '//') {
12
- out = out.replace(/\/\/[^\n]*/g, (m) => ' '.repeat(m.length));
13
- }
14
- if (line && lineChar === '#') {
15
- out = out.replace(/^[ \t]*#[^\n]*/gm, (m) => ' '.repeat(m.length));
16
- }
17
- return out;
6
+ let out = source;
7
+ if (block) {
8
+ out = out.replace(/\/\*[\s\S]*?\*\//g, (m) => m.replace(/[^\n]/g, ' '));
9
+ }
10
+ if (line && lineChar === '//') {
11
+ out = out.replace(/\/\/[^\n]*/g, (m) => ' '.repeat(m.length));
12
+ }
13
+ if (line && lineChar === '#') {
14
+ out = out.replace(/^[ \t]*#[^\n]*/gm, (m) => ' '.repeat(m.length));
15
+ }
16
+ return out;
17
+ }
18
+ // Keep only JavaScript/TypeScript code positions. Import regexes still read the
19
+ // original source for module strings, but use this mask to reject keywords
20
+ // inside comments and quoted examples. Newlines and offsets stay unchanged.
21
+ export function jsCodeMask(source) {
22
+ // Regex match indexes are UTF-16 offsets, so keep the same indexing even
23
+ // when source contains emoji or other astral characters.
24
+ const chars = String(source).split('');
25
+ const mask = chars.slice();
26
+ let state = 'code';
27
+ const blank = (i) => { if (chars[i] !== '\n')
28
+ mask[i] = ' '; };
29
+ for (let i = 0; i < chars.length; i++) {
30
+ const c = chars[i];
31
+ const next = chars[i + 1];
32
+ if (state === 'code') {
33
+ if (c === '/' && next === '/') {
34
+ blank(i);
35
+ blank(++i);
36
+ state = 'line';
37
+ }
38
+ else if (c === '/' && next === '*') {
39
+ blank(i);
40
+ blank(++i);
41
+ state = 'block';
42
+ }
43
+ else if (c === "'" || c === '"' || c === '`') {
44
+ blank(i);
45
+ state = c;
46
+ }
47
+ }
48
+ else if (state === 'line') {
49
+ if (c === '\n')
50
+ state = 'code';
51
+ else
52
+ blank(i);
53
+ }
54
+ else if (state === 'block') {
55
+ blank(i);
56
+ if (c === '*' && next === '/') {
57
+ blank(++i);
58
+ state = 'code';
59
+ }
60
+ }
61
+ else {
62
+ blank(i);
63
+ if (c === '\\' && next !== undefined)
64
+ blank(++i);
65
+ else if (c === state)
66
+ state = 'code';
67
+ }
68
+ }
69
+ return mask.join('');
18
70
  }
19
-
20
71
  export function lineOf(source, index) {
21
- let line = 1;
22
- for (let i = 0; i < index && i < source.length; i++) {
23
- if (source.charCodeAt(i) === 10) line++;
24
- }
25
- return line;
72
+ let line = 1;
73
+ for (let i = 0; i < index && i < source.length; i++) {
74
+ if (source.charCodeAt(i) === 10)
75
+ line++;
76
+ }
77
+ return line;
26
78
  }
27
-
28
79
  // The same answer as `lineOf`, for callers that need many of them from one
29
80
  // source. `lineOf` walks from byte 0 every time, which is nothing once and
30
81
  // quadratic when a 200KB file reports 300 imports, functions and classes — each
@@ -34,56 +85,58 @@ export function lineOf(source, index) {
34
85
  // The table is built on first use rather than up front, so a file that reports
35
86
  // no positions at all pays nothing for asking.
36
87
  export function lineCounter(source) {
37
- const s = String(source);
38
- let starts = null;
39
-
40
- return function lineAt(index) {
41
- if (!starts) {
42
- starts = [0];
43
- for (let i = 0; i < s.length; i++) {
44
- if (s.charCodeAt(i) === 10) starts.push(i + 1);
45
- }
46
- }
47
- // The line containing `index` is the last one that starts at or before it.
48
- let lo = 0;
49
- let hi = starts.length - 1;
50
- while (lo < hi) {
51
- const mid = (lo + hi + 1) >> 1;
52
- if (starts[mid] <= index) lo = mid;
53
- else hi = mid - 1;
54
- }
55
- return lo + 1;
56
- };
88
+ const s = String(source);
89
+ let starts = null;
90
+ return function lineAt(index) {
91
+ if (!starts) {
92
+ starts = [0];
93
+ for (let i = 0; i < s.length; i++) {
94
+ if (s.charCodeAt(i) === 10)
95
+ starts.push(i + 1);
96
+ }
97
+ }
98
+ // The line containing `index` is the last one that starts at or before it.
99
+ let lo = 0;
100
+ let hi = starts.length - 1;
101
+ while (lo < hi) {
102
+ const mid = (lo + hi + 1) >> 1;
103
+ if (starts[mid] <= index)
104
+ lo = mid;
105
+ else
106
+ hi = mid - 1;
107
+ }
108
+ return lo + 1;
109
+ };
57
110
  }
58
-
59
111
  // Returns the index just past the brace that closes the one at openIndex.
60
112
  // Best-effort: a brace inside a string can throw the count off, which is an
61
113
  // accepted trade of the no-parser approach.
62
114
  export function braceBodyEnd(source, openIndex) {
63
- let depth = 0;
64
- for (let i = openIndex; i < source.length; i++) {
65
- const c = source[i];
66
- if (c === '{') depth++;
67
- else if (c === '}') {
68
- depth--;
69
- if (depth === 0) return i + 1;
115
+ let depth = 0;
116
+ for (let i = openIndex; i < source.length; i++) {
117
+ const c = source[i];
118
+ if (c === '{')
119
+ depth++;
120
+ else if (c === '}') {
121
+ depth--;
122
+ if (depth === 0)
123
+ return i + 1;
124
+ }
70
125
  }
71
- }
72
- return source.length;
126
+ return source.length;
73
127
  }
74
-
75
128
  export function uniqueBy(items, key) {
76
- const seen = new Set();
77
- const out = [];
78
- for (const item of items) {
79
- const k = key(item);
80
- if (seen.has(k)) continue;
81
- seen.add(k);
82
- out.push(item);
83
- }
84
- return out;
129
+ const seen = new Set();
130
+ const out = [];
131
+ for (const item of items) {
132
+ const k = key(item);
133
+ if (seen.has(k))
134
+ continue;
135
+ seen.add(k);
136
+ out.push(item);
137
+ }
138
+ return out;
85
139
  }
86
-
87
140
  // Which of `names` is called inside `body`? Returns the distinct ones, in the
88
141
  // order they first appear.
89
142
  //
@@ -99,25 +152,26 @@ export function uniqueBy(items, key) {
99
152
  // to `method`: this is a best-effort text scan, not a resolver, and a method
100
153
  // name that matches a local function is more likely that function than not.
101
154
  const CALL_TOKEN = /(?<![\w$])([A-Za-z_$][\w$]*)\s*\(/g;
102
-
103
155
  export function callsWithin(body, names) {
104
- const found = [];
105
- const seen = new Set();
106
- for (const m of String(body).matchAll(CALL_TOKEN)) {
107
- const name = m[1];
108
- if (seen.has(name) || !names.has(name)) continue;
109
- seen.add(name);
110
- found.push(name);
111
- }
112
- return found;
156
+ const found = [];
157
+ const seen = new Set();
158
+ for (const m of String(body).matchAll(CALL_TOKEN)) {
159
+ const name = m[1];
160
+ if (seen.has(name) || !names.has(name))
161
+ continue;
162
+ seen.add(name);
163
+ found.push(name);
164
+ }
165
+ return found;
113
166
  }
114
-
115
167
  // The order the callee was declared in, first declaration winning — so the call
116
168
  // list comes out in the same order the per-name loop produced it.
117
169
  export function declarationOrder(fns) {
118
- const order = new Map();
119
- fns.forEach((f, i) => {
120
- if (!order.has(f.name)) order.set(f.name, i);
121
- });
122
- return order;
170
+ const order = new Map();
171
+ fns.forEach((f, i) => {
172
+ if (!order.has(f.name))
173
+ order.set(f.name, i);
174
+ });
175
+ return order;
123
176
  }
177
+ //# sourceMappingURL=util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/shared/analyzer/util.ts"],"names":[],"mappings":"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","sourcesContent":["// Small text utilities shared by the language analyzers.\n\n// Blanks out comments while preserving string contents, offsets and line\n// numbers (every matched character becomes a space except newlines), so\n// positions reported afterwards still line up with the original source.\nexport function blankComments(source, { block = true, line = true, lineChar = '//' }: Record<string, any> = {}) {\n let out = source;\n if (block) {\n out = out.replace(/\\/\\*[\\s\\S]*?\\*\\//g, (m) => m.replace(/[^\\n]/g, ' '));\n }\n if (line && lineChar === '//') {\n out = out.replace(/\\/\\/[^\\n]*/g, (m) => ' '.repeat(m.length));\n }\n if (line && lineChar === '#') {\n out = out.replace(/^[ \\t]*#[^\\n]*/gm, (m) => ' '.repeat(m.length));\n }\n return out;\n}\n\n// Keep only JavaScript/TypeScript code positions. Import regexes still read the\n// original source for module strings, but use this mask to reject keywords\n// inside comments and quoted examples. Newlines and offsets stay unchanged.\nexport function jsCodeMask(source) {\n // Regex match indexes are UTF-16 offsets, so keep the same indexing even\n // when source contains emoji or other astral characters.\n const chars = String(source).split('');\n const mask = chars.slice();\n let state = 'code';\n const blank = (i) => { if (chars[i] !== '\\n') mask[i] = ' '; };\n\n for (let i = 0; i < chars.length; i++) {\n const c = chars[i];\n const next = chars[i + 1];\n if (state === 'code') {\n if (c === '/' && next === '/') {\n blank(i); blank(++i); state = 'line';\n } else if (c === '/' && next === '*') {\n blank(i); blank(++i); state = 'block';\n } else if (c === \"'\" || c === '\"' || c === '`') {\n blank(i); state = c;\n }\n } else if (state === 'line') {\n if (c === '\\n') state = 'code';\n else blank(i);\n } else if (state === 'block') {\n blank(i);\n if (c === '*' && next === '/') { blank(++i); state = 'code'; }\n } else {\n blank(i);\n if (c === '\\\\' && next !== undefined) blank(++i);\n else if (c === state) state = 'code';\n }\n }\n return mask.join('');\n}\n\nexport function lineOf(source, index) {\n let line = 1;\n for (let i = 0; i < index && i < source.length; i++) {\n if (source.charCodeAt(i) === 10) line++;\n }\n return line;\n}\n\n// The same answer as `lineOf`, for callers that need many of them from one\n// source. `lineOf` walks from byte 0 every time, which is nothing once and\n// quadratic when a 200KB file reports 300 imports, functions and classes — each\n// scanning an average of half the file. This walks the source once, records\n// where every line starts, and binary-searches that table per lookup.\n//\n// The table is built on first use rather than up front, so a file that reports\n// no positions at all pays nothing for asking.\nexport function lineCounter(source) {\n const s = String(source);\n let starts = null;\n\n return function lineAt(index) {\n if (!starts) {\n starts = [0];\n for (let i = 0; i < s.length; i++) {\n if (s.charCodeAt(i) === 10) starts.push(i + 1);\n }\n }\n // The line containing `index` is the last one that starts at or before it.\n let lo = 0;\n let hi = starts.length - 1;\n while (lo < hi) {\n const mid = (lo + hi + 1) >> 1;\n if (starts[mid] <= index) lo = mid;\n else hi = mid - 1;\n }\n return lo + 1;\n };\n}\n\n// Returns the index just past the brace that closes the one at openIndex.\n// Best-effort: a brace inside a string can throw the count off, which is an\n// accepted trade of the no-parser approach.\nexport function braceBodyEnd(source, openIndex) {\n let depth = 0;\n for (let i = openIndex; i < source.length; i++) {\n const c = source[i];\n if (c === '{') depth++;\n else if (c === '}') {\n depth--;\n if (depth === 0) return i + 1;\n }\n }\n return source.length;\n}\n\nexport function uniqueBy(items, key) {\n const seen = new Set();\n const out = [];\n for (const item of items) {\n const k = key(item);\n if (seen.has(k)) continue;\n seen.add(k);\n out.push(item);\n }\n return out;\n}\n\n// Which of `names` is called inside `body`? Returns the distinct ones, in the\n// order they first appear.\n//\n// This replaced the obvious version — compile `\\bNAME\\s*\\(` per candidate and\n// test the body with it — which is O(functions²) in compiled regexes. A file\n// with 2,300 functions built five million of them, and profiling put two thirds\n// of the whole parse phase in that loop and the `escapeRe` feeding it. Reading\n// the body once and looking each token up in a Set does the same work in one\n// pass over the text.\n//\n// `$` counts as part of an identifier, as JavaScript has it, so `$foo(` is a\n// call to `$foo` and not to `foo`. A call written `obj.method(` counts as a call\n// to `method`: this is a best-effort text scan, not a resolver, and a method\n// name that matches a local function is more likely that function than not.\nconst CALL_TOKEN = /(?<![\\w$])([A-Za-z_$][\\w$]*)\\s*\\(/g;\n\nexport function callsWithin(body, names) {\n const found = [];\n const seen = new Set();\n for (const m of String(body).matchAll(CALL_TOKEN)) {\n const name = m[1];\n if (seen.has(name) || !names.has(name)) continue;\n seen.add(name);\n found.push(name);\n }\n return found;\n}\n\n// The order the callee was declared in, first declaration winning — so the call\n// list comes out in the same order the per-name loop produced it.\nexport function declarationOrder(fns) {\n const order = new Map();\n fns.forEach((f, i) => {\n if (!order.has(f.name)) order.set(f.name, i);\n });\n return order;\n}\n"]}
@@ -0,0 +1,8 @@
1
+ export declare function analyzeWorkflows(source: any): Promise<any[]>;
2
+ export declare function parseWorkflowYaml(text: any, filePath?: string, fileName?: string): {
3
+ file: string;
4
+ fileName: string;
5
+ name: string;
6
+ triggers: any[];
7
+ jobs: any[];
8
+ };
@@ -1,143 +1,148 @@
1
1
  // GitHub Actions & CI/CD workflow parser.
2
2
  // Pure isomorphic analyzer — parses YAML workflow files without external dependencies.
3
-
4
3
  export async function analyzeWorkflows(source) {
5
- const workflows = [];
6
- const entries = await source.list('.github/workflows').catch(() => []);
7
- const ymlFiles = entries.filter((e) => e.type === 'file' && /\.(ya?ml)$/i.test(e.name));
8
-
9
- for (const entry of ymlFiles) {
10
- const raw = await source.read(entry.path).catch(() => '');
11
- if (!raw) continue;
12
- const parsed = parseWorkflowYaml(raw, entry.path, entry.name);
13
- if (parsed) workflows.push(parsed);
14
- }
15
-
16
- return workflows;
4
+ const workflows = [];
5
+ const entries = await source.list('.github/workflows').catch(() => []);
6
+ const ymlFiles = entries.filter((e) => e.type === 'file' && /\.(ya?ml)$/i.test(e.name));
7
+ for (const entry of ymlFiles) {
8
+ const raw = await source.read(entry.path).catch(() => '');
9
+ if (!raw)
10
+ continue;
11
+ const parsed = parseWorkflowYaml(raw, entry.path, entry.name);
12
+ if (parsed)
13
+ workflows.push(parsed);
14
+ }
15
+ return workflows;
17
16
  }
18
-
19
17
  export function parseWorkflowYaml(text, filePath = '', fileName = '') {
20
- const lines = text.split('\n');
21
- let name = fileName.replace(/\.ya?ml$/i, '');
22
- const triggers = [];
23
- const jobs = [];
24
-
25
- let currentSection = null;
26
- let currentJob = null;
27
- let currentStep = null;
28
- let inOnSection = false;
29
-
30
- for (let i = 0; i < lines.length; i++) {
31
- const line = lines[i];
32
- const trimmed = line.trim();
33
- if (!trimmed || trimmed.startsWith('#')) continue;
34
-
35
- const indent = line.search(/\S/);
36
-
37
- // Top-level name: ...
38
- if (indent === 0 && /^name\s*:\s*(.+)$/i.test(trimmed)) {
39
- const m = trimmed.match(/^name\s*:\s*['"]?([^'"]+)['"]?/i);
40
- if (m) name = m[1].trim();
41
- continue;
42
- }
43
-
44
- // Top-level on: ...
45
- if (indent === 0 && /^on\s*:/i.test(trimmed)) {
46
- currentSection = 'on';
47
- inOnSection = true;
48
- const rest = trimmed.replace(/^on\s*:\s*/i, '').trim();
49
- if (rest) {
50
- if (rest.startsWith('[') && rest.endsWith(']')) {
51
- const list = rest.slice(1, -1).split(',').map((s) => s.trim().replace(/^['"]|['"]$/g, ''));
52
- triggers.push(...list.filter(Boolean));
53
- } else {
54
- triggers.push(rest.replace(/^['"]|['"]$/g, ''));
18
+ const lines = text.split('\n');
19
+ let name = fileName.replace(/\.ya?ml$/i, '');
20
+ const triggers = [];
21
+ const jobs = [];
22
+ let currentSection = null;
23
+ let currentJob = null;
24
+ let currentStep = null;
25
+ let inOnSection = false;
26
+ for (let i = 0; i < lines.length; i++) {
27
+ const line = lines[i];
28
+ const trimmed = line.trim();
29
+ if (!trimmed || trimmed.startsWith('#'))
30
+ continue;
31
+ const indent = line.search(/\S/);
32
+ // Top-level name: ...
33
+ if (indent === 0 && /^name\s*:\s*(.+)$/i.test(trimmed)) {
34
+ const m = trimmed.match(/^name\s*:\s*['"]?([^'"]+)['"]?/i);
35
+ if (m)
36
+ name = m[1].trim();
37
+ continue;
55
38
  }
56
- }
57
- continue;
58
- }
59
-
60
- // Top-level jobs: ...
61
- if (indent === 0 && /^jobs\s*:/i.test(trimmed)) {
62
- currentSection = 'jobs';
63
- inOnSection = false;
64
- continue;
65
- }
66
-
67
- if (currentSection === 'on') {
68
- if (indent === 0) {
69
- currentSection = null;
70
- inOnSection = false;
71
- } else {
72
- const trigMatch = trimmed.match(/^([a-zA-Z0-9_-]+)\s*:/);
73
- const listMatch = trimmed.match(/^-\s*([a-zA-Z0-9_-]+)/);
74
- if (trigMatch && indent <= 4) triggers.push(trigMatch[1]);
75
- else if (listMatch && indent <= 4) triggers.push(listMatch[1]);
76
- }
77
- }
78
-
79
- if (currentSection === 'jobs' && indent > 0) {
80
- // Job declaration at indent 2 (or top under jobs)
81
- if (indent === 2 && trimmed.endsWith(':')) {
82
- const jobId = trimmed.replace(/:$/, '').trim();
83
- currentJob = {
84
- id: jobId,
85
- name: jobId,
86
- runsOn: 'ubuntu-latest',
87
- needs: [],
88
- steps: [],
89
- };
90
- jobs.push(currentJob);
91
- currentStep = null;
92
- continue;
93
- }
94
-
95
- if (!currentJob) continue;
96
-
97
- // Inside a job:
98
- if (/^name\s*:\s*(.+)$/i.test(trimmed) && indent <= 6 && !currentStep) {
99
- const m = trimmed.match(/^name\s*:\s*['"]?([^'"]+)['"]?/i);
100
- if (m) currentJob.name = m[1].trim();
101
- } else if (/^runs-on\s*:\s*(.+)$/i.test(trimmed)) {
102
- const m = trimmed.match(/^runs-on\s*:\s*['"]?([^'"]+)['"]?/i);
103
- if (m) currentJob.runsOn = m[1].trim();
104
- } else if (/^needs\s*:\s*(.+)$/i.test(trimmed)) {
105
- const rest = trimmed.replace(/^needs\s*:\s*/i, '').trim();
106
- if (rest.startsWith('[') && rest.endsWith(']')) {
107
- const list = rest.slice(1, -1).split(',').map((s) => s.trim().replace(/^['"]|['"]$/g, ''));
108
- currentJob.needs.push(...list.filter(Boolean));
109
- } else if (rest) {
110
- currentJob.needs.push(rest.replace(/^['"]|['"]$/g, ''));
39
+ // Top-level on: ...
40
+ if (indent === 0 && /^on\s*:/i.test(trimmed)) {
41
+ currentSection = 'on';
42
+ inOnSection = true;
43
+ const rest = trimmed.replace(/^on\s*:\s*/i, '').trim();
44
+ if (rest) {
45
+ if (rest.startsWith('[') && rest.endsWith(']')) {
46
+ const list = rest.slice(1, -1).split(',').map((s) => s.trim().replace(/^['"]|['"]$/g, ''));
47
+ triggers.push(...list.filter(Boolean));
48
+ }
49
+ else {
50
+ triggers.push(rest.replace(/^['"]|['"]$/g, ''));
51
+ }
52
+ }
53
+ continue;
54
+ }
55
+ // Top-level jobs: ...
56
+ if (indent === 0 && /^jobs\s*:/i.test(trimmed)) {
57
+ currentSection = 'jobs';
58
+ inOnSection = false;
59
+ continue;
60
+ }
61
+ if (currentSection === 'on') {
62
+ if (indent === 0) {
63
+ currentSection = null;
64
+ inOnSection = false;
65
+ }
66
+ else {
67
+ const trigMatch = trimmed.match(/^([a-zA-Z0-9_-]+)\s*:/);
68
+ const listMatch = trimmed.match(/^-\s*([a-zA-Z0-9_-]+)/);
69
+ if (trigMatch && indent <= 4)
70
+ triggers.push(trigMatch[1]);
71
+ else if (listMatch && indent <= 4)
72
+ triggers.push(listMatch[1]);
73
+ }
74
+ }
75
+ if (currentSection === 'jobs' && indent > 0) {
76
+ // Job declaration at indent 2 (or top under jobs)
77
+ if (indent === 2 && trimmed.endsWith(':')) {
78
+ const jobId = trimmed.replace(/:$/, '').trim();
79
+ currentJob = {
80
+ id: jobId,
81
+ name: jobId,
82
+ runsOn: 'ubuntu-latest',
83
+ needs: [],
84
+ steps: [],
85
+ };
86
+ jobs.push(currentJob);
87
+ currentStep = null;
88
+ continue;
89
+ }
90
+ if (!currentJob)
91
+ continue;
92
+ // Inside a job:
93
+ if (/^name\s*:\s*(.+)$/i.test(trimmed) && indent <= 6 && !currentStep) {
94
+ const m = trimmed.match(/^name\s*:\s*['"]?([^'"]+)['"]?/i);
95
+ if (m)
96
+ currentJob.name = m[1].trim();
97
+ }
98
+ else if (/^runs-on\s*:\s*(.+)$/i.test(trimmed)) {
99
+ const m = trimmed.match(/^runs-on\s*:\s*['"]?([^'"]+)['"]?/i);
100
+ if (m)
101
+ currentJob.runsOn = m[1].trim();
102
+ }
103
+ else if (/^needs\s*:\s*(.+)$/i.test(trimmed)) {
104
+ const rest = trimmed.replace(/^needs\s*:\s*/i, '').trim();
105
+ if (rest.startsWith('[') && rest.endsWith(']')) {
106
+ const list = rest.slice(1, -1).split(',').map((s) => s.trim().replace(/^['"]|['"]$/g, ''));
107
+ currentJob.needs.push(...list.filter(Boolean));
108
+ }
109
+ else if (rest) {
110
+ currentJob.needs.push(rest.replace(/^['"]|['"]$/g, ''));
111
+ }
112
+ }
113
+ else if (/^-\s*needs\s*:\s*(.+)$/i.test(trimmed)) {
114
+ const m = trimmed.match(/^-\s*needs\s*:\s*(.+)$/i);
115
+ if (m)
116
+ currentJob.needs.push(m[1].trim());
117
+ }
118
+ else if (trimmed.startsWith('-') && (indent >= 4 || trimmed.startsWith('- uses:') || trimmed.startsWith('- name:'))) {
119
+ // Step start
120
+ const stepNameMatch = trimmed.match(/^-\s*name\s*:\s*['"]?([^'"]+)['"]?/i);
121
+ const stepUsesMatch = trimmed.match(/^-\s*uses\s*:\s*['"]?([^'"]+)['"]?/i);
122
+ const stepRunMatch = trimmed.match(/^-\s*run\s*:\s*(.+)$/i);
123
+ currentStep = {
124
+ name: stepNameMatch ? stepNameMatch[1] : (stepUsesMatch ? stepUsesMatch[1] : (stepRunMatch ? stepRunMatch[1] : 'Step')),
125
+ uses: stepUsesMatch ? stepUsesMatch[1] : null,
126
+ run: stepRunMatch ? stepRunMatch[1] : null,
127
+ };
128
+ currentJob.steps.push(currentStep);
129
+ }
130
+ else if (currentStep) {
131
+ const stepUsesMatch = trimmed.match(/^uses\s*:\s*['"]?([^'"]+)['"]?/i);
132
+ const stepRunMatch = trimmed.match(/^run\s*:\s*(.+)$/i);
133
+ if (stepUsesMatch)
134
+ currentStep.uses = stepUsesMatch[1];
135
+ if (stepRunMatch)
136
+ currentStep.run = stepRunMatch[1];
137
+ }
111
138
  }
112
- } else if (/^-\s*needs\s*:\s*(.+)$/i.test(trimmed)) {
113
- const m = trimmed.match(/^-\s*needs\s*:\s*(.+)$/i);
114
- if (m) currentJob.needs.push(m[1].trim());
115
- } else if (trimmed.startsWith('-') && (indent >= 4 || trimmed.startsWith('- uses:') || trimmed.startsWith('- name:'))) {
116
- // Step start
117
- const stepNameMatch = trimmed.match(/^-\s*name\s*:\s*['"]?([^'"]+)['"]?/i);
118
- const stepUsesMatch = trimmed.match(/^-\s*uses\s*:\s*['"]?([^'"]+)['"]?/i);
119
- const stepRunMatch = trimmed.match(/^-\s*run\s*:\s*(.+)$/i);
120
-
121
- currentStep = {
122
- name: stepNameMatch ? stepNameMatch[1] : (stepUsesMatch ? stepUsesMatch[1] : (stepRunMatch ? stepRunMatch[1] : 'Step')),
123
- uses: stepUsesMatch ? stepUsesMatch[1] : null,
124
- run: stepRunMatch ? stepRunMatch[1] : null,
125
- };
126
- currentJob.steps.push(currentStep);
127
- } else if (currentStep) {
128
- const stepUsesMatch = trimmed.match(/^uses\s*:\s*['"]?([^'"]+)['"]?/i);
129
- const stepRunMatch = trimmed.match(/^run\s*:\s*(.+)$/i);
130
- if (stepUsesMatch) currentStep.uses = stepUsesMatch[1];
131
- if (stepRunMatch) currentStep.run = stepRunMatch[1];
132
- }
133
139
  }
134
- }
135
-
136
- return {
137
- file: filePath,
138
- fileName,
139
- name: name || fileName,
140
- triggers: [...new Set(triggers.filter(Boolean))],
141
- jobs,
142
- };
140
+ return {
141
+ file: filePath,
142
+ fileName,
143
+ name: name || fileName,
144
+ triggers: [...new Set(triggers.filter(Boolean))],
145
+ jobs,
146
+ };
143
147
  }
148
+ //# sourceMappingURL=workflows.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflows.js","sourceRoot":"","sources":["../../src/shared/analyzer/workflows.ts"],"names":[],"mappings":"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","sourcesContent":["// GitHub Actions & CI/CD workflow parser.\n// Pure isomorphic analyzer — parses YAML workflow files without external dependencies.\n\nexport async function analyzeWorkflows(source) {\n const workflows = [];\n const entries = await source.list('.github/workflows').catch(() => []);\n const ymlFiles = entries.filter((e) => e.type === 'file' && /\\.(ya?ml)$/i.test(e.name));\n\n for (const entry of ymlFiles) {\n const raw = await source.read(entry.path).catch(() => '');\n if (!raw) continue;\n const parsed = parseWorkflowYaml(raw, entry.path, entry.name);\n if (parsed) workflows.push(parsed);\n }\n\n return workflows;\n}\n\nexport function parseWorkflowYaml(text, filePath = '', fileName = '') {\n const lines = text.split('\\n');\n let name = fileName.replace(/\\.ya?ml$/i, '');\n const triggers = [];\n const jobs = [];\n\n let currentSection = null;\n let currentJob = null;\n let currentStep = null;\n let inOnSection = false;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n\n const indent = line.search(/\\S/);\n\n // Top-level name: ...\n if (indent === 0 && /^name\\s*:\\s*(.+)$/i.test(trimmed)) {\n const m = trimmed.match(/^name\\s*:\\s*['\"]?([^'\"]+)['\"]?/i);\n if (m) name = m[1].trim();\n continue;\n }\n\n // Top-level on: ...\n if (indent === 0 && /^on\\s*:/i.test(trimmed)) {\n currentSection = 'on';\n inOnSection = true;\n const rest = trimmed.replace(/^on\\s*:\\s*/i, '').trim();\n if (rest) {\n if (rest.startsWith('[') && rest.endsWith(']')) {\n const list = rest.slice(1, -1).split(',').map((s) => s.trim().replace(/^['\"]|['\"]$/g, ''));\n triggers.push(...list.filter(Boolean));\n } else {\n triggers.push(rest.replace(/^['\"]|['\"]$/g, ''));\n }\n }\n continue;\n }\n\n // Top-level jobs: ...\n if (indent === 0 && /^jobs\\s*:/i.test(trimmed)) {\n currentSection = 'jobs';\n inOnSection = false;\n continue;\n }\n\n if (currentSection === 'on') {\n if (indent === 0) {\n currentSection = null;\n inOnSection = false;\n } else {\n const trigMatch = trimmed.match(/^([a-zA-Z0-9_-]+)\\s*:/);\n const listMatch = trimmed.match(/^-\\s*([a-zA-Z0-9_-]+)/);\n if (trigMatch && indent <= 4) triggers.push(trigMatch[1]);\n else if (listMatch && indent <= 4) triggers.push(listMatch[1]);\n }\n }\n\n if (currentSection === 'jobs' && indent > 0) {\n // Job declaration at indent 2 (or top under jobs)\n if (indent === 2 && trimmed.endsWith(':')) {\n const jobId = trimmed.replace(/:$/, '').trim();\n currentJob = {\n id: jobId,\n name: jobId,\n runsOn: 'ubuntu-latest',\n needs: [],\n steps: [],\n };\n jobs.push(currentJob);\n currentStep = null;\n continue;\n }\n\n if (!currentJob) continue;\n\n // Inside a job:\n if (/^name\\s*:\\s*(.+)$/i.test(trimmed) && indent <= 6 && !currentStep) {\n const m = trimmed.match(/^name\\s*:\\s*['\"]?([^'\"]+)['\"]?/i);\n if (m) currentJob.name = m[1].trim();\n } else if (/^runs-on\\s*:\\s*(.+)$/i.test(trimmed)) {\n const m = trimmed.match(/^runs-on\\s*:\\s*['\"]?([^'\"]+)['\"]?/i);\n if (m) currentJob.runsOn = m[1].trim();\n } else if (/^needs\\s*:\\s*(.+)$/i.test(trimmed)) {\n const rest = trimmed.replace(/^needs\\s*:\\s*/i, '').trim();\n if (rest.startsWith('[') && rest.endsWith(']')) {\n const list = rest.slice(1, -1).split(',').map((s) => s.trim().replace(/^['\"]|['\"]$/g, ''));\n currentJob.needs.push(...list.filter(Boolean));\n } else if (rest) {\n currentJob.needs.push(rest.replace(/^['\"]|['\"]$/g, ''));\n }\n } else if (/^-\\s*needs\\s*:\\s*(.+)$/i.test(trimmed)) {\n const m = trimmed.match(/^-\\s*needs\\s*:\\s*(.+)$/i);\n if (m) currentJob.needs.push(m[1].trim());\n } else if (trimmed.startsWith('-') && (indent >= 4 || trimmed.startsWith('- uses:') || trimmed.startsWith('- name:'))) {\n // Step start\n const stepNameMatch = trimmed.match(/^-\\s*name\\s*:\\s*['\"]?([^'\"]+)['\"]?/i);\n const stepUsesMatch = trimmed.match(/^-\\s*uses\\s*:\\s*['\"]?([^'\"]+)['\"]?/i);\n const stepRunMatch = trimmed.match(/^-\\s*run\\s*:\\s*(.+)$/i);\n\n currentStep = {\n name: stepNameMatch ? stepNameMatch[1] : (stepUsesMatch ? stepUsesMatch[1] : (stepRunMatch ? stepRunMatch[1] : 'Step')),\n uses: stepUsesMatch ? stepUsesMatch[1] : null,\n run: stepRunMatch ? stepRunMatch[1] : null,\n };\n currentJob.steps.push(currentStep);\n } else if (currentStep) {\n const stepUsesMatch = trimmed.match(/^uses\\s*:\\s*['\"]?([^'\"]+)['\"]?/i);\n const stepRunMatch = trimmed.match(/^run\\s*:\\s*(.+)$/i);\n if (stepUsesMatch) currentStep.uses = stepUsesMatch[1];\n if (stepRunMatch) currentStep.run = stepRunMatch[1];\n }\n }\n }\n\n return {\n file: filePath,\n fileName,\n name: name || fileName,\n triggers: [...new Set(triggers.filter(Boolean))],\n jobs,\n };\n}\n"]}