codebase-onboarder 0.5.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 +196 -47
  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 +449 -0
  8. package/cli/explorer/advanced.js.map +1 -0
  9. package/cli/explorer/app.d.ts +1 -0
  10. package/cli/explorer/app.js +396 -229
  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 +400 -162
  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 +73 -0
  23. package/cli/explorer/github.js.map +1 -0
  24. package/cli/explorer/graphs.d.ts +7 -0
  25. package/cli/explorer/graphs.js +173 -0
  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 +184 -95
  35. package/cli/explorer/session.js.map +1 -0
  36. package/cli/explorer/views.d.ts +19 -0
  37. package/cli/explorer/views.js +496 -412
  38. package/cli/explorer/views.js.map +1 -0
  39. package/cli/explorer/wrap.d.ts +1 -0
  40. package/cli/explorer/wrap.js +33 -0
  41. package/cli/explorer/wrap.js.map +1 -0
  42. package/cli/main.d.ts +1 -0
  43. package/cli/main.js +235 -138
  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 +55 -35
  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 +165 -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 +60 -0
  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 -37
  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 +79 -0
  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
@@ -27,244 +27,236 @@
27
27
  // Bare words stay forgiving, because a half-remembered name should still find
28
28
  // the file. That split is the whole design: `matchesPathFilters` is a gate,
29
29
  // `scorePath`/`scoreContent` are a ranking.
30
-
31
30
  import { baseName, extOf, isTestPath } from '../analyzer/pathUtil.js';
32
-
33
31
  // A regex longer than this is either a paste accident or an attempt to make the
34
32
  // tab hang. Real patterns people type at a search box are two orders of
35
33
  // magnitude shorter than the cap.
36
34
  const MAX_REGEX_LENGTH = 200;
37
-
38
35
  // Quoted phrase | /regex/flags | bare token. Order matters: the quote and the
39
36
  // slash have to win before `\S+` gets a chance to swallow them whole.
40
37
  const TOKEN_RE = /"([^"]*)"|\/([^\s/]+)\/([gimsuy]*)|\S+/g;
41
-
42
38
  // Ranges are capped as they are collected. A one-letter query against a
43
39
  // minified bundle can match tens of thousands of times, and the UI only ever
44
40
  // paints the first screenful.
45
41
  const MAX_RANGES = 400;
46
-
47
42
  function fold(text, caseSensitive) {
48
- return caseSensitive ? text : text.toLowerCase();
43
+ return caseSensitive ? text : text.toLowerCase();
49
44
  }
50
-
51
45
  function splitList(value) {
52
- return value
53
- .split(',')
54
- .map((part) => part.trim().toLowerCase().replace(/^\./, ''))
55
- .filter(Boolean);
46
+ return value
47
+ .split(',')
48
+ .map((part) => part.trim().toLowerCase().replace(/^\./, ''))
49
+ .filter(Boolean);
56
50
  }
57
-
58
-
59
51
  export function parseQuery(raw, options = {}) {
60
- const caseSensitive = !!options.caseSensitive;
61
- const text = String(raw ?? '');
62
- const parsed = {
63
- raw: text,
64
- clauses: [], // { kind, raw, start, end } — what the input was made of
65
- terms: [], // bare words — fuzzy against paths, substring in content
66
- phrases: [], // "quoted" — verbatim substrings
67
- negatives: [], // -foo — must not appear in the path
68
- exts: [], // ext:js,ts — extensions without the dot
69
- paths: [], // path:src/api — path substrings
70
- kinds: [], // kind:function — symbol kinds
71
- isTest: false, // is:test
72
- isSource: false, // is:source
73
- regex: null, // the pattern as authored
74
- regexSource: '',
75
- regexFlags: '',
76
- regexGlobal: null, // a 'g' copy used for scanning, never for matching
77
- caseSensitive,
78
- error: null,
79
- };
80
-
81
- if (!text.trim()) return parsed;
82
-
83
- const lower = (s) => fold(s, caseSensitive);
84
-
85
- for (const m of text.matchAll(TOKEN_RE)) {
86
- // The span each clause came from, so the palette can turn a filter into a
87
- // chip and take it back out of the input when the chip is dismissed.
88
- const note = (kind) => parsed.clauses.push({
89
- kind, raw: m[0], start: m.index, end: m.index + m[0].length,
90
- });
91
-
92
- if (m[1] !== undefined) {
93
- const phrase = m[1].trim();
94
- if (phrase) { parsed.phrases.push(lower(phrase)); note('phrase'); }
95
- continue;
52
+ const caseSensitive = !!options.caseSensitive;
53
+ const text = String(raw ?? '');
54
+ const parsed = {
55
+ raw: text,
56
+ clauses: [], // { kind, raw, start, end } — what the input was made of
57
+ terms: [], // bare words — fuzzy against paths, substring in content
58
+ phrases: [], // "quoted" — verbatim substrings
59
+ negatives: [], // -foo — must not appear in the path
60
+ exts: [], // ext:js,ts — extensions without the dot
61
+ paths: [], // path:src/api — path substrings
62
+ kinds: [], // kind:function — symbol kinds
63
+ isTest: false, // is:test
64
+ isSource: false, // is:source
65
+ regex: null, // the pattern as authored
66
+ regexSource: '',
67
+ regexFlags: '',
68
+ regexGlobal: null, // a 'g' copy used for scanning, never for matching
69
+ caseSensitive,
70
+ error: null,
71
+ };
72
+ if (!text.trim())
73
+ return parsed;
74
+ const lower = (s) => fold(s, caseSensitive);
75
+ for (const m of text.matchAll(TOKEN_RE)) {
76
+ // The span each clause came from, so the palette can turn a filter into a
77
+ // chip and take it back out of the input when the chip is dismissed.
78
+ const note = (kind) => parsed.clauses.push({
79
+ kind, raw: m[0], start: m.index, end: m.index + m[0].length,
80
+ });
81
+ if (m[1] !== undefined) {
82
+ const phrase = m[1].trim();
83
+ if (phrase) {
84
+ parsed.phrases.push(lower(phrase));
85
+ note('phrase');
86
+ }
87
+ continue;
88
+ }
89
+ if (m[2] !== undefined) {
90
+ const source = m[2];
91
+ parsed.regexSource = source;
92
+ // Flags the person typed are respected exactly; with no flags at all the
93
+ // case toggle decides, which is what makes `/Foo/` and the `Aa` button
94
+ // behave the way a reader expects.
95
+ const flags = m[3] || (caseSensitive ? '' : 'i');
96
+ parsed.regexFlags = flags;
97
+ if (source.length > MAX_REGEX_LENGTH) {
98
+ parsed.error = `Regex is too long (${source.length} > ${MAX_REGEX_LENGTH}).`;
99
+ continue;
100
+ }
101
+ try {
102
+ parsed.regex = new RegExp(source, flags.replace('g', ''));
103
+ parsed.regexGlobal = new RegExp(source, flags.includes('g') ? flags : flags + 'g');
104
+ note('regex');
105
+ }
106
+ catch (err) {
107
+ parsed.error = 'Bad regex: ' + err.message;
108
+ }
109
+ continue;
110
+ }
111
+ const token = m[0];
112
+ if (!token)
113
+ continue;
114
+ if (token.length > 1 && token.startsWith('-')) {
115
+ parsed.negatives.push(lower(token.slice(1)));
116
+ note('neg');
117
+ continue;
118
+ }
119
+ const colon = token.indexOf(':');
120
+ if (colon > 0) {
121
+ const field = token.slice(0, colon).toLowerCase();
122
+ const value = token.slice(colon + 1);
123
+ if (!value)
124
+ continue;
125
+ if (field === 'ext' || field === 'exts' || field === 'type') {
126
+ parsed.exts.push(...splitList(value));
127
+ note('ext');
128
+ continue;
129
+ }
130
+ if (field === 'path' || field === 'in') {
131
+ parsed.paths.push(lower(value));
132
+ note('path');
133
+ continue;
134
+ }
135
+ if (field === 'kind') {
136
+ parsed.kinds.push(value.toLowerCase());
137
+ note('kind');
138
+ continue;
139
+ }
140
+ if (field === 'is') {
141
+ const v = value.toLowerCase();
142
+ if (v === 'test' || v === 'tests') {
143
+ parsed.isTest = true;
144
+ note('is');
145
+ }
146
+ else if (v === 'source' || v === 'src') {
147
+ parsed.isSource = true;
148
+ note('is');
149
+ }
150
+ else {
151
+ parsed.terms.push(lower(token));
152
+ note('term');
153
+ }
154
+ continue;
155
+ }
156
+ // An unrecognized `foo:bar` is more likely a real word (a URL, a
157
+ // protocol, `Read:`) than a typo'd clause. Search for it as text.
158
+ }
159
+ parsed.terms.push(lower(token));
160
+ note('term');
96
161
  }
97
-
98
- if (m[2] !== undefined) {
99
- const source = m[2];
100
- parsed.regexSource = source;
101
- // Flags the person typed are respected exactly; with no flags at all the
102
- // case toggle decides, which is what makes `/Foo/` and the `Aa` button
103
- // behave the way a reader expects.
104
- const flags = m[3] || (caseSensitive ? '' : 'i');
105
- parsed.regexFlags = flags;
106
- if (source.length > MAX_REGEX_LENGTH) {
107
- parsed.error = `Regex is too long (${source.length} > ${MAX_REGEX_LENGTH}).`;
108
- continue;
109
- }
110
- try {
111
- parsed.regex = new RegExp(source, flags.replace('g', ''));
112
- parsed.regexGlobal = new RegExp(source, flags.includes('g') ? flags : flags + 'g');
113
- note('regex');
114
- } catch (err) {
115
- parsed.error = 'Bad regex: ' + err.message;
116
- }
117
- continue;
118
- }
119
-
120
- const token = m[0];
121
- if (!token) continue;
122
-
123
- if (token.length > 1 && token.startsWith('-')) {
124
- parsed.negatives.push(lower(token.slice(1)));
125
- note('neg');
126
- continue;
127
- }
128
-
129
- const colon = token.indexOf(':');
130
- if (colon > 0) {
131
- const field = token.slice(0, colon).toLowerCase();
132
- const value = token.slice(colon + 1);
133
- if (!value) continue;
134
- if (field === 'ext' || field === 'exts' || field === 'type') {
135
- parsed.exts.push(...splitList(value));
136
- note('ext');
137
- continue;
138
- }
139
- if (field === 'path' || field === 'in') {
140
- parsed.paths.push(lower(value));
141
- note('path');
142
- continue;
143
- }
144
- if (field === 'kind') {
145
- parsed.kinds.push(value.toLowerCase());
146
- note('kind');
147
- continue;
148
- }
149
- if (field === 'is') {
150
- const v = value.toLowerCase();
151
- if (v === 'test' || v === 'tests') { parsed.isTest = true; note('is'); }
152
- else if (v === 'source' || v === 'src') { parsed.isSource = true; note('is'); }
153
- else { parsed.terms.push(lower(token)); note('term'); }
154
- continue;
155
- }
156
- // An unrecognized `foo:bar` is more likely a real word (a URL, a
157
- // protocol, `Read:`) than a typo'd clause. Search for it as text.
158
- }
159
-
160
- parsed.terms.push(lower(token));
161
- note('term');
162
- }
163
-
164
- return parsed;
162
+ return parsed;
165
163
  }
166
-
167
164
  // Take one clause back out of the raw query, leaving the rest of the text
168
165
  // exactly as it was typed. The palette uses this when a filter chip is
169
166
  // dismissed — hand-editing a query that contains a quoted phrase is otherwise
170
167
  // a counting exercise.
171
168
  export function removeClause(raw, clause) {
172
- const text = String(raw ?? '');
173
- if (!clause) return text;
174
- const start = Math.max(0, Math.min(Number(clause.start) || 0, text.length));
175
- const end = Math.max(start, Math.min(Number(clause.end) || start, text.length));
176
- const head = text.slice(0, start).replace(/\s+$/, '');
177
- const tail = text.slice(end).replace(/^\s+/, '');
178
- if (head && tail) return `${head} ${tail}`;
179
- return head || tail;
169
+ const text = String(raw ?? '');
170
+ if (!clause)
171
+ return text;
172
+ const start = Math.max(0, Math.min(Number(clause.start) || 0, text.length));
173
+ const end = Math.max(start, Math.min(Number(clause.end) || start, text.length));
174
+ const head = text.slice(0, start).replace(/\s+$/, '');
175
+ const tail = text.slice(end).replace(/^\s+/, '');
176
+ if (head && tail)
177
+ return `${head} ${tail}`;
178
+ return head || tail;
180
179
  }
181
-
182
180
  // Is there anything to search *for*? A query of pure filters still filters —
183
181
  // see `hasFilters` — but it has no text to rank with, and that difference is
184
182
  // what tells the palette to stop asking the server for content matches.
185
183
  export function queryIsEmpty(parsed) {
186
- return !parsed || (
187
- !parsed.terms.length && !parsed.phrases.length && !parsed.regex
188
- && !parsed.negatives.length && !parsed.exts.length && !parsed.paths.length
189
- && !parsed.kinds.length && !parsed.isTest && !parsed.isSource
190
- );
184
+ return !parsed || (!parsed.terms.length && !parsed.phrases.length && !parsed.regex
185
+ && !parsed.negatives.length && !parsed.exts.length && !parsed.paths.length
186
+ && !parsed.kinds.length && !parsed.isTest && !parsed.isSource);
191
187
  }
192
-
193
188
  export function hasFilters(parsed) {
194
- return !!(parsed && (
195
- parsed.negatives.length || parsed.exts.length || parsed.paths.length
196
- || parsed.kinds.length || parsed.isTest || parsed.isSource
197
- ));
189
+ return !!(parsed && (parsed.negatives.length || parsed.exts.length || parsed.paths.length
190
+ || parsed.kinds.length || parsed.isTest || parsed.isSource));
198
191
  }
199
-
200
192
  // Advanced means "the strict clauses are in play": filters, a phrase, a regex,
201
193
  // or the case toggle. A query of bare words alone keeps the forgiving ranked
202
194
  // behaviour the palette always had — partial matches included — which is what a
203
195
  // half-remembered name deserves. Anything else is a decision, and decisions are
204
196
  // enforced rather than ranked.
205
197
  export function isAdvanced(parsed) {
206
- if (!parsed) return false;
207
- return hasFilters(parsed)
208
- || parsed.phrases.length > 0
209
- || parsed.regex !== null
210
- || parsed.caseSensitive;
198
+ if (!parsed)
199
+ return false;
200
+ return hasFilters(parsed)
201
+ || parsed.phrases.length > 0
202
+ || parsed.regex !== null
203
+ || parsed.caseSensitive;
211
204
  }
212
-
213
205
  // ---- the gate -------------------------------------------------------------
214
-
215
206
  // Everything that can be decided from the path alone. Cheap, so it runs first
216
207
  // and lets the expensive content pass skip the file entirely.
217
208
  export function matchesPathFilters(parsed, path) {
218
- if (!parsed) return true;
219
-
220
- if (parsed.exts.length) {
221
- // `extOf` hands back the dot (`'.js'`); the filter is stored without it,
222
- // because `ext:js` is what people type.
223
- const want = extOf(path).replace(/^\./, '');
224
- if (!parsed.exts.includes(want)) return false;
225
- }
226
-
227
- if (parsed.paths.length) {
228
- const folded = fold(path, parsed.caseSensitive);
229
- for (const needle of parsed.paths) {
230
- if (!folded.includes(needle)) return false;
209
+ if (!parsed)
210
+ return true;
211
+ if (parsed.exts.length) {
212
+ // `extOf` hands back the dot (`'.js'`); the filter is stored without it,
213
+ // because `ext:js` is what people type.
214
+ const want = extOf(path).replace(/^\./, '');
215
+ if (!parsed.exts.includes(want))
216
+ return false;
231
217
  }
232
- }
233
-
234
- if (parsed.isTest && !isTestPath(path)) return false;
235
- if (parsed.isSource && isTestPath(path)) return false;
236
-
237
- if (parsed.negatives.length) {
238
- const folded = fold(path, parsed.caseSensitive);
239
- for (const needle of parsed.negatives) {
240
- if (folded.includes(needle)) return false;
218
+ if (parsed.paths.length) {
219
+ const folded = fold(path, parsed.caseSensitive);
220
+ for (const needle of parsed.paths) {
221
+ if (!folded.includes(needle))
222
+ return false;
223
+ }
224
+ }
225
+ if (parsed.isTest && !isTestPath(path))
226
+ return false;
227
+ if (parsed.isSource && isTestPath(path))
228
+ return false;
229
+ if (parsed.negatives.length) {
230
+ const folded = fold(path, parsed.caseSensitive);
231
+ for (const needle of parsed.negatives) {
232
+ if (folded.includes(needle))
233
+ return false;
234
+ }
235
+ }
236
+ if (parsed.kinds.length) {
237
+ // A kind filter is a statement about symbols, not paths: the caller has to
238
+ // know the symbol to answer it. Answer "yes" here and let the symbol pass
239
+ // apply it, so a kind filter never silently hides every file.
240
+ return true;
241
241
  }
242
- }
243
-
244
- if (parsed.kinds.length) {
245
- // A kind filter is a statement about symbols, not paths: the caller has to
246
- // know the symbol to answer it. Answer "yes" here and let the symbol pass
247
- // apply it, so a kind filter never silently hides every file.
248
242
  return true;
249
- }
250
-
251
- return true;
252
243
  }
253
-
254
244
  // Decimals matter only for ordering, and this keeps the ordering stable: exact
255
245
  // matches win, then a prefix, then a word boundary, then anywhere.
256
246
  function occurrenceScore(hay, needle, weight) {
257
- const at = hay.indexOf(needle);
258
- if (at === -1) return 0;
259
- let score = weight - at;
260
- if (at === 0) score += weight * 0.6;
261
- else if (/[^a-z0-9]/.test(hay[at - 1])) score += weight * 0.35;
262
- if (hay === needle) score += weight * 1.2;
263
- return score;
247
+ const at = hay.indexOf(needle);
248
+ if (at === -1)
249
+ return 0;
250
+ let score = weight - at;
251
+ if (at === 0)
252
+ score += weight * 0.6;
253
+ else if (/[^a-z0-9]/.test(hay[at - 1]))
254
+ score += weight * 0.35;
255
+ if (hay === needle)
256
+ score += weight * 1.2;
257
+ return score;
264
258
  }
265
-
266
259
  // ---- the ranking ----------------------------------------------------------
267
-
268
260
  // Subsequence match, the fzf idea: `rt` finds `router.js` because the letters
269
261
  // appear in order. Adjacent runs, word boundaries and camel humps are worth
270
262
  // more than letters sprinkled through a long path, which is what stops `rt`
@@ -273,121 +265,133 @@ function occurrenceScore(hay, needle, weight) {
273
265
  // `raw` is kept alongside the folded haystack so the camel hump can be seen —
274
266
  // folding throws away the case that carries the signal.
275
267
  function fuzzyScore(needle, hay, raw) {
276
- let score = 0;
277
- let at = 0;
278
- let streak = 0;
279
- let first = -1;
280
-
281
- for (let i = 0; i < needle.length; i++) {
282
- const found = hay.indexOf(needle[i], at);
283
- if (found === -1) return 0;
284
- if (first === -1) first = found;
285
-
286
- streak = found === at && i > 0 ? streak + 1 : 0;
287
- score += 10 + streak * 6;
288
-
289
- if (found === 0) score += 14;
290
- else if (/[^a-z0-9]/.test(hay[found - 1])) score += 12;
291
- else if (raw && /[a-z0-9]/.test(raw[found - 1] || '') && /[A-Z]/.test(raw[found] || '')) score += 10;
292
-
293
- at = found + 1;
294
- }
295
-
296
- score -= first; // earlier is better
297
- score -= Math.max(0, hay.length - needle.length) * 0.4; // shorter is better
298
- return Math.max(1, score);
268
+ let score = 0;
269
+ let at = 0;
270
+ let streak = 0;
271
+ let first = -1;
272
+ for (let i = 0; i < needle.length; i++) {
273
+ const found = hay.indexOf(needle[i], at);
274
+ if (found === -1)
275
+ return 0;
276
+ if (first === -1)
277
+ first = found;
278
+ streak = found === at && i > 0 ? streak + 1 : 0;
279
+ score += 10 + streak * 6;
280
+ if (found === 0)
281
+ score += 14;
282
+ else if (/[^a-z0-9]/.test(hay[found - 1]))
283
+ score += 12;
284
+ else if (raw && /[a-z0-9]/.test(raw[found - 1] || '') && /[A-Z]/.test(raw[found] || ''))
285
+ score += 10;
286
+ at = found + 1;
287
+ }
288
+ score -= first; // earlier is better
289
+ score -= Math.max(0, hay.length - needle.length) * 0.4; // shorter is better
290
+ return Math.max(1, score);
299
291
  }
300
-
301
292
  // How well a path answers the free-text part of the query. Filters are not
302
293
  // consulted here — `matchesPathFilters` owns those.
303
294
  export function scorePath(parsed, path) {
304
- if (!parsed || queryIsEmpty(parsed)) return 1;
305
- const hay = fold(path, parsed.caseSensitive);
306
- const raw = path;
307
- const base = baseName(path);
308
- const baseHay = fold(base, parsed.caseSensitive);
309
- let score = 0;
310
-
311
- for (const phrase of parsed.phrases) {
312
- if (!hay.includes(phrase)) return 0;
313
- score += occurrenceScore(hay, phrase, 90);
314
- }
315
-
316
- if (parsed.regex) {
317
- parsed.regex.lastIndex = 0;
318
- if (!parsed.regex.test(path)) return 0;
319
- score += 80;
320
- }
321
-
322
- for (const term of parsed.terms) {
323
- const exact = baseHay === term ? 320 : 0;
324
- if (exact) { score += exact; continue; }
325
- const inBase = occurrenceScore(baseHay, term, 150);
326
- if (inBase) { score += inBase; continue; }
327
- const inPath = occurrenceScore(hay, term, 70);
328
- if (inPath) { score += inPath; continue; }
329
- const fuzzy = fuzzyScore(term, baseHay, base) || fuzzyScore(term, hay, raw);
330
- if (!fuzzy) return 0;
331
- score += fuzzy;
332
- }
333
-
334
- // A path with no holder for a bare term is not a match at all. (Filter-only
335
- // queries have no terms and are already satisfied by the gate.)
336
- if (!score && parsed.terms.length) return 0;
337
-
338
- // Nothing to rank by: a query of pure filters is a set, not an ordering, so
339
- // it answers with a flat 1 and skips the tie-breaking below.
340
- if (!parsed.terms.length) return score || 1;
341
-
342
- // Shallower files win ties. When the same name appears at three depths — a
343
- // page, a feature folder and a barrel — the one nearest the top of the tree
344
- // is usually the one meant. The clamp matters: a match must stay strictly
345
- // positive, because zero is how the callers spell "no match at all".
346
- const adjusted = score - path.split('/').length * 0.5;
347
- return adjusted > 0 ? adjusted : 0.5;
295
+ if (!parsed || queryIsEmpty(parsed))
296
+ return 1;
297
+ const hay = fold(path, parsed.caseSensitive);
298
+ const raw = path;
299
+ const base = baseName(path);
300
+ const baseHay = fold(base, parsed.caseSensitive);
301
+ let score = 0;
302
+ for (const phrase of parsed.phrases) {
303
+ if (!hay.includes(phrase))
304
+ return 0;
305
+ score += occurrenceScore(hay, phrase, 90);
306
+ }
307
+ if (parsed.regex) {
308
+ parsed.regex.lastIndex = 0;
309
+ if (!parsed.regex.test(path))
310
+ return 0;
311
+ score += 80;
312
+ }
313
+ for (const term of parsed.terms) {
314
+ const exact = baseHay === term ? 320 : 0;
315
+ if (exact) {
316
+ score += exact;
317
+ continue;
318
+ }
319
+ const inBase = occurrenceScore(baseHay, term, 150);
320
+ if (inBase) {
321
+ score += inBase;
322
+ continue;
323
+ }
324
+ const inPath = occurrenceScore(hay, term, 70);
325
+ if (inPath) {
326
+ score += inPath;
327
+ continue;
328
+ }
329
+ const fuzzy = fuzzyScore(term, baseHay, base) || fuzzyScore(term, hay, raw);
330
+ if (!fuzzy)
331
+ return 0;
332
+ score += fuzzy;
333
+ }
334
+ // A path with no holder for a bare term is not a match at all. (Filter-only
335
+ // queries have no terms and are already satisfied by the gate.)
336
+ if (!score && parsed.terms.length)
337
+ return 0;
338
+ // Nothing to rank by: a query of pure filters is a set, not an ordering, so
339
+ // it answers with a flat 1 and skips the tie-breaking below.
340
+ if (!parsed.terms.length)
341
+ return score || 1;
342
+ // Shallower files win ties. When the same name appears at three depths — a
343
+ // page, a feature folder and a barrel — the one nearest the top of the tree
344
+ // is usually the one meant. The clamp matters: a match must stay strictly
345
+ // positive, because zero is how the callers spell "no match at all".
346
+ const adjusted = score - path.split('/').length * 0.5;
347
+ return adjusted > 0 ? adjusted : 0.5;
348
348
  }
349
-
350
349
  // A symbol is a name plus the kind it was declared with. `kind:` and the bare
351
350
  // terms both apply here, and nothing about extensions or paths does.
352
351
  export function scoreSymbol(parsed, name, kind) {
353
- if (!parsed) return 0;
354
- const foldedName = fold(name || '', parsed.caseSensitive);
355
- const foldedKind = (kind || '').toLowerCase();
356
-
357
- if (parsed.kinds.length) {
358
- const kindHit = parsed.kinds.some((k) => foldedKind.includes(k) || foldedName.endsWith(k));
359
- if (!kindHit) return 0;
360
- }
361
- if (parsed.regex) {
362
- parsed.regex.lastIndex = 0;
363
- if (!parsed.regex.test(name || '')) return 0;
364
- }
365
- for (const negative of parsed.negatives) {
366
- if (foldedName.includes(negative)) return 0;
367
- }
368
- for (const phrase of parsed.phrases) {
369
- if (!foldedName.includes(phrase)) return 0;
370
- }
371
- if (!parsed.terms.length) return parsed.regex || parsed.phrases.length || parsed.kinds.length ? 60 : 0;
372
-
373
- let score = 0;
374
- for (const term of parsed.terms) {
375
- if (foldedName === term) score += 240;
376
- else {
377
- const hit = occurrenceScore(foldedName, term, 130);
378
- if (hit) score += hit;
379
- else {
380
- const fuzzy = fuzzyScore(term, foldedName, name);
381
- if (!fuzzy) return 0;
382
- score += fuzzy;
383
- }
352
+ if (!parsed)
353
+ return 0;
354
+ const foldedName = fold(name || '', parsed.caseSensitive);
355
+ const foldedKind = (kind || '').toLowerCase();
356
+ if (parsed.kinds.length) {
357
+ const kindHit = parsed.kinds.some((k) => foldedKind.includes(k) || foldedName.endsWith(k));
358
+ if (!kindHit)
359
+ return 0;
360
+ }
361
+ if (parsed.regex) {
362
+ parsed.regex.lastIndex = 0;
363
+ if (!parsed.regex.test(name || ''))
364
+ return 0;
384
365
  }
385
- }
386
- return score;
366
+ for (const negative of parsed.negatives) {
367
+ if (foldedName.includes(negative))
368
+ return 0;
369
+ }
370
+ for (const phrase of parsed.phrases) {
371
+ if (!foldedName.includes(phrase))
372
+ return 0;
373
+ }
374
+ if (!parsed.terms.length)
375
+ return parsed.regex || parsed.phrases.length || parsed.kinds.length ? 60 : 0;
376
+ let score = 0;
377
+ for (const term of parsed.terms) {
378
+ if (foldedName === term)
379
+ score += 240;
380
+ else {
381
+ const hit = occurrenceScore(foldedName, term, 130);
382
+ if (hit)
383
+ score += hit;
384
+ else {
385
+ const fuzzy = fuzzyScore(term, foldedName, name);
386
+ if (!fuzzy)
387
+ return 0;
388
+ score += fuzzy;
389
+ }
390
+ }
391
+ }
392
+ return score;
387
393
  }
388
-
389
394
  // ---- content --------------------------------------------------------------
390
-
391
395
  // How well a file's text answers the query, plus the offset of the best hit so
392
396
  // the caller can turn it into a line number and a snippet without searching
393
397
  // again. Returns `{ score: 0, index: -1 }` when the file does not answer it.
@@ -398,121 +402,124 @@ export function scoreSymbol(parsed, name, kind) {
398
402
  // paths (see `matchesPathFilters`), and reading it as "this file must not
399
403
  // mention the word vendor" would hide exactly the code you were looking for.
400
404
  export function scoreContent(parsed, text) {
401
- if (!parsed || !text || queryIsEmpty(parsed)) return { score: 0, index: -1 };
402
- const hay = fold(text, parsed.caseSensitive);
403
- let score = 0;
404
- let best = -1;
405
-
406
- const note = (at) => {
407
- if (at !== -1 && (best === -1 || at < best)) best = at;
408
- };
409
-
410
- for (const phrase of parsed.phrases) {
411
- const at = hay.indexOf(phrase);
412
- if (at === -1) return { score: 0, index: -1 };
413
- score += occurrenceScore(hay, phrase, 120);
414
- note(at);
415
- }
416
-
417
- if (parsed.regex) {
418
- parsed.regex.lastIndex = 0;
419
- const at = hay.search(parsed.regex);
420
- if (at === -1) return { score: 0, index: -1 };
421
- score += 100;
422
- note(at);
423
- }
424
-
425
- for (const term of parsed.terms) {
426
- const at = hay.indexOf(term);
427
- if (at === -1) return { score: 0, index: -1 };
428
- score += occurrenceScore(hay, term, 60);
429
- note(at);
430
- }
431
-
432
- return { score, index: best };
405
+ if (!parsed || !text || queryIsEmpty(parsed))
406
+ return { score: 0, index: -1 };
407
+ const hay = fold(text, parsed.caseSensitive);
408
+ let score = 0;
409
+ let best = -1;
410
+ const note = (at) => {
411
+ if (at !== -1 && (best === -1 || at < best))
412
+ best = at;
413
+ };
414
+ for (const phrase of parsed.phrases) {
415
+ const at = hay.indexOf(phrase);
416
+ if (at === -1)
417
+ return { score: 0, index: -1 };
418
+ score += occurrenceScore(hay, phrase, 120);
419
+ note(at);
420
+ }
421
+ if (parsed.regex) {
422
+ parsed.regex.lastIndex = 0;
423
+ const at = hay.search(parsed.regex);
424
+ if (at === -1)
425
+ return { score: 0, index: -1 };
426
+ score += 100;
427
+ note(at);
428
+ }
429
+ for (const term of parsed.terms) {
430
+ const at = hay.indexOf(term);
431
+ if (at === -1)
432
+ return { score: 0, index: -1 };
433
+ score += occurrenceScore(hay, term, 60);
434
+ note(at);
435
+ }
436
+ return { score, index: best };
433
437
  }
434
-
435
438
  // ---- highlighting ---------------------------------------------------------
436
-
437
439
  function mergeRanges(ranges) {
438
- if (!ranges.length) return [];
439
- const sorted = ranges.slice().sort((a, b) => a[0] - b[0] || a[1] - b[1]);
440
- const out = [sorted[0]];
441
- for (let i = 1; i < sorted.length; i++) {
442
- const last = out[out.length - 1];
443
- if (sorted[i][0] <= last[1]) last[1] = Math.max(last[1], sorted[i][1]);
444
- else out.push(sorted[i]);
445
- }
446
- return out;
440
+ if (!ranges.length)
441
+ return [];
442
+ const sorted = ranges.slice().sort((a, b) => a[0] - b[0] || a[1] - b[1]);
443
+ const out = [sorted[0]];
444
+ for (let i = 1; i < sorted.length; i++) {
445
+ const last = out[out.length - 1];
446
+ if (sorted[i][0] <= last[1])
447
+ last[1] = Math.max(last[1], sorted[i][1]);
448
+ else
449
+ out.push(sorted[i]);
450
+ }
451
+ return out;
447
452
  }
448
-
449
453
  // Every span of `text` the query matches, as `[start, end)` offsets, merged so
450
454
  // overlapping hits paint once. This is what lets a snippet mark *all* the words
451
455
  // instead of only the first — the old highlighter stopped at one, which made a
452
456
  // multi-word query look like it had only matched half of itself.
453
457
  export function highlightRanges(text, parsed) {
454
- if (!text || !parsed) return [];
455
- const ranges = [];
456
- const add = (start, length) => {
457
- if (length > 0 && start >= 0 && ranges.length < MAX_RANGES) ranges.push([start, start + length]);
458
- };
459
-
460
- if (parsed.regexGlobal) {
461
- parsed.regexGlobal.lastIndex = 0;
462
- let m;
463
- let guard = 0;
464
- while ((m = parsed.regexGlobal.exec(text)) !== null && guard++ < MAX_RANGES) {
465
- add(m.index, m[0].length);
466
- // A pattern that can match the empty string would spin forever here.
467
- if (m[0].length === 0) parsed.regexGlobal.lastIndex++;
458
+ if (!text || !parsed)
459
+ return [];
460
+ const ranges = [];
461
+ const add = (start, length) => {
462
+ if (length > 0 && start >= 0 && ranges.length < MAX_RANGES)
463
+ ranges.push([start, start + length]);
464
+ };
465
+ if (parsed.regexGlobal) {
466
+ parsed.regexGlobal.lastIndex = 0;
467
+ let m;
468
+ let guard = 0;
469
+ while ((m = parsed.regexGlobal.exec(text)) !== null && guard++ < MAX_RANGES) {
470
+ add(m.index, m[0].length);
471
+ // A pattern that can match the empty string would spin forever here.
472
+ if (m[0].length === 0)
473
+ parsed.regexGlobal.lastIndex++;
474
+ }
468
475
  }
469
- }
470
-
471
- const needles = parsed.phrases.concat(parsed.terms);
472
- if (needles.length) {
473
- const hay = fold(text, parsed.caseSensitive);
474
- for (const needle of needles) {
475
- if (!needle) continue;
476
- let from = 0;
477
- let at;
478
- while ((at = hay.indexOf(needle, from)) !== -1) {
479
- add(at, needle.length);
480
- from = at + needle.length;
481
- if (ranges.length >= MAX_RANGES) break;
482
- }
476
+ const needles = parsed.phrases.concat(parsed.terms);
477
+ if (needles.length) {
478
+ const hay = fold(text, parsed.caseSensitive);
479
+ for (const needle of needles) {
480
+ if (!needle)
481
+ continue;
482
+ let from = 0;
483
+ let at;
484
+ while ((at = hay.indexOf(needle, from)) !== -1) {
485
+ add(at, needle.length);
486
+ from = at + needle.length;
487
+ if (ranges.length >= MAX_RANGES)
488
+ break;
489
+ }
490
+ }
483
491
  }
484
- }
485
-
486
- return mergeRanges(ranges);
492
+ return mergeRanges(ranges);
487
493
  }
488
-
489
494
  // ---- turning an offset into a place to stand ------------------------------
490
-
491
495
  // 1-based line number for an offset. Used for the "Line 42" label on a result
492
496
  // and, more importantly, to put the cursor there when the result is opened.
493
497
  export function lineOfIndex(text, index) {
494
- if (!text || index <= 0) return 1;
495
- let line = 1;
496
- for (let i = 0; i < index && i < text.length; i++) {
497
- if (text.charCodeAt(i) === 10) line++;
498
- }
499
- return line;
498
+ if (!text || index <= 0)
499
+ return 1;
500
+ let line = 1;
501
+ for (let i = 0; i < index && i < text.length; i++) {
502
+ if (text.charCodeAt(i) === 10)
503
+ line++;
504
+ }
505
+ return line;
500
506
  }
501
-
502
507
  // The trimmed text of the line containing `index`, shortened around the match
503
508
  // so the interesting part is not the part that gets cut off.
504
509
  export function snippetAt(text, index, maxLength = 120) {
505
- if (!text) return '';
506
- const start = index < 0 ? 0 : index;
507
- let lineStart = text.lastIndexOf('\n', start - 1) + 1;
508
- let lineEnd = text.indexOf('\n', start);
509
- if (lineEnd === -1) lineEnd = text.length;
510
- let line = text.slice(lineStart, lineEnd).replace(/\r$/, '');
511
-
512
- if (line.length > maxLength) {
513
- const column = Math.max(0, start - lineStart);
514
- const from = Math.max(0, column - Math.floor(maxLength / 3));
515
- line = (from > 0 ? '…' : '') + line.slice(from, from + maxLength - 2);
516
- }
517
- return line.trim();
518
- }
510
+ if (!text)
511
+ return '';
512
+ const start = index < 0 ? 0 : index;
513
+ let lineStart = text.lastIndexOf('\n', start - 1) + 1;
514
+ let lineEnd = text.indexOf('\n', start);
515
+ if (lineEnd === -1)
516
+ lineEnd = text.length;
517
+ let line = text.slice(lineStart, lineEnd).replace(/\r$/, '');
518
+ if (line.length > maxLength) {
519
+ const column = Math.max(0, start - lineStart);
520
+ const from = Math.max(0, column - Math.floor(maxLength / 3));
521
+ line = (from > 0 ? '…' : '') + line.slice(from, from + maxLength - 2);
522
+ }
523
+ return line.trim();
524
+ }
525
+ //# sourceMappingURL=query.js.map