@elench/testkit 0.1.65 → 0.1.66

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 (305) hide show
  1. package/lib/app/browser-bridge.mjs +66 -0
  2. package/lib/app/configs.mjs +81 -0
  3. package/lib/app/configs.test.mjs +34 -0
  4. package/lib/cli/command-helpers.mjs +2 -10
  5. package/lib/cli/commands/browser/serve.mjs +3 -62
  6. package/lib/cli/db.mjs +3 -68
  7. package/lib/config/binaries.mjs +34 -0
  8. package/lib/config/database.mjs +9 -6
  9. package/lib/config/index.mjs +2 -31
  10. package/lib/config/runtime.mjs +24 -95
  11. package/lib/config/validation.mjs +18 -62
  12. package/lib/coverage/backend-discovery.mjs +68 -85
  13. package/lib/coverage/backend-discovery.test.mjs +55 -46
  14. package/lib/coverage/graph-builder.mjs +5 -5
  15. package/lib/coverage/next-ir-to-graph.mjs +0 -1
  16. package/lib/coverage/routing.mjs +2 -29
  17. package/lib/coverage/routing.test.mjs +0 -16
  18. package/lib/coverage/shared.mjs +22 -82
  19. package/lib/database/fingerprint.mjs +1 -1
  20. package/lib/known-failures/github-cache.mjs +159 -0
  21. package/lib/known-failures/github-transport.mjs +174 -0
  22. package/lib/known-failures/github.mjs +17 -325
  23. package/lib/runner/default-runtime-runner.mjs +4 -10
  24. package/lib/runner/execution-config.mjs +12 -83
  25. package/lib/runner/live-run.mjs +45 -0
  26. package/lib/runner/managed-processes.mjs +29 -0
  27. package/lib/runner/orchestrator.mjs +57 -188
  28. package/lib/runner/playwright-runner.mjs +4 -11
  29. package/lib/runner/run-finalization.mjs +132 -0
  30. package/lib/runner/run-guards.mjs +45 -0
  31. package/lib/runner/runtime-preparation.mjs +1 -1
  32. package/lib/runner/services.mjs +3 -4
  33. package/lib/runner/template-steps.mjs +8 -45
  34. package/lib/runner/template.mjs +7 -28
  35. package/lib/shared/configured-steps.mjs +178 -0
  36. package/lib/shared/configured-steps.test.mjs +73 -0
  37. package/lib/shared/execution-schema.mjs +74 -0
  38. package/lib/shared/execution-schema.test.mjs +26 -0
  39. package/node_modules/@elench/next-analysis/dist/api-routes.d.ts +7 -0
  40. package/node_modules/@elench/next-analysis/dist/api-routes.d.ts.map +1 -0
  41. package/node_modules/@elench/next-analysis/dist/api-routes.js +66 -0
  42. package/node_modules/@elench/next-analysis/dist/api-routes.js.map +1 -0
  43. package/node_modules/@elench/next-analysis/dist/app-root.d.ts +2 -0
  44. package/node_modules/@elench/next-analysis/dist/app-root.d.ts.map +1 -0
  45. package/node_modules/@elench/next-analysis/dist/app-root.js +7 -0
  46. package/node_modules/@elench/next-analysis/dist/app-root.js.map +1 -0
  47. package/node_modules/@elench/next-analysis/dist/backend-links.d.ts +8 -0
  48. package/node_modules/@elench/next-analysis/dist/backend-links.d.ts.map +1 -0
  49. package/node_modules/@elench/next-analysis/dist/backend-links.js +30 -0
  50. package/node_modules/@elench/next-analysis/dist/backend-links.js.map +1 -0
  51. package/node_modules/@elench/next-analysis/dist/index.d.ts +11 -0
  52. package/node_modules/@elench/next-analysis/dist/index.d.ts.map +1 -0
  53. package/node_modules/@elench/next-analysis/dist/index.js +10 -0
  54. package/node_modules/@elench/next-analysis/dist/index.js.map +1 -0
  55. package/node_modules/@elench/next-analysis/dist/pages.d.ts +7 -0
  56. package/node_modules/@elench/next-analysis/dist/pages.d.ts.map +1 -0
  57. package/node_modules/@elench/next-analysis/dist/pages.js +47 -0
  58. package/node_modules/@elench/next-analysis/dist/pages.js.map +1 -0
  59. package/node_modules/@elench/next-analysis/dist/project.d.ts +3 -0
  60. package/node_modules/@elench/next-analysis/dist/project.d.ts.map +1 -0
  61. package/node_modules/@elench/next-analysis/dist/project.js +102 -0
  62. package/node_modules/@elench/next-analysis/dist/project.js.map +1 -0
  63. package/node_modules/@elench/next-analysis/dist/route-tree.d.ts +7 -0
  64. package/node_modules/@elench/next-analysis/dist/route-tree.d.ts.map +1 -0
  65. package/node_modules/@elench/next-analysis/dist/route-tree.js +575 -0
  66. package/node_modules/@elench/next-analysis/dist/route-tree.js.map +1 -0
  67. package/node_modules/@elench/next-analysis/dist/routes.d.ts +6 -0
  68. package/node_modules/@elench/next-analysis/dist/routes.d.ts.map +1 -0
  69. package/node_modules/@elench/next-analysis/dist/routes.js +41 -0
  70. package/node_modules/@elench/next-analysis/dist/routes.js.map +1 -0
  71. package/node_modules/@elench/next-analysis/dist/server-actions.d.ts +7 -0
  72. package/node_modules/@elench/next-analysis/dist/server-actions.d.ts.map +1 -0
  73. package/node_modules/@elench/next-analysis/dist/server-actions.js +37 -0
  74. package/node_modules/@elench/next-analysis/dist/server-actions.js.map +1 -0
  75. package/node_modules/@elench/next-analysis/dist/shared.d.ts +57 -0
  76. package/node_modules/@elench/next-analysis/dist/shared.d.ts.map +1 -0
  77. package/node_modules/@elench/next-analysis/dist/shared.js +229 -0
  78. package/node_modules/@elench/next-analysis/dist/shared.js.map +1 -0
  79. package/node_modules/@elench/next-analysis/dist/swc.d.ts +53 -0
  80. package/node_modules/@elench/next-analysis/dist/swc.d.ts.map +1 -0
  81. package/node_modules/@elench/next-analysis/dist/swc.js +387 -0
  82. package/node_modules/@elench/next-analysis/dist/swc.js.map +1 -0
  83. package/node_modules/@elench/next-analysis/dist/types.d.ts +125 -0
  84. package/node_modules/@elench/next-analysis/dist/types.d.ts.map +1 -0
  85. package/node_modules/@elench/next-analysis/dist/types.js +2 -0
  86. package/node_modules/@elench/next-analysis/dist/types.js.map +1 -0
  87. package/node_modules/@elench/next-analysis/package.json +15 -2
  88. package/node_modules/@elench/testkit-bridge/dist/index.d.ts +36 -0
  89. package/node_modules/@elench/testkit-bridge/dist/index.d.ts.map +1 -0
  90. package/node_modules/@elench/testkit-bridge/dist/index.js +538 -0
  91. package/node_modules/@elench/testkit-bridge/dist/index.js.map +1 -0
  92. package/node_modules/@elench/testkit-bridge/package.json +16 -5
  93. package/node_modules/@elench/testkit-protocol/dist/index.d.ts +190 -0
  94. package/node_modules/@elench/testkit-protocol/dist/index.d.ts.map +1 -0
  95. package/node_modules/@elench/testkit-protocol/dist/index.js +296 -0
  96. package/node_modules/@elench/testkit-protocol/dist/index.js.map +1 -0
  97. package/node_modules/@elench/testkit-protocol/package.json +14 -7
  98. package/node_modules/@elench/ts-analysis/dist/callables.d.ts +8 -0
  99. package/node_modules/@elench/ts-analysis/dist/callables.d.ts.map +1 -0
  100. package/node_modules/@elench/ts-analysis/dist/callables.js +126 -0
  101. package/node_modules/@elench/ts-analysis/dist/callables.js.map +1 -0
  102. package/node_modules/@elench/ts-analysis/dist/exports.d.ts +6 -0
  103. package/node_modules/@elench/ts-analysis/dist/exports.d.ts.map +1 -0
  104. package/node_modules/@elench/ts-analysis/dist/exports.js +70 -0
  105. package/node_modules/@elench/ts-analysis/dist/exports.js.map +1 -0
  106. package/node_modules/@elench/ts-analysis/dist/index.d.ts +10 -0
  107. package/node_modules/@elench/ts-analysis/dist/index.d.ts.map +1 -0
  108. package/node_modules/@elench/ts-analysis/{src/index.mjs → dist/index.js} +9 -14
  109. package/node_modules/@elench/ts-analysis/dist/index.js.map +1 -0
  110. package/node_modules/@elench/ts-analysis/dist/jsx.d.ts +9 -0
  111. package/node_modules/@elench/ts-analysis/dist/jsx.d.ts.map +1 -0
  112. package/node_modules/@elench/ts-analysis/dist/jsx.js +68 -0
  113. package/node_modules/@elench/ts-analysis/dist/jsx.js.map +1 -0
  114. package/node_modules/@elench/ts-analysis/dist/project.d.ts +5 -0
  115. package/node_modules/@elench/ts-analysis/dist/project.d.ts.map +1 -0
  116. package/node_modules/@elench/ts-analysis/dist/project.js +90 -0
  117. package/node_modules/@elench/ts-analysis/dist/project.js.map +1 -0
  118. package/node_modules/@elench/ts-analysis/dist/requests.d.ts +6 -0
  119. package/node_modules/@elench/ts-analysis/dist/requests.d.ts.map +1 -0
  120. package/node_modules/@elench/ts-analysis/dist/requests.js +140 -0
  121. package/node_modules/@elench/ts-analysis/dist/requests.js.map +1 -0
  122. package/node_modules/@elench/ts-analysis/dist/resolution.d.ts +4 -0
  123. package/node_modules/@elench/ts-analysis/dist/resolution.d.ts.map +1 -0
  124. package/node_modules/@elench/ts-analysis/dist/resolution.js +53 -0
  125. package/node_modules/@elench/ts-analysis/dist/resolution.js.map +1 -0
  126. package/node_modules/@elench/ts-analysis/dist/shared.d.ts +6 -0
  127. package/node_modules/@elench/ts-analysis/dist/shared.d.ts.map +1 -0
  128. package/node_modules/@elench/ts-analysis/dist/shared.js +31 -0
  129. package/node_modules/@elench/ts-analysis/dist/shared.js.map +1 -0
  130. package/node_modules/@elench/ts-analysis/dist/syntax.d.ts +7 -0
  131. package/node_modules/@elench/ts-analysis/dist/syntax.d.ts.map +1 -0
  132. package/node_modules/@elench/ts-analysis/dist/syntax.js +27 -0
  133. package/node_modules/@elench/ts-analysis/dist/syntax.js.map +1 -0
  134. package/node_modules/@elench/ts-analysis/dist/types.d.ts +58 -0
  135. package/node_modules/@elench/ts-analysis/dist/types.d.ts.map +1 -0
  136. package/node_modules/@elench/ts-analysis/dist/types.js +2 -0
  137. package/node_modules/@elench/ts-analysis/dist/types.js.map +1 -0
  138. package/node_modules/@elench/ts-analysis/package.json +18 -2
  139. package/node_modules/typescript/LICENSE.txt +55 -0
  140. package/node_modules/typescript/README.md +50 -0
  141. package/node_modules/typescript/SECURITY.md +41 -0
  142. package/node_modules/typescript/ThirdPartyNoticeText.txt +193 -0
  143. package/node_modules/typescript/bin/tsc +2 -0
  144. package/node_modules/typescript/bin/tsserver +2 -0
  145. package/node_modules/typescript/lib/_tsc.js +133818 -0
  146. package/node_modules/typescript/lib/_tsserver.js +659 -0
  147. package/node_modules/typescript/lib/_typingsInstaller.js +222 -0
  148. package/node_modules/typescript/lib/cs/diagnosticMessages.generated.json +2122 -0
  149. package/node_modules/typescript/lib/de/diagnosticMessages.generated.json +2122 -0
  150. package/node_modules/typescript/lib/es/diagnosticMessages.generated.json +2122 -0
  151. package/node_modules/typescript/lib/fr/diagnosticMessages.generated.json +2122 -0
  152. package/node_modules/typescript/lib/it/diagnosticMessages.generated.json +2122 -0
  153. package/node_modules/typescript/lib/ja/diagnosticMessages.generated.json +2122 -0
  154. package/node_modules/typescript/lib/ko/diagnosticMessages.generated.json +2122 -0
  155. package/node_modules/typescript/lib/lib.d.ts +22 -0
  156. package/node_modules/typescript/lib/lib.decorators.d.ts +384 -0
  157. package/node_modules/typescript/lib/lib.decorators.legacy.d.ts +22 -0
  158. package/node_modules/typescript/lib/lib.dom.asynciterable.d.ts +41 -0
  159. package/node_modules/typescript/lib/lib.dom.d.ts +39429 -0
  160. package/node_modules/typescript/lib/lib.dom.iterable.d.ts +571 -0
  161. package/node_modules/typescript/lib/lib.es2015.collection.d.ts +147 -0
  162. package/node_modules/typescript/lib/lib.es2015.core.d.ts +597 -0
  163. package/node_modules/typescript/lib/lib.es2015.d.ts +28 -0
  164. package/node_modules/typescript/lib/lib.es2015.generator.d.ts +77 -0
  165. package/node_modules/typescript/lib/lib.es2015.iterable.d.ts +605 -0
  166. package/node_modules/typescript/lib/lib.es2015.promise.d.ts +81 -0
  167. package/node_modules/typescript/lib/lib.es2015.proxy.d.ts +128 -0
  168. package/node_modules/typescript/lib/lib.es2015.reflect.d.ts +144 -0
  169. package/node_modules/typescript/lib/lib.es2015.symbol.d.ts +46 -0
  170. package/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts +326 -0
  171. package/node_modules/typescript/lib/lib.es2016.array.include.d.ts +116 -0
  172. package/node_modules/typescript/lib/lib.es2016.d.ts +21 -0
  173. package/node_modules/typescript/lib/lib.es2016.full.d.ts +23 -0
  174. package/node_modules/typescript/lib/lib.es2016.intl.d.ts +31 -0
  175. package/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts +21 -0
  176. package/node_modules/typescript/lib/lib.es2017.d.ts +26 -0
  177. package/node_modules/typescript/lib/lib.es2017.date.d.ts +31 -0
  178. package/node_modules/typescript/lib/lib.es2017.full.d.ts +23 -0
  179. package/node_modules/typescript/lib/lib.es2017.intl.d.ts +44 -0
  180. package/node_modules/typescript/lib/lib.es2017.object.d.ts +49 -0
  181. package/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts +135 -0
  182. package/node_modules/typescript/lib/lib.es2017.string.d.ts +45 -0
  183. package/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts +53 -0
  184. package/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts +77 -0
  185. package/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts +53 -0
  186. package/node_modules/typescript/lib/lib.es2018.d.ts +24 -0
  187. package/node_modules/typescript/lib/lib.es2018.full.d.ts +24 -0
  188. package/node_modules/typescript/lib/lib.es2018.intl.d.ts +83 -0
  189. package/node_modules/typescript/lib/lib.es2018.promise.d.ts +30 -0
  190. package/node_modules/typescript/lib/lib.es2018.regexp.d.ts +37 -0
  191. package/node_modules/typescript/lib/lib.es2019.array.d.ts +79 -0
  192. package/node_modules/typescript/lib/lib.es2019.d.ts +24 -0
  193. package/node_modules/typescript/lib/lib.es2019.full.d.ts +24 -0
  194. package/node_modules/typescript/lib/lib.es2019.intl.d.ts +23 -0
  195. package/node_modules/typescript/lib/lib.es2019.object.d.ts +33 -0
  196. package/node_modules/typescript/lib/lib.es2019.string.d.ts +37 -0
  197. package/node_modules/typescript/lib/lib.es2019.symbol.d.ts +24 -0
  198. package/node_modules/typescript/lib/lib.es2020.bigint.d.ts +765 -0
  199. package/node_modules/typescript/lib/lib.es2020.d.ts +27 -0
  200. package/node_modules/typescript/lib/lib.es2020.date.d.ts +42 -0
  201. package/node_modules/typescript/lib/lib.es2020.full.d.ts +24 -0
  202. package/node_modules/typescript/lib/lib.es2020.intl.d.ts +474 -0
  203. package/node_modules/typescript/lib/lib.es2020.number.d.ts +28 -0
  204. package/node_modules/typescript/lib/lib.es2020.promise.d.ts +47 -0
  205. package/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts +99 -0
  206. package/node_modules/typescript/lib/lib.es2020.string.d.ts +44 -0
  207. package/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts +41 -0
  208. package/node_modules/typescript/lib/lib.es2021.d.ts +23 -0
  209. package/node_modules/typescript/lib/lib.es2021.full.d.ts +24 -0
  210. package/node_modules/typescript/lib/lib.es2021.intl.d.ts +166 -0
  211. package/node_modules/typescript/lib/lib.es2021.promise.d.ts +48 -0
  212. package/node_modules/typescript/lib/lib.es2021.string.d.ts +33 -0
  213. package/node_modules/typescript/lib/lib.es2021.weakref.d.ts +78 -0
  214. package/node_modules/typescript/lib/lib.es2022.array.d.ts +121 -0
  215. package/node_modules/typescript/lib/lib.es2022.d.ts +25 -0
  216. package/node_modules/typescript/lib/lib.es2022.error.d.ts +75 -0
  217. package/node_modules/typescript/lib/lib.es2022.full.d.ts +24 -0
  218. package/node_modules/typescript/lib/lib.es2022.intl.d.ts +145 -0
  219. package/node_modules/typescript/lib/lib.es2022.object.d.ts +26 -0
  220. package/node_modules/typescript/lib/lib.es2022.regexp.d.ts +39 -0
  221. package/node_modules/typescript/lib/lib.es2022.string.d.ts +25 -0
  222. package/node_modules/typescript/lib/lib.es2023.array.d.ts +924 -0
  223. package/node_modules/typescript/lib/lib.es2023.collection.d.ts +21 -0
  224. package/node_modules/typescript/lib/lib.es2023.d.ts +22 -0
  225. package/node_modules/typescript/lib/lib.es2023.full.d.ts +24 -0
  226. package/node_modules/typescript/lib/lib.es2023.intl.d.ts +56 -0
  227. package/node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts +65 -0
  228. package/node_modules/typescript/lib/lib.es2024.collection.d.ts +29 -0
  229. package/node_modules/typescript/lib/lib.es2024.d.ts +26 -0
  230. package/node_modules/typescript/lib/lib.es2024.full.d.ts +24 -0
  231. package/node_modules/typescript/lib/lib.es2024.object.d.ts +29 -0
  232. package/node_modules/typescript/lib/lib.es2024.promise.d.ts +35 -0
  233. package/node_modules/typescript/lib/lib.es2024.regexp.d.ts +25 -0
  234. package/node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts +68 -0
  235. package/node_modules/typescript/lib/lib.es2024.string.d.ts +29 -0
  236. package/node_modules/typescript/lib/lib.es5.d.ts +4601 -0
  237. package/node_modules/typescript/lib/lib.es6.d.ts +23 -0
  238. package/node_modules/typescript/lib/lib.esnext.array.d.ts +35 -0
  239. package/node_modules/typescript/lib/lib.esnext.collection.d.ts +96 -0
  240. package/node_modules/typescript/lib/lib.esnext.d.ts +29 -0
  241. package/node_modules/typescript/lib/lib.esnext.decorators.d.ts +28 -0
  242. package/node_modules/typescript/lib/lib.esnext.disposable.d.ts +193 -0
  243. package/node_modules/typescript/lib/lib.esnext.error.d.ts +24 -0
  244. package/node_modules/typescript/lib/lib.esnext.float16.d.ts +445 -0
  245. package/node_modules/typescript/lib/lib.esnext.full.d.ts +24 -0
  246. package/node_modules/typescript/lib/lib.esnext.intl.d.ts +21 -0
  247. package/node_modules/typescript/lib/lib.esnext.iterator.d.ts +148 -0
  248. package/node_modules/typescript/lib/lib.esnext.promise.d.ts +34 -0
  249. package/node_modules/typescript/lib/lib.esnext.sharedmemory.d.ts +25 -0
  250. package/node_modules/typescript/lib/lib.scripthost.d.ts +322 -0
  251. package/node_modules/typescript/lib/lib.webworker.asynciterable.d.ts +41 -0
  252. package/node_modules/typescript/lib/lib.webworker.d.ts +13150 -0
  253. package/node_modules/typescript/lib/lib.webworker.importscripts.d.ts +23 -0
  254. package/node_modules/typescript/lib/lib.webworker.iterable.d.ts +340 -0
  255. package/node_modules/typescript/lib/pl/diagnosticMessages.generated.json +2122 -0
  256. package/node_modules/typescript/lib/pt-br/diagnosticMessages.generated.json +2122 -0
  257. package/node_modules/typescript/lib/ru/diagnosticMessages.generated.json +2122 -0
  258. package/node_modules/typescript/lib/tr/diagnosticMessages.generated.json +2122 -0
  259. package/node_modules/typescript/lib/tsc.js +8 -0
  260. package/node_modules/typescript/lib/tsserver.js +8 -0
  261. package/node_modules/typescript/lib/tsserverlibrary.d.ts +17 -0
  262. package/node_modules/typescript/lib/tsserverlibrary.js +21 -0
  263. package/node_modules/typescript/lib/typesMap.json +497 -0
  264. package/node_modules/typescript/lib/typescript.d.ts +11437 -0
  265. package/node_modules/typescript/lib/typescript.js +200276 -0
  266. package/node_modules/typescript/lib/typingsInstaller.js +8 -0
  267. package/node_modules/typescript/lib/watchGuard.js +53 -0
  268. package/node_modules/typescript/lib/zh-cn/diagnosticMessages.generated.json +2122 -0
  269. package/node_modules/typescript/lib/zh-tw/diagnosticMessages.generated.json +2122 -0
  270. package/node_modules/typescript/package.json +120 -0
  271. package/package.json +12 -9
  272. package/lib/coverage/fs-walk.mjs +0 -64
  273. package/node_modules/@elench/next-analysis/src/api-routes.mjs +0 -81
  274. package/node_modules/@elench/next-analysis/src/api-routes.test.mjs +0 -22
  275. package/node_modules/@elench/next-analysis/src/app-root.mjs +0 -7
  276. package/node_modules/@elench/next-analysis/src/backend-links.mjs +0 -31
  277. package/node_modules/@elench/next-analysis/src/index.mjs +0 -21
  278. package/node_modules/@elench/next-analysis/src/pages.mjs +0 -68
  279. package/node_modules/@elench/next-analysis/src/project.mjs +0 -94
  280. package/node_modules/@elench/next-analysis/src/project.test.mjs +0 -35
  281. package/node_modules/@elench/next-analysis/src/route-tree.mjs +0 -621
  282. package/node_modules/@elench/next-analysis/src/routes.mjs +0 -41
  283. package/node_modules/@elench/next-analysis/src/routes.test.mjs +0 -25
  284. package/node_modules/@elench/next-analysis/src/server-actions.mjs +0 -53
  285. package/node_modules/@elench/next-analysis/src/server-actions.test.mjs +0 -37
  286. package/node_modules/@elench/next-analysis/src/shared.mjs +0 -209
  287. package/node_modules/@elench/next-analysis/src/swc.mjs +0 -388
  288. package/node_modules/@elench/testkit-bridge/src/index.mjs +0 -583
  289. package/node_modules/@elench/testkit-bridge/src/index.test.mjs +0 -409
  290. package/node_modules/@elench/testkit-protocol/src/index.d.ts +0 -231
  291. package/node_modules/@elench/testkit-protocol/src/index.mjs +0 -265
  292. package/node_modules/@elench/testkit-protocol/src/index.test.mjs +0 -242
  293. package/node_modules/@elench/ts-analysis/src/callables.mjs +0 -135
  294. package/node_modules/@elench/ts-analysis/src/callables.test.mjs +0 -55
  295. package/node_modules/@elench/ts-analysis/src/exports.mjs +0 -69
  296. package/node_modules/@elench/ts-analysis/src/exports.test.mjs +0 -50
  297. package/node_modules/@elench/ts-analysis/src/jsx.mjs +0 -69
  298. package/node_modules/@elench/ts-analysis/src/jsx.test.mjs +0 -43
  299. package/node_modules/@elench/ts-analysis/src/project.mjs +0 -100
  300. package/node_modules/@elench/ts-analysis/src/project.test.mjs +0 -54
  301. package/node_modules/@elench/ts-analysis/src/requests.mjs +0 -141
  302. package/node_modules/@elench/ts-analysis/src/requests.test.mjs +0 -35
  303. package/node_modules/@elench/ts-analysis/src/resolution.mjs +0 -53
  304. package/node_modules/@elench/ts-analysis/src/shared.mjs +0 -32
  305. package/node_modules/@elench/ts-analysis/src/syntax.mjs +0 -27
@@ -0,0 +1,159 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+
4
+ export function loadIssueCache(productDir, cachePath, schemaVersion) {
5
+ const filePath = path.join(productDir, ...cachePath);
6
+ if (!fs.existsSync(filePath)) {
7
+ return {
8
+ schemaVersion,
9
+ entries: {},
10
+ };
11
+ }
12
+
13
+ try {
14
+ const parsed = JSON.parse(fs.readFileSync(filePath, "utf8"));
15
+ if (parsed?.schemaVersion !== schemaVersion || typeof parsed.entries !== "object") {
16
+ return {
17
+ schemaVersion,
18
+ entries: {},
19
+ };
20
+ }
21
+ return parsed;
22
+ } catch {
23
+ return {
24
+ schemaVersion,
25
+ entries: {},
26
+ };
27
+ }
28
+ }
29
+
30
+ export function resolveIssueCache(cache, issueNumbersByRepo, config, now) {
31
+ const issuesByRepo = new Map();
32
+ const missingByRepo = new Map();
33
+ const staleByRepo = new Map();
34
+ const ttlMs = config.cacheTtlSeconds * 1000;
35
+
36
+ for (const [repo, numbers] of issueNumbersByRepo.entries()) {
37
+ const cachedIssues = new Map();
38
+ const missing = [];
39
+ const stale = [];
40
+
41
+ for (const number of numbers) {
42
+ const key = buildIssueCacheKey(repo, number);
43
+ const cached = cache.entries[key];
44
+ if (!cached) {
45
+ missing.push(number);
46
+ continue;
47
+ }
48
+
49
+ const checkedAt = Date.parse(cached.checkedAt);
50
+ const normalized = {
51
+ repo,
52
+ number,
53
+ exists: Boolean(cached.exists),
54
+ title: normalizeOptionalString(cached.title),
55
+ state: normalizeOptionalString(cached.state),
56
+ url: normalizeOptionalString(cached.url),
57
+ checkedAt: cached.checkedAt || null,
58
+ source: "cache",
59
+ };
60
+
61
+ if (!Number.isFinite(checkedAt) || now - checkedAt > ttlMs) {
62
+ stale.push(number);
63
+ cachedIssues.set(number, normalized);
64
+ continue;
65
+ }
66
+
67
+ cachedIssues.set(number, normalized);
68
+ }
69
+
70
+ issuesByRepo.set(repo, cachedIssues);
71
+ if (missing.length > 0 || stale.length > 0) {
72
+ missingByRepo.set(repo, [...new Set([...missing, ...stale])].sort((a, b) => a - b));
73
+ }
74
+ if (stale.length > 0) {
75
+ staleByRepo.set(repo, stale.sort((a, b) => a - b));
76
+ }
77
+ }
78
+
79
+ return {
80
+ issuesByRepo,
81
+ missingByRepo,
82
+ staleByRepo,
83
+ };
84
+ }
85
+
86
+ export function updateIssueCache(cache, issuesByRepo, now, schemaVersion) {
87
+ cache.schemaVersion = schemaVersion;
88
+ cache.entries = cache.entries || {};
89
+ const checkedAt = new Date(now).toISOString();
90
+
91
+ for (const [repo, issues] of issuesByRepo.entries()) {
92
+ for (const [number, issue] of issues.entries()) {
93
+ issue.checkedAt = checkedAt;
94
+ cache.entries[buildIssueCacheKey(repo, number)] = {
95
+ exists: issue.exists,
96
+ title: issue.title,
97
+ state: issue.state,
98
+ url: issue.url,
99
+ checkedAt,
100
+ };
101
+ }
102
+ }
103
+ }
104
+
105
+ export function writeIssueCache(productDir, cachePath, cache) {
106
+ const filePath = path.join(productDir, ...cachePath);
107
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
108
+ fs.writeFileSync(filePath, `${JSON.stringify(cache, null, 2)}\n`);
109
+ }
110
+
111
+ export function applyStaleCacheFallback(issuesByRepo, staleByRepo, findings) {
112
+ let usedStale = false;
113
+ for (const [repo, numbers] of staleByRepo.entries()) {
114
+ const issues = issuesByRepo.get(repo);
115
+ if (!issues) continue;
116
+ for (const number of numbers) {
117
+ if (issues.has(number)) {
118
+ usedStale = true;
119
+ }
120
+ }
121
+ }
122
+ if (usedStale) {
123
+ findings.push({
124
+ code: "used_stale_cache",
125
+ severity: "warning",
126
+ message: "Used stale cached GitHub issue metadata because fresh validation failed",
127
+ });
128
+ }
129
+ return issuesByRepo;
130
+ }
131
+
132
+ export function mergeIssuesByRepo(left, right) {
133
+ const merged = new Map();
134
+ for (const [repo, issues] of left.entries()) {
135
+ merged.set(repo, new Map(issues.entries()));
136
+ }
137
+
138
+ for (const [repo, issues] of right.entries()) {
139
+ if (!merged.has(repo)) {
140
+ merged.set(repo, new Map());
141
+ }
142
+ const mergedIssues = merged.get(repo);
143
+ for (const [number, issue] of issues.entries()) {
144
+ mergedIssues.set(number, issue);
145
+ }
146
+ }
147
+
148
+ return merged;
149
+ }
150
+
151
+ function buildIssueCacheKey(repo, number) {
152
+ return `${repo}#${number}`;
153
+ }
154
+
155
+ function normalizeOptionalString(value) {
156
+ if (typeof value !== "string") return null;
157
+ const normalized = value.trim();
158
+ return normalized.length > 0 ? normalized : null;
159
+ }
@@ -0,0 +1,174 @@
1
+ import { execFile } from "child_process";
2
+ import { promisify } from "util";
3
+
4
+ const execFileAsync = promisify(execFile);
5
+
6
+ export function parseGitHubRepoSlug(remoteUrl) {
7
+ const normalized = normalizeOptionalString(remoteUrl);
8
+ if (!normalized) return null;
9
+
10
+ let match = normalized.match(/^https:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?$/i);
11
+ if (match) return `${match[1]}/${match[2]}`;
12
+
13
+ match = normalized.match(/^git@github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/i);
14
+ if (match) return `${match[1]}/${match[2]}`;
15
+
16
+ match = normalized.match(/^ssh:\/\/git@github\.com\/([^/]+)\/([^/]+?)(?:\.git)?$/i);
17
+ if (match) return `${match[1]}/${match[2]}`;
18
+
19
+ return null;
20
+ }
21
+
22
+ export async function createDefaultGitHubIssueTransport(env = process.env) {
23
+ const token = env.GH_TOKEN || env.GITHUB_TOKEN || null;
24
+ if (token) {
25
+ return {
26
+ type: "token",
27
+ async fetchRepoIssues(repo, numbers) {
28
+ return fetchRepoIssuesViaToken(repo, numbers, token);
29
+ },
30
+ };
31
+ }
32
+
33
+ try {
34
+ await execFileAsync("gh", ["auth", "status"], {
35
+ encoding: "utf8",
36
+ env,
37
+ maxBuffer: 1024 * 1024,
38
+ });
39
+ return {
40
+ type: "gh",
41
+ async fetchRepoIssues(repo, numbers) {
42
+ return fetchRepoIssuesViaGh(repo, numbers, env);
43
+ },
44
+ };
45
+ } catch {
46
+ return null;
47
+ }
48
+ }
49
+
50
+ export async function fetchIssuesByRepo(client, issueNumbersByRepo) {
51
+ const issuesByRepo = new Map();
52
+
53
+ for (const [repo, numbers] of issueNumbersByRepo.entries()) {
54
+ const issueMap = new Map();
55
+ const chunks = chunkValues(numbers, 40);
56
+ for (const chunk of chunks) {
57
+ const fetched = await client.fetchRepoIssues(repo, chunk);
58
+ for (const [number, issue] of fetched.entries()) {
59
+ issueMap.set(number, issue);
60
+ }
61
+ }
62
+ issuesByRepo.set(repo, issueMap);
63
+ }
64
+
65
+ return issuesByRepo;
66
+ }
67
+
68
+ async function fetchRepoIssuesViaToken(repo, numbers, token) {
69
+ const query = buildIssueQuery(repo, numbers);
70
+ const response = await fetch("https://api.github.com/graphql", {
71
+ method: "POST",
72
+ headers: {
73
+ "Content-Type": "application/json",
74
+ Accept: "application/vnd.github+json",
75
+ Authorization: `Bearer ${token}`,
76
+ "X-GitHub-Api-Version": "2022-11-28",
77
+ },
78
+ body: JSON.stringify({ query }),
79
+ });
80
+
81
+ const payload = await response.json().catch(() => null);
82
+ if (!response.ok) {
83
+ throw new Error(
84
+ `GitHub GraphQL request failed with ${response.status}${payload?.message ? `: ${payload.message}` : ""}`
85
+ );
86
+ }
87
+ if (Array.isArray(payload?.errors) && payload.errors.length > 0) {
88
+ throw new Error(payload.errors.map((error) => error.message).join("; "));
89
+ }
90
+ return normalizeGraphqlIssuesResponse(repo, numbers, payload?.data);
91
+ }
92
+
93
+ async function fetchRepoIssuesViaGh(repo, numbers, env) {
94
+ const query = buildIssueQuery(repo, numbers);
95
+ const { stdout } = await execFileAsync("gh", ["api", "graphql", "-f", `query=${query}`], {
96
+ encoding: "utf8",
97
+ env,
98
+ maxBuffer: 1024 * 1024,
99
+ });
100
+ const payload = JSON.parse(stdout);
101
+ if (Array.isArray(payload?.errors) && payload.errors.length > 0) {
102
+ throw new Error(payload.errors.map((error) => error.message).join("; "));
103
+ }
104
+ return normalizeGraphqlIssuesResponse(repo, numbers, payload?.data);
105
+ }
106
+
107
+ function buildIssueQuery(repo, numbers) {
108
+ const [owner, name] = repo.split("/");
109
+ return `
110
+ query TestkitKnownFailureIssues {
111
+ repository(owner: ${JSON.stringify(owner)}, name: ${JSON.stringify(name)}) {
112
+ ${numbers
113
+ .map(
114
+ (number) => `
115
+ issue_${number}: issue(number: ${number}) {
116
+ number
117
+ title
118
+ state
119
+ url
120
+ }
121
+ `
122
+ )
123
+ .join("\n")}
124
+ }
125
+ }
126
+ `;
127
+ }
128
+
129
+ function normalizeGraphqlIssuesResponse(repo, numbers, data) {
130
+ const map = new Map();
131
+ const repository = data?.repository || null;
132
+ for (const number of numbers) {
133
+ const issue = repository?.[`issue_${number}`] || null;
134
+ if (!issue) {
135
+ map.set(number, {
136
+ repo,
137
+ number,
138
+ exists: false,
139
+ title: null,
140
+ state: null,
141
+ url: null,
142
+ checkedAt: null,
143
+ source: "github",
144
+ });
145
+ continue;
146
+ }
147
+
148
+ map.set(number, {
149
+ repo,
150
+ number: issue.number,
151
+ exists: true,
152
+ title: normalizeOptionalString(issue.title),
153
+ state: normalizeOptionalString(issue.state),
154
+ url: normalizeOptionalString(issue.url),
155
+ checkedAt: null,
156
+ source: "github",
157
+ });
158
+ }
159
+ return map;
160
+ }
161
+
162
+ function normalizeOptionalString(value) {
163
+ if (typeof value !== "string") return null;
164
+ const normalized = value.trim();
165
+ return normalized.length > 0 ? normalized : null;
166
+ }
167
+
168
+ function chunkValues(values, size) {
169
+ const chunks = [];
170
+ for (let index = 0; index < values.length; index += size) {
171
+ chunks.push(values.slice(index, index + size));
172
+ }
173
+ return chunks;
174
+ }
@@ -1,10 +1,18 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import { execFile } from "child_process";
4
- import { promisify } from "util";
5
1
  import { findMatchingKnownFailureEntries } from "./index.mjs";
6
-
7
- const execFileAsync = promisify(execFile);
2
+ import {
3
+ applyStaleCacheFallback,
4
+ loadIssueCache,
5
+ mergeIssuesByRepo,
6
+ resolveIssueCache,
7
+ updateIssueCache,
8
+ writeIssueCache,
9
+ } from "./github-cache.mjs";
10
+ import {
11
+ createDefaultGitHubIssueTransport,
12
+ fetchIssuesByRepo,
13
+ parseGitHubRepoSlug,
14
+ } from "./github-transport.mjs";
15
+ export { parseGitHubRepoSlug } from "./github-transport.mjs";
8
16
  const DEFAULT_CACHE_TTL_SECONDS = 15 * 60;
9
17
  const CACHE_SCHEMA_VERSION = 1;
10
18
  const CACHE_PATH = [".testkit", "known-failures", "github-issues-cache.json"];
@@ -60,7 +68,7 @@ export async function validateKnownFailureIssues({
60
68
  const issueNumbersByRepo = groupIssueNumbersByRepo(document.entries);
61
69
  const repoSlug = gitMetadata?.repoSlug || null;
62
70
  const remoteUrl = gitMetadata?.remoteUrl || null;
63
- const cache = loadIssueCache(productDir);
71
+ const cache = loadIssueCache(productDir, CACHE_PATH, CACHE_SCHEMA_VERSION);
64
72
  const cacheResolution = resolveIssueCache(cache, issueNumbersByRepo, normalizedConfig, now);
65
73
  const availabilityFindings = [];
66
74
  let issuesByRepo = cacheResolution.issuesByRepo;
@@ -71,8 +79,8 @@ export async function validateKnownFailureIssues({
71
79
  try {
72
80
  const fetchedIssues = await fetchIssuesByRepo(client, cacheResolution.missingByRepo);
73
81
  issuesByRepo = mergeIssuesByRepo(issuesByRepo, fetchedIssues);
74
- updateIssueCache(cache, fetchedIssues, now);
75
- writeIssueCache(productDir, cache);
82
+ updateIssueCache(cache, fetchedIssues, now, CACHE_SCHEMA_VERSION);
83
+ writeIssueCache(productDir, CACHE_PATH, cache);
76
84
  } catch (error) {
77
85
  issuesByRepo = applyStaleCacheFallback(
78
86
  issuesByRepo,
@@ -191,167 +199,6 @@ export function buildKnownFailureIssueValidationSummaryLines(result) {
191
199
  ];
192
200
  }
193
201
 
194
- export function parseGitHubRepoSlug(remoteUrl) {
195
- const normalized = normalizeOptionalString(remoteUrl);
196
- if (!normalized) return null;
197
-
198
- let match = normalized.match(/^https:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?$/i);
199
- if (match) return `${match[1]}/${match[2]}`;
200
-
201
- match = normalized.match(/^git@github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/i);
202
- if (match) return `${match[1]}/${match[2]}`;
203
-
204
- match = normalized.match(/^ssh:\/\/git@github\.com\/([^/]+)\/([^/]+?)(?:\.git)?$/i);
205
- if (match) return `${match[1]}/${match[2]}`;
206
-
207
- return null;
208
- }
209
-
210
- async function createDefaultGitHubIssueTransport() {
211
- const token = process.env.GH_TOKEN || process.env.GITHUB_TOKEN || null;
212
- if (token) {
213
- return {
214
- type: "token",
215
- async fetchRepoIssues(repo, numbers) {
216
- return fetchRepoIssuesViaToken(repo, numbers, token);
217
- },
218
- };
219
- }
220
-
221
- try {
222
- await execFileAsync("gh", ["auth", "status"], {
223
- encoding: "utf8",
224
- env: process.env,
225
- maxBuffer: 1024 * 1024,
226
- });
227
- return {
228
- type: "gh",
229
- async fetchRepoIssues(repo, numbers) {
230
- return fetchRepoIssuesViaGh(repo, numbers);
231
- },
232
- };
233
- } catch {
234
- return null;
235
- }
236
- }
237
-
238
- async function fetchIssuesByRepo(client, issueNumbersByRepo) {
239
- const issuesByRepo = new Map();
240
-
241
- for (const [repo, numbers] of issueNumbersByRepo.entries()) {
242
- const issueMap = new Map();
243
- const chunks = chunkValues(numbers, 40);
244
- for (const chunk of chunks) {
245
- const fetched = await client.fetchRepoIssues(repo, chunk);
246
- for (const [number, issue] of fetched.entries()) {
247
- issueMap.set(number, issue);
248
- }
249
- }
250
- issuesByRepo.set(repo, issueMap);
251
- }
252
-
253
- return issuesByRepo;
254
- }
255
-
256
- async function fetchRepoIssuesViaToken(repo, numbers, token) {
257
- const query = buildIssueQuery(repo, numbers);
258
- const response = await fetch("https://api.github.com/graphql", {
259
- method: "POST",
260
- headers: {
261
- "Content-Type": "application/json",
262
- Accept: "application/vnd.github+json",
263
- Authorization: `Bearer ${token}`,
264
- "X-GitHub-Api-Version": "2022-11-28",
265
- },
266
- body: JSON.stringify({ query }),
267
- });
268
-
269
- const payload = await response.json().catch(() => null);
270
- if (!response.ok) {
271
- throw new Error(
272
- `GitHub GraphQL request failed with ${response.status}${
273
- payload?.message ? `: ${payload.message}` : ""
274
- }`
275
- );
276
- }
277
- if (Array.isArray(payload?.errors) && payload.errors.length > 0) {
278
- throw new Error(payload.errors.map((error) => error.message).join("; "));
279
- }
280
- return normalizeGraphqlIssuesResponse(repo, numbers, payload?.data);
281
- }
282
-
283
- async function fetchRepoIssuesViaGh(repo, numbers) {
284
- const query = buildIssueQuery(repo, numbers);
285
- const { stdout } = await execFileAsync(
286
- "gh",
287
- ["api", "graphql", "-f", `query=${query}`],
288
- {
289
- encoding: "utf8",
290
- env: process.env,
291
- maxBuffer: 1024 * 1024,
292
- }
293
- );
294
- const payload = JSON.parse(stdout);
295
- if (Array.isArray(payload?.errors) && payload.errors.length > 0) {
296
- throw new Error(payload.errors.map((error) => error.message).join("; "));
297
- }
298
- return normalizeGraphqlIssuesResponse(repo, numbers, payload?.data);
299
- }
300
-
301
- function buildIssueQuery(repo, numbers) {
302
- const [owner, name] = repo.split("/");
303
- return `
304
- query TestkitKnownFailureIssues {
305
- repository(owner: ${JSON.stringify(owner)}, name: ${JSON.stringify(name)}) {
306
- ${numbers
307
- .map(
308
- (number) => `
309
- issue_${number}: issue(number: ${number}) {
310
- number
311
- title
312
- state
313
- url
314
- }
315
- `
316
- )
317
- .join("\n")}
318
- }
319
- }
320
- `;
321
- }
322
-
323
- function normalizeGraphqlIssuesResponse(repo, numbers, data) {
324
- const map = new Map();
325
- const repository = data?.repository || null;
326
- for (const number of numbers) {
327
- const issue = repository?.[`issue_${number}`] || null;
328
- if (!issue) {
329
- map.set(number, {
330
- repo,
331
- number,
332
- exists: false,
333
- title: null,
334
- state: null,
335
- url: null,
336
- checkedAt: null,
337
- source: "github",
338
- });
339
- continue;
340
- }
341
-
342
- map.set(number, {
343
- repo,
344
- number: issue.number,
345
- exists: true,
346
- title: normalizeOptionalString(issue.title),
347
- state: normalizeOptionalString(issue.state),
348
- url: normalizeOptionalString(issue.url),
349
- checkedAt: null,
350
- source: "github",
351
- });
352
- }
353
- return map;
354
- }
355
202
 
356
203
  function collectObservedKnownFailureEntries(document, runArtifact, statusArtifact) {
357
204
  const observedTests = collectObservedTests(runArtifact, statusArtifact);
@@ -583,161 +430,6 @@ function buildIssueValidationSummary(entries, globalFindings) {
583
430
  };
584
431
  }
585
432
 
586
- function loadIssueCache(productDir) {
587
- const filePath = getIssueCachePath(productDir);
588
- if (!fs.existsSync(filePath)) {
589
- return {
590
- schemaVersion: CACHE_SCHEMA_VERSION,
591
- entries: {},
592
- };
593
- }
594
-
595
- try {
596
- const parsed = JSON.parse(fs.readFileSync(filePath, "utf8"));
597
- if (parsed?.schemaVersion !== CACHE_SCHEMA_VERSION || typeof parsed.entries !== "object") {
598
- return {
599
- schemaVersion: CACHE_SCHEMA_VERSION,
600
- entries: {},
601
- };
602
- }
603
- return parsed;
604
- } catch {
605
- return {
606
- schemaVersion: CACHE_SCHEMA_VERSION,
607
- entries: {},
608
- };
609
- }
610
- }
611
-
612
- function resolveIssueCache(cache, issueNumbersByRepo, config, now) {
613
- const issuesByRepo = new Map();
614
- const missingByRepo = new Map();
615
- const staleByRepo = new Map();
616
- const ttlMs = config.cacheTtlSeconds * 1000;
617
-
618
- for (const [repo, numbers] of issueNumbersByRepo.entries()) {
619
- const cachedIssues = new Map();
620
- const missing = [];
621
- const stale = [];
622
-
623
- for (const number of numbers) {
624
- const key = buildIssueCacheKey(repo, number);
625
- const cached = cache.entries[key];
626
- if (!cached) {
627
- missing.push(number);
628
- continue;
629
- }
630
-
631
- const checkedAt = Date.parse(cached.checkedAt);
632
- const normalized = {
633
- repo,
634
- number,
635
- exists: Boolean(cached.exists),
636
- title: normalizeOptionalString(cached.title),
637
- state: normalizeOptionalString(cached.state),
638
- url: normalizeOptionalString(cached.url),
639
- checkedAt: cached.checkedAt || null,
640
- source: "cache",
641
- };
642
-
643
- if (!Number.isFinite(checkedAt) || now - checkedAt > ttlMs) {
644
- stale.push(number);
645
- cachedIssues.set(number, normalized);
646
- continue;
647
- }
648
-
649
- cachedIssues.set(number, normalized);
650
- }
651
-
652
- issuesByRepo.set(repo, cachedIssues);
653
- if (missing.length > 0 || stale.length > 0) {
654
- missingByRepo.set(repo, [...new Set([...missing, ...stale])].sort((a, b) => a - b));
655
- }
656
- if (stale.length > 0) {
657
- staleByRepo.set(repo, stale.sort((a, b) => a - b));
658
- }
659
- }
660
-
661
- return {
662
- issuesByRepo,
663
- missingByRepo,
664
- staleByRepo,
665
- };
666
- }
667
-
668
- function updateIssueCache(cache, issuesByRepo, now) {
669
- cache.schemaVersion = CACHE_SCHEMA_VERSION;
670
- cache.entries = cache.entries || {};
671
- const checkedAt = new Date(now).toISOString();
672
-
673
- for (const [repo, issues] of issuesByRepo.entries()) {
674
- for (const [number, issue] of issues.entries()) {
675
- issue.checkedAt = checkedAt;
676
- cache.entries[buildIssueCacheKey(repo, number)] = {
677
- exists: issue.exists,
678
- title: issue.title,
679
- state: issue.state,
680
- url: issue.url,
681
- checkedAt,
682
- };
683
- }
684
- }
685
- }
686
-
687
- function writeIssueCache(productDir, cache) {
688
- const filePath = getIssueCachePath(productDir);
689
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
690
- fs.writeFileSync(filePath, `${JSON.stringify(cache, null, 2)}\n`);
691
- }
692
-
693
- function getIssueCachePath(productDir) {
694
- return path.join(productDir, ...CACHE_PATH);
695
- }
696
-
697
- function applyStaleCacheFallback(issuesByRepo, staleByRepo, findings) {
698
- let usedStale = false;
699
- for (const [repo, numbers] of staleByRepo.entries()) {
700
- const issues = issuesByRepo.get(repo);
701
- if (!issues) continue;
702
- for (const number of numbers) {
703
- if (issues.has(number)) {
704
- usedStale = true;
705
- }
706
- }
707
- }
708
- if (usedStale) {
709
- findings.push({
710
- code: "used_stale_cache",
711
- severity: "warning",
712
- message: "Used stale cached GitHub issue metadata because fresh validation failed",
713
- });
714
- }
715
- return issuesByRepo;
716
- }
717
-
718
- function mergeIssuesByRepo(left, right) {
719
- const merged = new Map();
720
- for (const [repo, issues] of left.entries()) {
721
- merged.set(repo, new Map(issues.entries()));
722
- }
723
-
724
- for (const [repo, issues] of right.entries()) {
725
- if (!merged.has(repo)) {
726
- merged.set(repo, new Map());
727
- }
728
- const mergedIssues = merged.get(repo);
729
- for (const [number, issue] of issues.entries()) {
730
- mergedIssues.set(number, issue);
731
- }
732
- }
733
-
734
- return merged;
735
- }
736
-
737
- function buildIssueCacheKey(repo, number) {
738
- return `${repo}#${number}`;
739
- }
740
-
741
433
  function normalizeIssueState(value) {
742
434
  const normalized = normalizeOptionalString(value);
743
435
  if (!normalized) return null;