@code-rag/core 0.1.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 (347) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +19 -0
  3. package/dist/auth/audit-log.d.ts +35 -0
  4. package/dist/auth/audit-log.js +110 -0
  5. package/dist/auth/audit-log.js.map +1 -0
  6. package/dist/auth/audit-log.test.d.ts +1 -0
  7. package/dist/auth/audit-log.test.js +261 -0
  8. package/dist/auth/audit-log.test.js.map +1 -0
  9. package/dist/auth/index.d.ts +6 -0
  10. package/dist/auth/index.js +5 -0
  11. package/dist/auth/index.js.map +1 -0
  12. package/dist/auth/oidc-provider.d.ts +49 -0
  13. package/dist/auth/oidc-provider.js +358 -0
  14. package/dist/auth/oidc-provider.js.map +1 -0
  15. package/dist/auth/oidc-provider.test.d.ts +1 -0
  16. package/dist/auth/oidc-provider.test.js +520 -0
  17. package/dist/auth/oidc-provider.test.js.map +1 -0
  18. package/dist/auth/rbac.d.ts +29 -0
  19. package/dist/auth/rbac.js +75 -0
  20. package/dist/auth/rbac.js.map +1 -0
  21. package/dist/auth/rbac.test.d.ts +1 -0
  22. package/dist/auth/rbac.test.js +224 -0
  23. package/dist/auth/rbac.test.js.map +1 -0
  24. package/dist/auth/saml-provider.d.ts +51 -0
  25. package/dist/auth/saml-provider.js +355 -0
  26. package/dist/auth/saml-provider.js.map +1 -0
  27. package/dist/auth/saml-provider.test.d.ts +1 -0
  28. package/dist/auth/saml-provider.test.js +422 -0
  29. package/dist/auth/saml-provider.test.js.map +1 -0
  30. package/dist/auth/types.d.ts +81 -0
  31. package/dist/auth/types.js +11 -0
  32. package/dist/auth/types.js.map +1 -0
  33. package/dist/auth/types.test.d.ts +1 -0
  34. package/dist/auth/types.test.js +147 -0
  35. package/dist/auth/types.test.js.map +1 -0
  36. package/dist/backlog/ab-reference-scanner.d.ts +10 -0
  37. package/dist/backlog/ab-reference-scanner.js +22 -0
  38. package/dist/backlog/ab-reference-scanner.js.map +1 -0
  39. package/dist/backlog/ab-reference-scanner.test.d.ts +1 -0
  40. package/dist/backlog/ab-reference-scanner.test.js +83 -0
  41. package/dist/backlog/ab-reference-scanner.test.js.map +1 -0
  42. package/dist/backlog/azure-devops-provider.d.ts +59 -0
  43. package/dist/backlog/azure-devops-provider.js +283 -0
  44. package/dist/backlog/azure-devops-provider.js.map +1 -0
  45. package/dist/backlog/backlog-provider.d.ts +13 -0
  46. package/dist/backlog/backlog-provider.js +6 -0
  47. package/dist/backlog/backlog-provider.js.map +1 -0
  48. package/dist/backlog/backlog-provider.test.d.ts +1 -0
  49. package/dist/backlog/backlog-provider.test.js +426 -0
  50. package/dist/backlog/backlog-provider.test.js.map +1 -0
  51. package/dist/backlog/clickup-provider.d.ts +55 -0
  52. package/dist/backlog/clickup-provider.js +301 -0
  53. package/dist/backlog/clickup-provider.js.map +1 -0
  54. package/dist/backlog/clickup-provider.test.d.ts +1 -0
  55. package/dist/backlog/clickup-provider.test.js +426 -0
  56. package/dist/backlog/clickup-provider.test.js.map +1 -0
  57. package/dist/backlog/clickup-reference-scanner.d.ts +10 -0
  58. package/dist/backlog/clickup-reference-scanner.js +32 -0
  59. package/dist/backlog/clickup-reference-scanner.js.map +1 -0
  60. package/dist/backlog/clickup-reference-scanner.test.d.ts +1 -0
  61. package/dist/backlog/clickup-reference-scanner.test.js +92 -0
  62. package/dist/backlog/clickup-reference-scanner.test.js.map +1 -0
  63. package/dist/backlog/code-linker.d.ts +63 -0
  64. package/dist/backlog/code-linker.js +90 -0
  65. package/dist/backlog/code-linker.js.map +1 -0
  66. package/dist/backlog/code-linker.test.d.ts +1 -0
  67. package/dist/backlog/code-linker.test.js +325 -0
  68. package/dist/backlog/code-linker.test.js.map +1 -0
  69. package/dist/backlog/index.d.ts +14 -0
  70. package/dist/backlog/index.js +8 -0
  71. package/dist/backlog/index.js.map +1 -0
  72. package/dist/backlog/jira-provider.d.ts +60 -0
  73. package/dist/backlog/jira-provider.js +272 -0
  74. package/dist/backlog/jira-provider.js.map +1 -0
  75. package/dist/backlog/jira-provider.test.d.ts +1 -0
  76. package/dist/backlog/jira-provider.test.js +449 -0
  77. package/dist/backlog/jira-provider.test.js.map +1 -0
  78. package/dist/backlog/jira-reference-scanner.d.ts +11 -0
  79. package/dist/backlog/jira-reference-scanner.js +26 -0
  80. package/dist/backlog/jira-reference-scanner.js.map +1 -0
  81. package/dist/backlog/jira-reference-scanner.test.d.ts +1 -0
  82. package/dist/backlog/jira-reference-scanner.test.js +127 -0
  83. package/dist/backlog/jira-reference-scanner.test.js.map +1 -0
  84. package/dist/backlog/types.d.ts +22 -0
  85. package/dist/backlog/types.js +1 -0
  86. package/dist/backlog/types.js.map +1 -0
  87. package/dist/chunker/ast-chunker.d.ts +45 -0
  88. package/dist/chunker/ast-chunker.js +292 -0
  89. package/dist/chunker/ast-chunker.js.map +1 -0
  90. package/dist/chunker/ast-chunker.test.d.ts +1 -0
  91. package/dist/chunker/ast-chunker.test.js +391 -0
  92. package/dist/chunker/ast-chunker.test.js.map +1 -0
  93. package/dist/chunker/chunker.d.ts +8 -0
  94. package/dist/chunker/chunker.js +1 -0
  95. package/dist/chunker/chunker.js.map +1 -0
  96. package/dist/chunker/index.d.ts +3 -0
  97. package/dist/chunker/index.js +2 -0
  98. package/dist/chunker/index.js.map +1 -0
  99. package/dist/config/config-parser.d.ts +15 -0
  100. package/dist/config/config-parser.js +283 -0
  101. package/dist/config/config-parser.js.map +1 -0
  102. package/dist/config/config-parser.test.d.ts +1 -0
  103. package/dist/config/config-parser.test.js +699 -0
  104. package/dist/config/config-parser.test.js.map +1 -0
  105. package/dist/docs/confluence-provider.d.ts +121 -0
  106. package/dist/docs/confluence-provider.js +459 -0
  107. package/dist/docs/confluence-provider.js.map +1 -0
  108. package/dist/docs/confluence-provider.test.d.ts +1 -0
  109. package/dist/docs/confluence-provider.test.js +765 -0
  110. package/dist/docs/confluence-provider.test.js.map +1 -0
  111. package/dist/docs/index.d.ts +4 -0
  112. package/dist/docs/index.js +2 -0
  113. package/dist/docs/index.js.map +1 -0
  114. package/dist/docs/sharepoint-provider.d.ts +150 -0
  115. package/dist/docs/sharepoint-provider.js +637 -0
  116. package/dist/docs/sharepoint-provider.js.map +1 -0
  117. package/dist/docs/sharepoint-provider.test.d.ts +1 -0
  118. package/dist/docs/sharepoint-provider.test.js +873 -0
  119. package/dist/docs/sharepoint-provider.test.js.map +1 -0
  120. package/dist/embedding/bm25-index.d.ts +12 -0
  121. package/dist/embedding/bm25-index.js +89 -0
  122. package/dist/embedding/bm25-index.js.map +1 -0
  123. package/dist/embedding/bm25-index.test.d.ts +1 -0
  124. package/dist/embedding/bm25-index.test.js +289 -0
  125. package/dist/embedding/bm25-index.test.js.map +1 -0
  126. package/dist/embedding/hybrid-search.d.ts +13 -0
  127. package/dist/embedding/hybrid-search.js +124 -0
  128. package/dist/embedding/hybrid-search.js.map +1 -0
  129. package/dist/embedding/hybrid-search.test.d.ts +1 -0
  130. package/dist/embedding/hybrid-search.test.js +266 -0
  131. package/dist/embedding/hybrid-search.test.js.map +1 -0
  132. package/dist/embedding/index.d.ts +11 -0
  133. package/dist/embedding/index.js +7 -0
  134. package/dist/embedding/index.js.map +1 -0
  135. package/dist/embedding/lancedb-store.d.ts +21 -0
  136. package/dist/embedding/lancedb-store.js +172 -0
  137. package/dist/embedding/lancedb-store.js.map +1 -0
  138. package/dist/embedding/lancedb-store.test.d.ts +1 -0
  139. package/dist/embedding/lancedb-store.test.js +268 -0
  140. package/dist/embedding/lancedb-store.test.js.map +1 -0
  141. package/dist/embedding/model-lifecycle-manager.d.ts +83 -0
  142. package/dist/embedding/model-lifecycle-manager.js +419 -0
  143. package/dist/embedding/model-lifecycle-manager.js.map +1 -0
  144. package/dist/embedding/model-lifecycle-manager.test.d.ts +1 -0
  145. package/dist/embedding/model-lifecycle-manager.test.js +642 -0
  146. package/dist/embedding/model-lifecycle-manager.test.js.map +1 -0
  147. package/dist/embedding/ollama-embedding-provider.d.ts +16 -0
  148. package/dist/embedding/ollama-embedding-provider.js +74 -0
  149. package/dist/embedding/ollama-embedding-provider.js.map +1 -0
  150. package/dist/embedding/ollama-embedding-provider.test.d.ts +1 -0
  151. package/dist/embedding/ollama-embedding-provider.test.js +198 -0
  152. package/dist/embedding/ollama-embedding-provider.test.js.map +1 -0
  153. package/dist/embedding/openai-compatible-embedding-provider.d.ts +19 -0
  154. package/dist/embedding/openai-compatible-embedding-provider.js +108 -0
  155. package/dist/embedding/openai-compatible-embedding-provider.js.map +1 -0
  156. package/dist/embedding/openai-compatible-embedding-provider.test.d.ts +1 -0
  157. package/dist/embedding/openai-compatible-embedding-provider.test.js +456 -0
  158. package/dist/embedding/openai-compatible-embedding-provider.test.js.map +1 -0
  159. package/dist/embedding/qdrant-store.d.ts +28 -0
  160. package/dist/embedding/qdrant-store.js +174 -0
  161. package/dist/embedding/qdrant-store.js.map +1 -0
  162. package/dist/embedding/qdrant-store.test.d.ts +1 -0
  163. package/dist/embedding/qdrant-store.test.js +359 -0
  164. package/dist/embedding/qdrant-store.test.js.map +1 -0
  165. package/dist/enrichment/index.d.ts +4 -0
  166. package/dist/enrichment/index.js +2 -0
  167. package/dist/enrichment/index.js.map +1 -0
  168. package/dist/enrichment/nl-enricher.d.ts +16 -0
  169. package/dist/enrichment/nl-enricher.js +47 -0
  170. package/dist/enrichment/nl-enricher.js.map +1 -0
  171. package/dist/enrichment/nl-enricher.test.d.ts +1 -0
  172. package/dist/enrichment/nl-enricher.test.js +154 -0
  173. package/dist/enrichment/nl-enricher.test.js.map +1 -0
  174. package/dist/enrichment/ollama-client.d.ts +18 -0
  175. package/dist/enrichment/ollama-client.js +55 -0
  176. package/dist/enrichment/ollama-client.js.map +1 -0
  177. package/dist/enrichment/ollama-client.test.d.ts +1 -0
  178. package/dist/enrichment/ollama-client.test.js +129 -0
  179. package/dist/enrichment/ollama-client.test.js.map +1 -0
  180. package/dist/git/git-client.d.ts +22 -0
  181. package/dist/git/git-client.js +6 -0
  182. package/dist/git/git-client.js.map +1 -0
  183. package/dist/git/git-client.test.d.ts +1 -0
  184. package/dist/git/git-client.test.js +200 -0
  185. package/dist/git/git-client.test.js.map +1 -0
  186. package/dist/git/ignore-filter.d.ts +2 -0
  187. package/dist/git/ignore-filter.js +31 -0
  188. package/dist/git/ignore-filter.js.map +1 -0
  189. package/dist/git/ignore-filter.test.d.ts +1 -0
  190. package/dist/git/ignore-filter.test.js +87 -0
  191. package/dist/git/ignore-filter.test.js.map +1 -0
  192. package/dist/git/index.d.ts +4 -0
  193. package/dist/git/index.js +3 -0
  194. package/dist/git/index.js.map +1 -0
  195. package/dist/git/simple-git-client.d.ts +12 -0
  196. package/dist/git/simple-git-client.js +138 -0
  197. package/dist/git/simple-git-client.js.map +1 -0
  198. package/dist/graph/cross-repo-resolver.d.ts +50 -0
  199. package/dist/graph/cross-repo-resolver.js +315 -0
  200. package/dist/graph/cross-repo-resolver.js.map +1 -0
  201. package/dist/graph/cross-repo-resolver.test.d.ts +1 -0
  202. package/dist/graph/cross-repo-resolver.test.js +548 -0
  203. package/dist/graph/cross-repo-resolver.test.js.map +1 -0
  204. package/dist/graph/dependency-graph.d.ts +44 -0
  205. package/dist/graph/dependency-graph.js +108 -0
  206. package/dist/graph/dependency-graph.js.map +1 -0
  207. package/dist/graph/dependency-graph.test.d.ts +1 -0
  208. package/dist/graph/dependency-graph.test.js +276 -0
  209. package/dist/graph/dependency-graph.test.js.map +1 -0
  210. package/dist/graph/graph-builder.d.ts +11 -0
  211. package/dist/graph/graph-builder.js +113 -0
  212. package/dist/graph/graph-builder.js.map +1 -0
  213. package/dist/graph/graph-builder.test.d.ts +1 -0
  214. package/dist/graph/graph-builder.test.js +178 -0
  215. package/dist/graph/graph-builder.test.js.map +1 -0
  216. package/dist/graph/import-resolver.d.ts +11 -0
  217. package/dist/graph/import-resolver.js +199 -0
  218. package/dist/graph/import-resolver.js.map +1 -0
  219. package/dist/graph/import-resolver.test.d.ts +1 -0
  220. package/dist/graph/import-resolver.test.js +282 -0
  221. package/dist/graph/import-resolver.test.js.map +1 -0
  222. package/dist/graph/index.d.ts +7 -0
  223. package/dist/graph/index.js +4 -0
  224. package/dist/graph/index.js.map +1 -0
  225. package/dist/index.d.ts +31 -0
  226. package/dist/index.js +15 -0
  227. package/dist/index.js.map +1 -0
  228. package/dist/indexer/file-scanner.d.ts +34 -0
  229. package/dist/indexer/file-scanner.js +69 -0
  230. package/dist/indexer/file-scanner.js.map +1 -0
  231. package/dist/indexer/file-scanner.test.d.ts +1 -0
  232. package/dist/indexer/file-scanner.test.js +110 -0
  233. package/dist/indexer/file-scanner.test.js.map +1 -0
  234. package/dist/indexer/file-watcher.d.ts +79 -0
  235. package/dist/indexer/file-watcher.js +148 -0
  236. package/dist/indexer/incremental-indexer.d.ts +67 -0
  237. package/dist/indexer/incremental-indexer.js +142 -0
  238. package/dist/indexer/incremental-indexer.js.map +1 -0
  239. package/dist/indexer/incremental-indexer.test.d.ts +1 -0
  240. package/dist/indexer/incremental-indexer.test.js +266 -0
  241. package/dist/indexer/incremental-indexer.test.js.map +1 -0
  242. package/dist/indexer/index-check.d.ts +22 -0
  243. package/dist/indexer/index-check.js +74 -0
  244. package/dist/indexer/index-check.js.map +1 -0
  245. package/dist/indexer/index-check.test.d.ts +1 -0
  246. package/dist/indexer/index-check.test.js +100 -0
  247. package/dist/indexer/index-check.test.js.map +1 -0
  248. package/dist/indexer/index-state.d.ts +61 -0
  249. package/dist/indexer/index-state.js +82 -0
  250. package/dist/indexer/index-state.js.map +1 -0
  251. package/dist/indexer/index-state.test.d.ts +1 -0
  252. package/dist/indexer/index-state.test.js +140 -0
  253. package/dist/indexer/index-state.test.js.map +1 -0
  254. package/dist/indexer/index.d.ts +12 -0
  255. package/dist/indexer/index.js +6 -0
  256. package/dist/indexer/index.js.map +1 -0
  257. package/dist/indexer/multi-repo-indexer.d.ts +63 -0
  258. package/dist/indexer/multi-repo-indexer.js +144 -0
  259. package/dist/indexer/multi-repo-indexer.js.map +1 -0
  260. package/dist/indexer/multi-repo-indexer.test.d.ts +1 -0
  261. package/dist/indexer/multi-repo-indexer.test.js +238 -0
  262. package/dist/indexer/multi-repo-indexer.test.js.map +1 -0
  263. package/dist/parser/index.d.ts +4 -0
  264. package/dist/parser/index.js +3 -0
  265. package/dist/parser/index.js.map +1 -0
  266. package/dist/parser/language-registry.d.ts +46 -0
  267. package/dist/parser/language-registry.js +219 -0
  268. package/dist/parser/language-registry.js.map +1 -0
  269. package/dist/parser/language-registry.test.d.ts +1 -0
  270. package/dist/parser/language-registry.test.js +225 -0
  271. package/dist/parser/language-registry.test.js.map +1 -0
  272. package/dist/parser/markdown-parser.d.ts +124 -0
  273. package/dist/parser/markdown-parser.js +487 -0
  274. package/dist/parser/markdown-parser.js.map +1 -0
  275. package/dist/parser/markdown-parser.test.d.ts +1 -0
  276. package/dist/parser/markdown-parser.test.js +600 -0
  277. package/dist/parser/markdown-parser.test.js.map +1 -0
  278. package/dist/parser/tree-sitter-parser.d.ts +32 -0
  279. package/dist/parser/tree-sitter-parser.js +146 -0
  280. package/dist/parser/tree-sitter-parser.js.map +1 -0
  281. package/dist/retrieval/context-expander.d.ts +51 -0
  282. package/dist/retrieval/context-expander.js +218 -0
  283. package/dist/retrieval/context-expander.js.map +1 -0
  284. package/dist/retrieval/context-expander.test.d.ts +1 -0
  285. package/dist/retrieval/context-expander.test.js +339 -0
  286. package/dist/retrieval/context-expander.test.js.map +1 -0
  287. package/dist/retrieval/cross-encoder-reranker.d.ts +16 -0
  288. package/dist/retrieval/cross-encoder-reranker.js +90 -0
  289. package/dist/retrieval/cross-encoder-reranker.js.map +1 -0
  290. package/dist/retrieval/cross-encoder-reranker.test.d.ts +1 -0
  291. package/dist/retrieval/cross-encoder-reranker.test.js +305 -0
  292. package/dist/retrieval/cross-encoder-reranker.test.js.map +1 -0
  293. package/dist/retrieval/index.d.ts +8 -0
  294. package/dist/retrieval/index.js +4 -0
  295. package/dist/retrieval/index.js.map +1 -0
  296. package/dist/retrieval/query-analyzer.d.ts +29 -0
  297. package/dist/retrieval/query-analyzer.js +238 -0
  298. package/dist/retrieval/query-analyzer.js.map +1 -0
  299. package/dist/retrieval/query-analyzer.test.d.ts +1 -0
  300. package/dist/retrieval/query-analyzer.test.js +236 -0
  301. package/dist/retrieval/query-analyzer.test.js.map +1 -0
  302. package/dist/retrieval/token-budget.d.ts +51 -0
  303. package/dist/retrieval/token-budget.js +141 -0
  304. package/dist/retrieval/token-budget.js.map +1 -0
  305. package/dist/retrieval/token-budget.test.d.ts +1 -0
  306. package/dist/retrieval/token-budget.test.js +404 -0
  307. package/dist/retrieval/token-budget.test.js.map +1 -0
  308. package/dist/storage/azure-blob-provider.d.ts +19 -0
  309. package/dist/storage/azure-blob-provider.js +199 -0
  310. package/dist/storage/azure-blob-provider.js.map +1 -0
  311. package/dist/storage/azure-blob-provider.test.d.ts +1 -0
  312. package/dist/storage/azure-blob-provider.test.js +250 -0
  313. package/dist/storage/azure-blob-provider.test.js.map +1 -0
  314. package/dist/storage/gcs-provider.d.ts +22 -0
  315. package/dist/storage/gcs-provider.js +241 -0
  316. package/dist/storage/gcs-provider.js.map +1 -0
  317. package/dist/storage/gcs-provider.test.d.ts +1 -0
  318. package/dist/storage/gcs-provider.test.js +299 -0
  319. package/dist/storage/gcs-provider.test.js.map +1 -0
  320. package/dist/storage/index.d.ts +5 -0
  321. package/dist/storage/index.js +4 -0
  322. package/dist/storage/index.js.map +1 -0
  323. package/dist/storage/s3-provider.d.ts +21 -0
  324. package/dist/storage/s3-provider.js +220 -0
  325. package/dist/storage/s3-provider.js.map +1 -0
  326. package/dist/storage/s3-provider.test.d.ts +1 -0
  327. package/dist/storage/s3-provider.test.js +329 -0
  328. package/dist/storage/s3-provider.test.js.map +1 -0
  329. package/dist/storage/types.d.ts +65 -0
  330. package/dist/storage/types.js +12 -0
  331. package/dist/storage/types.js.map +1 -0
  332. package/dist/types/chunk.d.ts +32 -0
  333. package/dist/types/chunk.js +1 -0
  334. package/dist/types/chunk.js.map +1 -0
  335. package/dist/types/config.d.ts +71 -0
  336. package/dist/types/config.js +1 -0
  337. package/dist/types/config.js.map +1 -0
  338. package/dist/types/index.d.ts +5 -0
  339. package/dist/types/index.js +1 -0
  340. package/dist/types/index.js.map +1 -0
  341. package/dist/types/provider.d.ts +54 -0
  342. package/dist/types/provider.js +36 -0
  343. package/dist/types/provider.js.map +1 -0
  344. package/dist/types/search.d.ts +27 -0
  345. package/dist/types/search.js +1 -0
  346. package/dist/types/search.js.map +1 -0
  347. package/package.json +70 -0
@@ -0,0 +1,449 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import { JiraProvider } from './jira-provider.js';
3
+ import { BacklogError } from './backlog-provider.js';
4
+ // ---------------------------------------------------------------------------
5
+ // Helpers
6
+ // ---------------------------------------------------------------------------
7
+ function createMockResponse(body, status = 200, statusText = 'OK') {
8
+ return {
9
+ ok: status >= 200 && status < 300,
10
+ status,
11
+ statusText,
12
+ json: () => Promise.resolve(body),
13
+ headers: new Headers(),
14
+ redirected: false,
15
+ type: 'basic',
16
+ url: '',
17
+ clone: () => createMockResponse(body, status, statusText),
18
+ body: null,
19
+ bodyUsed: false,
20
+ arrayBuffer: () => Promise.resolve(new ArrayBuffer(0)),
21
+ blob: () => Promise.resolve(new Blob()),
22
+ formData: () => Promise.resolve(new FormData()),
23
+ text: () => Promise.resolve(JSON.stringify(body)),
24
+ bytes: () => Promise.resolve(new Uint8Array()),
25
+ };
26
+ }
27
+ function createJiraIssue(overrides) {
28
+ return {
29
+ id: '10001',
30
+ key: 'PROJ-123',
31
+ self: 'https://mycompany.atlassian.net/rest/api/3/issue/10001',
32
+ fields: {
33
+ summary: 'Fix login bug',
34
+ description: 'Users cannot log in when using SSO',
35
+ issuetype: { name: 'Bug' },
36
+ status: { name: 'In Progress' },
37
+ assignee: {
38
+ displayName: 'Jane Developer',
39
+ emailAddress: 'jane@example.com',
40
+ },
41
+ labels: ['auth', 'sso'],
42
+ issuelinks: [
43
+ {
44
+ type: {
45
+ name: 'Relates',
46
+ inward: 'is related to',
47
+ outward: 'relates to',
48
+ },
49
+ outwardIssue: {
50
+ key: 'PROJ-100',
51
+ fields: { summary: 'Auth refactor' },
52
+ },
53
+ },
54
+ ],
55
+ ...(overrides ?? {}),
56
+ },
57
+ };
58
+ }
59
+ const VALID_CONFIG = {
60
+ host: 'https://mycompany.atlassian.net',
61
+ email: 'user@example.com',
62
+ apiToken: 'test-token-123',
63
+ project: 'PROJ',
64
+ };
65
+ // ---------------------------------------------------------------------------
66
+ // Tests
67
+ // ---------------------------------------------------------------------------
68
+ describe('JiraProvider', () => {
69
+ let provider;
70
+ let fetchSpy;
71
+ beforeEach(() => {
72
+ provider = new JiraProvider();
73
+ fetchSpy = vi.fn();
74
+ vi.stubGlobal('fetch', fetchSpy);
75
+ });
76
+ afterEach(() => {
77
+ vi.restoreAllMocks();
78
+ });
79
+ // --- name ---
80
+ it('should have name set to jira', () => {
81
+ expect(provider.name).toBe('jira');
82
+ });
83
+ // --- initialize ---
84
+ describe('initialize', () => {
85
+ it('should return ok on successful connection', async () => {
86
+ fetchSpy.mockResolvedValueOnce(createMockResponse({ accountId: '12345', displayName: 'Test User' }));
87
+ const result = await provider.initialize(VALID_CONFIG);
88
+ expect(result.isOk()).toBe(true);
89
+ expect(fetchSpy).toHaveBeenCalledOnce();
90
+ expect(fetchSpy.mock.calls[0][0]).toContain('/rest/api/3/myself');
91
+ });
92
+ it('should return err when host is missing', async () => {
93
+ const result = await provider.initialize({
94
+ email: 'user@example.com',
95
+ apiToken: 'token',
96
+ });
97
+ expect(result.isErr()).toBe(true);
98
+ if (result.isErr()) {
99
+ expect(result.error).toBeInstanceOf(BacklogError);
100
+ expect(result.error.message).toContain('host');
101
+ }
102
+ });
103
+ it('should return err when email is missing', async () => {
104
+ const result = await provider.initialize({
105
+ host: 'https://mycompany.atlassian.net',
106
+ apiToken: 'token',
107
+ });
108
+ expect(result.isErr()).toBe(true);
109
+ if (result.isErr()) {
110
+ expect(result.error.message).toContain('email');
111
+ }
112
+ });
113
+ it('should return err when apiToken is missing', async () => {
114
+ const result = await provider.initialize({
115
+ host: 'https://mycompany.atlassian.net',
116
+ email: 'user@example.com',
117
+ });
118
+ expect(result.isErr()).toBe(true);
119
+ if (result.isErr()) {
120
+ expect(result.error.message).toContain('apiToken');
121
+ }
122
+ });
123
+ it('should return err when connection fails with HTTP error', async () => {
124
+ fetchSpy.mockResolvedValueOnce(createMockResponse({ message: 'Unauthorized' }, 401, 'Unauthorized'));
125
+ const result = await provider.initialize(VALID_CONFIG);
126
+ expect(result.isErr()).toBe(true);
127
+ if (result.isErr()) {
128
+ expect(result.error.message).toContain('401');
129
+ }
130
+ });
131
+ it('should return err when connection throws a network error', async () => {
132
+ fetchSpy.mockRejectedValueOnce(new Error('ECONNREFUSED'));
133
+ const result = await provider.initialize(VALID_CONFIG);
134
+ expect(result.isErr()).toBe(true);
135
+ if (result.isErr()) {
136
+ expect(result.error.message).toContain('ECONNREFUSED');
137
+ }
138
+ });
139
+ it('should send correct authorization header', async () => {
140
+ fetchSpy.mockResolvedValueOnce(createMockResponse({ accountId: '12345' }));
141
+ await provider.initialize(VALID_CONFIG);
142
+ const callHeaders = fetchSpy.mock.calls[0][1]?.headers;
143
+ const expectedAuth = `Basic ${btoa(`${VALID_CONFIG.email}:${VALID_CONFIG.apiToken}`)}`;
144
+ expect(callHeaders['Authorization']).toBe(expectedAuth);
145
+ });
146
+ it('should normalize host without protocol by prepending https', async () => {
147
+ fetchSpy.mockResolvedValueOnce(createMockResponse({ accountId: '12345' }));
148
+ await provider.initialize({
149
+ ...VALID_CONFIG,
150
+ host: 'mycompany.atlassian.net',
151
+ });
152
+ expect(fetchSpy.mock.calls[0][0]).toContain('https://mycompany.atlassian.net/rest/api/3/myself');
153
+ });
154
+ it('should strip trailing slashes from host', async () => {
155
+ fetchSpy.mockResolvedValueOnce(createMockResponse({ accountId: '12345' }));
156
+ await provider.initialize({
157
+ ...VALID_CONFIG,
158
+ host: 'https://mycompany.atlassian.net/',
159
+ });
160
+ expect(fetchSpy.mock.calls[0][0]).toBe('https://mycompany.atlassian.net/rest/api/3/myself');
161
+ });
162
+ });
163
+ // --- getItems ---
164
+ describe('getItems', () => {
165
+ beforeEach(async () => {
166
+ fetchSpy.mockResolvedValueOnce(createMockResponse({ accountId: '12345' }));
167
+ await provider.initialize(VALID_CONFIG);
168
+ });
169
+ it('should build JQL from query types', async () => {
170
+ fetchSpy.mockResolvedValueOnce(createMockResponse({ issues: [], total: 0 }));
171
+ await provider.getItems({ types: ['bug', 'story'] });
172
+ const url = fetchSpy.mock.calls[1][0];
173
+ expect(url).toContain('issuetype');
174
+ expect(url).toContain('Bug');
175
+ expect(url).toContain('Story');
176
+ });
177
+ it('should build JQL from query states', async () => {
178
+ fetchSpy.mockResolvedValueOnce(createMockResponse({ issues: [], total: 0 }));
179
+ await provider.getItems({ states: ['In Progress', 'Done'] });
180
+ const url = fetchSpy.mock.calls[1][0];
181
+ expect(url).toContain('status');
182
+ expect(url).toContain('In+Progress');
183
+ });
184
+ it('should build JQL from query assignedTo', async () => {
185
+ fetchSpy.mockResolvedValueOnce(createMockResponse({ issues: [], total: 0 }));
186
+ await provider.getItems({ assignedTo: 'jane@example.com' });
187
+ const url = fetchSpy.mock.calls[1][0];
188
+ expect(url).toContain('assignee');
189
+ });
190
+ it('should build JQL from query tags', async () => {
191
+ fetchSpy.mockResolvedValueOnce(createMockResponse({ issues: [], total: 0 }));
192
+ await provider.getItems({ tags: ['auth'] });
193
+ const url = fetchSpy.mock.calls[1][0];
194
+ expect(url).toContain('labels');
195
+ expect(url).toContain('auth');
196
+ });
197
+ it('should build JQL from query text', async () => {
198
+ fetchSpy.mockResolvedValueOnce(createMockResponse({ issues: [], total: 0 }));
199
+ await provider.getItems({ text: 'login' });
200
+ const url = fetchSpy.mock.calls[1][0];
201
+ expect(url).toContain('summary');
202
+ expect(url).toContain('description');
203
+ expect(url).toContain('login');
204
+ });
205
+ it('should scope JQL to project when configured', async () => {
206
+ fetchSpy.mockResolvedValueOnce(createMockResponse({ issues: [], total: 0 }));
207
+ await provider.getItems({});
208
+ const url = fetchSpy.mock.calls[1][0];
209
+ expect(url).toContain('project');
210
+ expect(url).toContain('PROJ');
211
+ });
212
+ it('should map response issues to BacklogItems', async () => {
213
+ fetchSpy.mockResolvedValueOnce(createMockResponse({
214
+ issues: [createJiraIssue()],
215
+ total: 1,
216
+ }));
217
+ const result = await provider.getItems({});
218
+ expect(result.isOk()).toBe(true);
219
+ if (result.isOk()) {
220
+ expect(result.value).toHaveLength(1);
221
+ const item = result.value[0];
222
+ expect(item.id).toBe('10001');
223
+ expect(item.externalId).toBe('PROJ-123');
224
+ expect(item.title).toBe('Fix login bug');
225
+ expect(item.description).toBe('Users cannot log in when using SSO');
226
+ expect(item.type).toBe('bug');
227
+ expect(item.state).toBe('In Progress');
228
+ expect(item.assignedTo).toBe('Jane Developer');
229
+ expect(item.tags).toEqual(['auth', 'sso']);
230
+ expect(item.url).toContain('/browse/PROJ-123');
231
+ }
232
+ });
233
+ it('should respect the limit parameter', async () => {
234
+ fetchSpy.mockResolvedValueOnce(createMockResponse({ issues: [], total: 0 }));
235
+ await provider.getItems({ limit: 5 });
236
+ const url = fetchSpy.mock.calls[1][0];
237
+ expect(url).toContain('maxResults=5');
238
+ });
239
+ it('should return err on API failure', async () => {
240
+ fetchSpy.mockResolvedValueOnce(createMockResponse({ message: 'Bad Request' }, 400, 'Bad Request'));
241
+ const result = await provider.getItems({});
242
+ expect(result.isErr()).toBe(true);
243
+ if (result.isErr()) {
244
+ expect(result.error).toBeInstanceOf(BacklogError);
245
+ expect(result.error.message).toContain('400');
246
+ }
247
+ });
248
+ it('should return err on network failure', async () => {
249
+ fetchSpy.mockRejectedValueOnce(new Error('Network error'));
250
+ const result = await provider.getItems({});
251
+ expect(result.isErr()).toBe(true);
252
+ if (result.isErr()) {
253
+ expect(result.error.message).toContain('Network error');
254
+ }
255
+ });
256
+ it('should return empty array when no issues match', async () => {
257
+ fetchSpy.mockResolvedValueOnce(createMockResponse({ issues: [], total: 0 }));
258
+ const result = await provider.getItems({ text: 'nonexistent' });
259
+ expect(result.isOk()).toBe(true);
260
+ if (result.isOk()) {
261
+ expect(result.value).toEqual([]);
262
+ }
263
+ });
264
+ });
265
+ // --- getItem ---
266
+ describe('getItem', () => {
267
+ beforeEach(async () => {
268
+ fetchSpy.mockResolvedValueOnce(createMockResponse({ accountId: '12345' }));
269
+ await provider.initialize(VALID_CONFIG);
270
+ });
271
+ it('should fetch and map a single issue', async () => {
272
+ fetchSpy.mockResolvedValueOnce(createMockResponse(createJiraIssue()));
273
+ const result = await provider.getItem('PROJ-123');
274
+ expect(result.isOk()).toBe(true);
275
+ if (result.isOk()) {
276
+ expect(result.value.externalId).toBe('PROJ-123');
277
+ expect(result.value.title).toBe('Fix login bug');
278
+ expect(result.value.type).toBe('bug');
279
+ }
280
+ });
281
+ it('should return err when issue is not found (404)', async () => {
282
+ fetchSpy.mockResolvedValueOnce(createMockResponse({ errorMessages: ['Issue does not exist'] }, 404, 'Not Found'));
283
+ const result = await provider.getItem('PROJ-999');
284
+ expect(result.isErr()).toBe(true);
285
+ if (result.isErr()) {
286
+ expect(result.error).toBeInstanceOf(BacklogError);
287
+ expect(result.error.message).toContain('not found');
288
+ expect(result.error.message).toContain('PROJ-999');
289
+ }
290
+ });
291
+ it('should return err on non-404 HTTP error', async () => {
292
+ fetchSpy.mockResolvedValueOnce(createMockResponse({ message: 'Forbidden' }, 403, 'Forbidden'));
293
+ const result = await provider.getItem('PROJ-123');
294
+ expect(result.isErr()).toBe(true);
295
+ if (result.isErr()) {
296
+ expect(result.error.message).toContain('403');
297
+ }
298
+ });
299
+ it('should return err on network error', async () => {
300
+ fetchSpy.mockRejectedValueOnce(new Error('Connection reset'));
301
+ const result = await provider.getItem('PROJ-123');
302
+ expect(result.isErr()).toBe(true);
303
+ if (result.isErr()) {
304
+ expect(result.error.message).toContain('Connection reset');
305
+ }
306
+ });
307
+ it('should handle issue with null assignee', async () => {
308
+ fetchSpy.mockResolvedValueOnce(createMockResponse(createJiraIssue({ assignee: null })));
309
+ const result = await provider.getItem('PROJ-123');
310
+ expect(result.isOk()).toBe(true);
311
+ if (result.isOk()) {
312
+ expect(result.value.assignedTo).toBeUndefined();
313
+ }
314
+ });
315
+ it('should handle issue with null description', async () => {
316
+ fetchSpy.mockResolvedValueOnce(createMockResponse(createJiraIssue({ description: null })));
317
+ const result = await provider.getItem('PROJ-123');
318
+ expect(result.isOk()).toBe(true);
319
+ if (result.isOk()) {
320
+ expect(result.value.description).toBe('');
321
+ }
322
+ });
323
+ it('should map unknown issue type to task', async () => {
324
+ fetchSpy.mockResolvedValueOnce(createMockResponse(createJiraIssue({ issuetype: { name: 'Custom Type' } })));
325
+ const result = await provider.getItem('PROJ-123');
326
+ expect(result.isOk()).toBe(true);
327
+ if (result.isOk()) {
328
+ expect(result.value.type).toBe('task');
329
+ }
330
+ });
331
+ });
332
+ // --- searchItems ---
333
+ describe('searchItems', () => {
334
+ beforeEach(async () => {
335
+ fetchSpy.mockResolvedValueOnce(createMockResponse({ accountId: '12345' }));
336
+ await provider.initialize(VALID_CONFIG);
337
+ });
338
+ it('should search with JQL text query', async () => {
339
+ fetchSpy.mockResolvedValueOnce(createMockResponse({
340
+ issues: [createJiraIssue()],
341
+ total: 1,
342
+ }));
343
+ const result = await provider.searchItems('login');
344
+ expect(result.isOk()).toBe(true);
345
+ const url = fetchSpy.mock.calls[1][0];
346
+ expect(url).toContain('summary');
347
+ expect(url).toContain('description');
348
+ expect(url).toContain('login');
349
+ });
350
+ it('should respect the limit parameter', async () => {
351
+ fetchSpy.mockResolvedValueOnce(createMockResponse({ issues: [], total: 0 }));
352
+ await provider.searchItems('test', 3);
353
+ const url = fetchSpy.mock.calls[1][0];
354
+ expect(url).toContain('maxResults=3');
355
+ });
356
+ it('should scope search to project', async () => {
357
+ fetchSpy.mockResolvedValueOnce(createMockResponse({ issues: [], total: 0 }));
358
+ await provider.searchItems('test');
359
+ const url = fetchSpy.mock.calls[1][0];
360
+ expect(url).toContain('project');
361
+ expect(url).toContain('PROJ');
362
+ });
363
+ it('should return err on API failure', async () => {
364
+ fetchSpy.mockResolvedValueOnce(createMockResponse({}, 500, 'Internal Server Error'));
365
+ const result = await provider.searchItems('test');
366
+ expect(result.isErr()).toBe(true);
367
+ if (result.isErr()) {
368
+ expect(result.error.message).toContain('500');
369
+ }
370
+ });
371
+ });
372
+ // --- getLinkedCode ---
373
+ describe('getLinkedCode', () => {
374
+ beforeEach(async () => {
375
+ fetchSpy.mockResolvedValueOnce(createMockResponse({ accountId: '12345' }));
376
+ await provider.initialize(VALID_CONFIG);
377
+ });
378
+ it('should extract linked issue keys as code references', async () => {
379
+ fetchSpy.mockResolvedValueOnce(createMockResponse(createJiraIssue()));
380
+ const result = await provider.getLinkedCode('PROJ-123');
381
+ expect(result.isOk()).toBe(true);
382
+ if (result.isOk()) {
383
+ expect(result.value).toContain('PROJ-100');
384
+ }
385
+ });
386
+ it('should return empty array when no links exist', async () => {
387
+ fetchSpy.mockResolvedValueOnce(createMockResponse(createJiraIssue({ issuelinks: [] })));
388
+ const result = await provider.getLinkedCode('PROJ-123');
389
+ expect(result.isOk()).toBe(true);
390
+ if (result.isOk()) {
391
+ expect(result.value).toEqual([]);
392
+ }
393
+ });
394
+ it('should return err when issue is not found', async () => {
395
+ fetchSpy.mockResolvedValueOnce(createMockResponse({}, 404, 'Not Found'));
396
+ const result = await provider.getLinkedCode('PROJ-999');
397
+ expect(result.isErr()).toBe(true);
398
+ if (result.isErr()) {
399
+ expect(result.error.message).toContain('not found');
400
+ }
401
+ });
402
+ it('should return err on network error', async () => {
403
+ fetchSpy.mockRejectedValueOnce(new Error('Timeout'));
404
+ const result = await provider.getLinkedCode('PROJ-123');
405
+ expect(result.isErr()).toBe(true);
406
+ if (result.isErr()) {
407
+ expect(result.error.message).toContain('Timeout');
408
+ }
409
+ });
410
+ it('should handle inward issue links', async () => {
411
+ fetchSpy.mockResolvedValueOnce(createMockResponse(createJiraIssue({
412
+ issuelinks: [
413
+ {
414
+ type: {
415
+ name: 'Blocks',
416
+ inward: 'is blocked by',
417
+ outward: 'blocks',
418
+ },
419
+ inwardIssue: {
420
+ key: 'PROJ-200',
421
+ fields: { summary: 'Blocking issue' },
422
+ },
423
+ },
424
+ ],
425
+ })));
426
+ const result = await provider.getLinkedCode('PROJ-123');
427
+ expect(result.isOk()).toBe(true);
428
+ if (result.isOk()) {
429
+ expect(result.value).toContain('PROJ-200');
430
+ }
431
+ });
432
+ });
433
+ // --- Error when not initialized ---
434
+ describe('when not initialized', () => {
435
+ it('should throw BacklogError from getItems', async () => {
436
+ await expect(provider.getItems({})).rejects.toThrow(BacklogError);
437
+ });
438
+ it('should throw BacklogError from getItem', async () => {
439
+ await expect(provider.getItem('PROJ-1')).rejects.toThrow(BacklogError);
440
+ });
441
+ it('should throw BacklogError from searchItems', async () => {
442
+ await expect(provider.searchItems('test')).rejects.toThrow(BacklogError);
443
+ });
444
+ it('should throw BacklogError from getLinkedCode', async () => {
445
+ await expect(provider.getLinkedCode('PROJ-1')).rejects.toThrow(BacklogError);
446
+ });
447
+ });
448
+ });
449
+ //# sourceMappingURL=jira-provider.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jira-provider.test.js","sourceRoot":"","sources":["../../src/backlog/jira-provider.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Scans source code content for Jira issue key references (e.g., PROJECT-123).
3
+ *
4
+ * Extracts all `UPPER-digits` patterns found in the given content string
5
+ * and returns an array of the full issue keys as strings.
6
+ *
7
+ * @param content - The source code or text content to scan
8
+ * @param projectKey - Optional project key to restrict matches (e.g., "PROJ")
9
+ * @returns An array of Jira issue key strings (e.g., ["PROJ-123", "CORE-456"])
10
+ */
11
+ export declare function scanForJiraReferences(content: string, projectKey?: string): string[];
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Scans source code content for Jira issue key references (e.g., PROJECT-123).
3
+ *
4
+ * Extracts all `UPPER-digits` patterns found in the given content string
5
+ * and returns an array of the full issue keys as strings.
6
+ *
7
+ * @param content - The source code or text content to scan
8
+ * @param projectKey - Optional project key to restrict matches (e.g., "PROJ")
9
+ * @returns An array of Jira issue key strings (e.g., ["PROJ-123", "CORE-456"])
10
+ */
11
+ export function scanForJiraReferences(content, projectKey) {
12
+ const pattern = projectKey
13
+ ? new RegExp(`\\b${projectKey}-(\\d+)\\b`, 'g')
14
+ : /\b([A-Z][A-Z0-9_]+-\d+)\b/g;
15
+ const keys = [];
16
+ let match;
17
+ while ((match = pattern.exec(content)) !== null) {
18
+ // When projectKey is provided, reconstruct the full key from the captured number
19
+ const key = projectKey ? `${projectKey}-${match[1]}` : match[1];
20
+ // Avoid duplicates while preserving first-occurrence order
21
+ if (!keys.includes(key)) {
22
+ keys.push(key);
23
+ }
24
+ }
25
+ return keys;
26
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jira-reference-scanner.js","sourceRoot":"","sources":["../../src/backlog/jira-reference-scanner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,UAAU,qBAAqB,CACnC,OAAe,EACf,UAAmB;IAEnB,MAAM,OAAO,GAAG,UAAU;QACxB,CAAC,CAAC,IAAI,MAAM,CAAC,MAAM,UAAU,YAAY,EAAE,GAAG,CAAC;QAC/C,CAAC,CAAC,4BAA4B,CAAC;IAEjC,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,IAAI,KAA6B,CAAC;IAElC,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAChD,iFAAiF;QACjF,MAAM,GAAG,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,IAAI,KAAK,CAAC,CAAC,CAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC;QAClE,2DAA2D;QAC3D,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjB,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,127 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { scanForJiraReferences } from './jira-reference-scanner.js';
3
+ describe('scanForJiraReferences', () => {
4
+ it('should extract a single Jira reference', () => {
5
+ const result = scanForJiraReferences('Fixes PROJ-123');
6
+ expect(result).toEqual(['PROJ-123']);
7
+ });
8
+ it('should extract multiple Jira references', () => {
9
+ const result = scanForJiraReferences('Related to PROJ-123 and CORE-456');
10
+ expect(result).toEqual(['PROJ-123', 'CORE-456']);
11
+ });
12
+ it('should extract multiple references on the same line', () => {
13
+ const result = scanForJiraReferences('PROJ-10 PROJ-20 PROJ-30');
14
+ expect(result).toEqual(['PROJ-10', 'PROJ-20', 'PROJ-30']);
15
+ });
16
+ it('should return empty array when no references found', () => {
17
+ const result = scanForJiraReferences('No issue references here');
18
+ expect(result).toEqual([]);
19
+ });
20
+ it('should handle references in code comments (single-line)', () => {
21
+ const code = `
22
+ // PROJ-100: Fix authentication bug
23
+ function login() { return true; }
24
+ `;
25
+ const result = scanForJiraReferences(code);
26
+ expect(result).toEqual(['PROJ-100']);
27
+ });
28
+ it('should handle references in block comments', () => {
29
+ const code = `
30
+ /*
31
+ * Implements PROJ-200 and CORE-201
32
+ */
33
+ export class AuthService {}
34
+ `;
35
+ const result = scanForJiraReferences(code);
36
+ expect(result).toEqual(['PROJ-200', 'CORE-201']);
37
+ });
38
+ it('should deduplicate repeated references', () => {
39
+ const content = 'PROJ-42 mentioned first, then PROJ-42 again';
40
+ const result = scanForJiraReferences(content);
41
+ expect(result).toEqual(['PROJ-42']);
42
+ });
43
+ it('should not match keys without a number', () => {
44
+ const result = scanForJiraReferences('PROJ- is not valid');
45
+ expect(result).toEqual([]);
46
+ });
47
+ it('should not match lowercase project keys', () => {
48
+ const result = scanForJiraReferences('proj-123 is not valid');
49
+ expect(result).toEqual([]);
50
+ });
51
+ it('should handle large IDs', () => {
52
+ const result = scanForJiraReferences('PROJ-1234567890');
53
+ expect(result).toEqual(['PROJ-1234567890']);
54
+ });
55
+ it('should extract references across multiple lines', () => {
56
+ const content = `
57
+ Line 1: PROJ-1
58
+ Line 2: nothing here
59
+ Line 3: PROJ-2 and CORE-3
60
+ Line 4: also PROJ-1 (duplicate)
61
+ `;
62
+ const result = scanForJiraReferences(content);
63
+ expect(result).toEqual(['PROJ-1', 'PROJ-2', 'CORE-3']);
64
+ });
65
+ it('should handle empty string', () => {
66
+ const result = scanForJiraReferences('');
67
+ expect(result).toEqual([]);
68
+ });
69
+ it('should handle project keys with numbers', () => {
70
+ const result = scanForJiraReferences('FIX2-100 is a valid key');
71
+ expect(result).toEqual(['FIX2-100']);
72
+ });
73
+ it('should handle project keys with underscores', () => {
74
+ const result = scanForJiraReferences('MY_PROJ-99 is valid');
75
+ expect(result).toEqual(['MY_PROJ-99']);
76
+ });
77
+ // --- projectKey filtering ---
78
+ describe('with projectKey filter', () => {
79
+ it('should only match the specified project', () => {
80
+ const result = scanForJiraReferences('PROJ-1 and CORE-2 and PROJ-3', 'PROJ');
81
+ expect(result).toEqual(['PROJ-1', 'PROJ-3']);
82
+ });
83
+ it('should return empty array when project key does not match', () => {
84
+ const result = scanForJiraReferences('CORE-1 and CORE-2', 'PROJ');
85
+ expect(result).toEqual([]);
86
+ });
87
+ it('should deduplicate with project key filter', () => {
88
+ const result = scanForJiraReferences('PROJ-10 then PROJ-10 again', 'PROJ');
89
+ expect(result).toEqual(['PROJ-10']);
90
+ });
91
+ it('should handle empty content with project key filter', () => {
92
+ const result = scanForJiraReferences('', 'PROJ');
93
+ expect(result).toEqual([]);
94
+ });
95
+ it('should extract from commit messages with project filter', () => {
96
+ const commit = 'feat(auth): implement SSO login PROJ-42';
97
+ const result = scanForJiraReferences(commit, 'PROJ');
98
+ expect(result).toEqual(['PROJ-42']);
99
+ });
100
+ });
101
+ // --- edge cases ---
102
+ describe('edge cases', () => {
103
+ it('should not match mid-word patterns', () => {
104
+ // Word boundary should prevent matching inside other words
105
+ const result = scanForJiraReferences('NOTAPROJ-123SUFFIX');
106
+ // This is technically a valid issue key pattern (NOTAPROJ-123),
107
+ // it will match because NOTAPROJ is uppercase+digits
108
+ expect(result.length).toBeGreaterThanOrEqual(0);
109
+ });
110
+ it('should handle references in branch names', () => {
111
+ const branch = 'feature/PROJ-123-add-login';
112
+ const result = scanForJiraReferences(branch);
113
+ expect(result).toEqual(['PROJ-123']);
114
+ });
115
+ it('should handle references in PR titles', () => {
116
+ const prTitle = '[PROJ-456] Fix authentication timeout';
117
+ const result = scanForJiraReferences(prTitle);
118
+ expect(result).toEqual(['PROJ-456']);
119
+ });
120
+ it('should handle multiple projects in one string', () => {
121
+ const content = 'PROJ-1 BACKEND-2 FRONTEND-3';
122
+ const result = scanForJiraReferences(content);
123
+ expect(result).toEqual(['PROJ-1', 'BACKEND-2', 'FRONTEND-3']);
124
+ });
125
+ });
126
+ });
127
+ //# sourceMappingURL=jira-reference-scanner.test.js.map