@hyperfrontend/project-scope 0.2.1 → 0.2.3

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 (443) hide show
  1. package/CHANGELOG.md +14 -1
  2. package/README.md +3 -4
  3. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/array/index.cjs.js +7 -0
  4. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/array/index.esm.js +5 -0
  5. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/console/index.cjs.js +13 -0
  6. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/console/index.esm.js +8 -0
  7. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/date/index.cjs.js +10 -0
  8. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/date/index.esm.js +8 -0
  9. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/error/index.cjs.js +6 -0
  10. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/error/index.esm.js +5 -0
  11. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/json/index.cjs.js +7 -0
  12. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/json/index.esm.js +5 -0
  13. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/map/index.cjs.js +6 -0
  14. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/map/index.esm.js +5 -0
  15. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/math/index.cjs.js +9 -0
  16. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/math/index.esm.js +6 -0
  17. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/number/index.cjs.js +7 -0
  18. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/number/index.esm.js +7 -0
  19. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/object/index.cjs.js +15 -0
  20. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/object/index.esm.js +9 -0
  21. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/set/index.cjs.js +6 -0
  22. package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/set/index.esm.js +5 -0
  23. package/_dependencies/@hyperfrontend/logging/index.cjs.js +191 -0
  24. package/_dependencies/@hyperfrontend/logging/index.d.ts +151 -0
  25. package/_dependencies/@hyperfrontend/logging/index.esm.js +186 -0
  26. package/_shared/core/cache/index.cjs.js +135 -0
  27. package/_shared/core/cache/index.esm.js +128 -0
  28. package/_shared/core/errors/structured-errors/index.cjs.js +28 -0
  29. package/_shared/core/errors/structured-errors/index.esm.js +23 -0
  30. package/_shared/core/fs/guard/index.cjs.js +7 -0
  31. package/_shared/core/fs/guard/index.esm.js +5 -0
  32. package/_shared/core/fs/stat/index.cjs.js +47 -0
  33. package/_shared/core/fs/stat/index.esm.js +41 -0
  34. package/_shared/core/path/confine/index.cjs.js +22 -0
  35. package/_shared/core/path/confine/index.esm.js +19 -0
  36. package/_shared/core/path/join/index.cjs.js +13 -0
  37. package/_shared/core/path/join/index.esm.js +10 -0
  38. package/_shared/core/path/normalize/index.cjs.js +37 -0
  39. package/_shared/core/path/normalize/index.esm.js +31 -0
  40. package/_shared/core/path/resolve/index.cjs.js +47 -0
  41. package/_shared/core/path/resolve/index.esm.js +41 -0
  42. package/_shared/core/path/segments/index.cjs.js +38 -0
  43. package/_shared/core/path/segments/index.esm.js +31 -0
  44. package/_shared/core/patterns/glob/index.cjs.js +145 -0
  45. package/_shared/core/patterns/glob/index.esm.js +136 -0
  46. package/_shared/core/platform/detect/index.cjs.js +103 -0
  47. package/_shared/core/platform/detect/index.esm.js +95 -0
  48. package/_shared/core/platform/line-endings/index.cjs.js +52 -0
  49. package/_shared/core/platform/line-endings/index.esm.js +44 -0
  50. package/_shared/project/config/patterns/index.cjs.js +172 -0
  51. package/_shared/project/config/patterns/index.esm.js +169 -0
  52. package/_shared/tech/monorepo/pnpm-workspaces/index.cjs.js +33 -0
  53. package/_shared/tech/monorepo/pnpm-workspaces/index.esm.js +31 -0
  54. package/_shared/tech/shared-utils/detector-helpers/index.cjs.js +48 -0
  55. package/_shared/tech/shared-utils/detector-helpers/index.esm.js +43 -0
  56. package/_shared/vfs/types/index.cjs.js +14 -0
  57. package/_shared/vfs/types/index.esm.js +12 -0
  58. package/cli/index.cjs.js +1706 -1910
  59. package/cli/index.d.ts +273 -7
  60. package/cli/index.d.ts.map +1 -1
  61. package/cli/index.esm.js +1593 -1797
  62. package/core/encoding/index.cjs.js +86 -401
  63. package/core/encoding/index.d.ts +186 -3
  64. package/core/encoding/index.d.ts.map +1 -1
  65. package/core/encoding/index.esm.js +78 -392
  66. package/core/fs/index.cjs.js +243 -583
  67. package/core/fs/index.d.ts +479 -6
  68. package/core/fs/index.d.ts.map +1 -1
  69. package/core/fs/index.esm.js +233 -573
  70. package/core/index.cjs.js +526 -1746
  71. package/core/index.d.ts +486 -9
  72. package/core/index.d.ts.map +1 -1
  73. package/core/index.esm.js +515 -1732
  74. package/core/path/index.cjs.js +8 -234
  75. package/core/path/index.d.ts +327 -5
  76. package/core/path/index.d.ts.map +1 -1
  77. package/core/path/index.esm.js +8 -235
  78. package/core/platform/index.cjs.js +5 -216
  79. package/core/platform/index.d.ts +185 -3
  80. package/core/platform/index.d.ts.map +1 -1
  81. package/core/platform/index.esm.js +3 -212
  82. package/heuristics/dependencies/index.cjs.js +105 -493
  83. package/heuristics/dependencies/index.d.ts +99 -2
  84. package/heuristics/dependencies/index.d.ts.map +1 -1
  85. package/heuristics/dependencies/index.esm.js +81 -469
  86. package/heuristics/entry-points/index.cjs.js +93 -796
  87. package/heuristics/entry-points/index.d.ts +123 -2
  88. package/heuristics/entry-points/index.d.ts.map +1 -1
  89. package/heuristics/entry-points/index.esm.js +74 -777
  90. package/heuristics/framework/index.cjs.js +1483 -1411
  91. package/heuristics/framework/index.d.ts +104 -2
  92. package/heuristics/framework/index.d.ts.map +1 -1
  93. package/heuristics/framework/index.esm.js +1419 -1347
  94. package/heuristics/index.cjs.js +3220 -3306
  95. package/heuristics/index.d.ts +4 -5
  96. package/heuristics/index.d.ts.map +1 -1
  97. package/heuristics/index.esm.js +3244 -3330
  98. package/heuristics/project-type/index.cjs.js +1489 -1438
  99. package/heuristics/project-type/index.d.ts +64 -2
  100. package/heuristics/project-type/index.d.ts.map +1 -1
  101. package/heuristics/project-type/index.esm.js +1419 -1368
  102. package/index.cjs.js +3058 -3532
  103. package/index.d.ts +44 -10
  104. package/index.d.ts.map +1 -1
  105. package/index.esm.js +2914 -3376
  106. package/models/index.cjs.js +0 -1
  107. package/models/index.d.ts +20 -14
  108. package/models/index.d.ts.map +1 -1
  109. package/models/index.esm.js +0 -1
  110. package/nx/index.cjs.js +166 -579
  111. package/nx/index.d.ts +279 -4
  112. package/nx/index.d.ts.map +1 -1
  113. package/nx/index.esm.js +148 -556
  114. package/package.json +13 -12
  115. package/project/config/index.cjs.js +127 -1063
  116. package/project/config/index.d.ts +202 -4
  117. package/project/config/index.d.ts.map +1 -1
  118. package/project/config/index.esm.js +110 -1044
  119. package/project/index.cjs.js +328 -1101
  120. package/project/index.d.ts +4 -5
  121. package/project/index.d.ts.map +1 -1
  122. package/project/index.esm.js +307 -1077
  123. package/project/package/index.cjs.js +196 -473
  124. package/project/package/index.d.ts +280 -3
  125. package/project/package/index.d.ts.map +1 -1
  126. package/project/package/index.esm.js +183 -459
  127. package/project/root/index.cjs.js +109 -417
  128. package/project/root/index.d.ts +83 -2
  129. package/project/root/index.d.ts.map +1 -1
  130. package/project/root/index.esm.js +98 -406
  131. package/project/traversal/index.cjs.js +96 -622
  132. package/project/traversal/index.d.ts +165 -3
  133. package/project/traversal/index.d.ts.map +1 -1
  134. package/project/traversal/index.esm.js +82 -608
  135. package/tech/backend/index.cjs.js +223 -508
  136. package/tech/backend/index.d.ts +205 -8
  137. package/tech/backend/index.d.ts.map +1 -1
  138. package/tech/backend/index.esm.js +202 -487
  139. package/tech/build/index.cjs.js +350 -636
  140. package/tech/build/index.d.ts +276 -10
  141. package/tech/build/index.d.ts.map +1 -1
  142. package/tech/build/index.esm.js +328 -614
  143. package/tech/frontend/index.cjs.js +507 -685
  144. package/tech/frontend/index.d.ts +379 -15
  145. package/tech/frontend/index.d.ts.map +1 -1
  146. package/tech/frontend/index.esm.js +483 -661
  147. package/tech/index.cjs.js +1581 -1420
  148. package/tech/index.d.ts +55 -32
  149. package/tech/index.d.ts.map +1 -1
  150. package/tech/index.esm.js +1515 -1354
  151. package/tech/legacy/index.cjs.js +99 -449
  152. package/tech/legacy/index.d.ts +125 -7
  153. package/tech/legacy/index.d.ts.map +1 -1
  154. package/tech/legacy/index.esm.js +81 -431
  155. package/tech/linting/index.cjs.js +138 -523
  156. package/tech/linting/index.d.ts +129 -7
  157. package/tech/linting/index.d.ts.map +1 -1
  158. package/tech/linting/index.esm.js +118 -503
  159. package/tech/monorepo/index.cjs.js +246 -573
  160. package/tech/monorepo/index.d.ts +241 -10
  161. package/tech/monorepo/index.d.ts.map +1 -1
  162. package/tech/monorepo/index.esm.js +226 -553
  163. package/tech/testing/index.cjs.js +216 -571
  164. package/tech/testing/index.d.ts +176 -8
  165. package/tech/testing/index.d.ts.map +1 -1
  166. package/tech/testing/index.esm.js +198 -553
  167. package/tech/types/index.cjs.js +123 -506
  168. package/tech/types/index.d.ts +120 -2
  169. package/tech/types/index.d.ts.map +1 -1
  170. package/tech/types/index.esm.js +101 -484
  171. package/vfs/index.cjs.js +647 -1142
  172. package/vfs/index.d.ts +360 -6
  173. package/vfs/index.d.ts.map +1 -1
  174. package/vfs/index.esm.js +672 -1167
  175. package/ARCHITECTURE.md +0 -370
  176. package/analyze.d.ts +0 -33
  177. package/analyze.d.ts.map +0 -1
  178. package/cli/commands/analyze.d.ts +0 -28
  179. package/cli/commands/analyze.d.ts.map +0 -1
  180. package/cli/commands/config.d.ts +0 -27
  181. package/cli/commands/config.d.ts.map +0 -1
  182. package/cli/commands/deps.d.ts +0 -24
  183. package/cli/commands/deps.d.ts.map +0 -1
  184. package/cli/commands/tree.d.ts +0 -36
  185. package/cli/commands/tree.d.ts.map +0 -1
  186. package/cli/index.cjs.js.map +0 -1
  187. package/cli/index.esm.js.map +0 -1
  188. package/cli/run.d.ts +0 -25
  189. package/cli/run.d.ts.map +0 -1
  190. package/cli/types.d.ts +0 -55
  191. package/cli/types.d.ts.map +0 -1
  192. package/core/cache.d.ts +0 -158
  193. package/core/cache.d.ts.map +0 -1
  194. package/core/encoding/convert.d.ts +0 -32
  195. package/core/encoding/convert.d.ts.map +0 -1
  196. package/core/encoding/detect.d.ts +0 -91
  197. package/core/encoding/detect.d.ts.map +0 -1
  198. package/core/encoding/index.cjs.js.map +0 -1
  199. package/core/encoding/index.esm.js.map +0 -1
  200. package/core/errors/structured-errors.d.ts +0 -66
  201. package/core/errors/structured-errors.d.ts.map +0 -1
  202. package/core/fs/directory.d.ts +0 -91
  203. package/core/fs/directory.d.ts.map +0 -1
  204. package/core/fs/index.cjs.js.map +0 -1
  205. package/core/fs/index.esm.js.map +0 -1
  206. package/core/fs/read.d.ts +0 -94
  207. package/core/fs/read.d.ts.map +0 -1
  208. package/core/fs/stat.d.ts +0 -58
  209. package/core/fs/stat.d.ts.map +0 -1
  210. package/core/fs/traversal.d.ts +0 -26
  211. package/core/fs/traversal.d.ts.map +0 -1
  212. package/core/fs/write.d.ts +0 -75
  213. package/core/fs/write.d.ts.map +0 -1
  214. package/core/index.cjs.js.map +0 -1
  215. package/core/index.esm.js.map +0 -1
  216. package/core/logger.d.ts +0 -111
  217. package/core/logger.d.ts.map +0 -1
  218. package/core/path/index.cjs.js.map +0 -1
  219. package/core/path/index.esm.js.map +0 -1
  220. package/core/path/join.d.ts +0 -17
  221. package/core/path/join.d.ts.map +0 -1
  222. package/core/path/normalize.d.ts +0 -37
  223. package/core/path/normalize.d.ts.map +0 -1
  224. package/core/path/resolve.d.ts +0 -52
  225. package/core/path/resolve.d.ts.map +0 -1
  226. package/core/path/segments.d.ts +0 -59
  227. package/core/path/segments.d.ts.map +0 -1
  228. package/core/patterns/glob.d.ts +0 -42
  229. package/core/patterns/glob.d.ts.map +0 -1
  230. package/core/platform/detect.d.ts +0 -66
  231. package/core/platform/detect.d.ts.map +0 -1
  232. package/core/platform/index.cjs.js.map +0 -1
  233. package/core/platform/index.esm.js.map +0 -1
  234. package/core/platform/line-endings.d.ts +0 -48
  235. package/core/platform/line-endings.d.ts.map +0 -1
  236. package/heuristics/dependencies/analyze.d.ts +0 -77
  237. package/heuristics/dependencies/analyze.d.ts.map +0 -1
  238. package/heuristics/dependencies/index.cjs.js.map +0 -1
  239. package/heuristics/dependencies/index.esm.js.map +0 -1
  240. package/heuristics/entry-points/discover.d.ts +0 -113
  241. package/heuristics/entry-points/discover.d.ts.map +0 -1
  242. package/heuristics/entry-points/index.cjs.js.map +0 -1
  243. package/heuristics/entry-points/index.esm.js.map +0 -1
  244. package/heuristics/framework/identify.d.ts +0 -84
  245. package/heuristics/framework/identify.d.ts.map +0 -1
  246. package/heuristics/framework/index.cjs.js.map +0 -1
  247. package/heuristics/framework/index.esm.js.map +0 -1
  248. package/heuristics/index.cjs.js.map +0 -1
  249. package/heuristics/index.esm.js.map +0 -1
  250. package/heuristics/project-type/detect.d.ts +0 -61
  251. package/heuristics/project-type/detect.d.ts.map +0 -1
  252. package/heuristics/project-type/index.cjs.js.map +0 -1
  253. package/heuristics/project-type/index.esm.js.map +0 -1
  254. package/index.cjs.js.map +0 -1
  255. package/index.esm.js.map +0 -1
  256. package/models/index.cjs.js.map +0 -1
  257. package/models/index.esm.js.map +0 -1
  258. package/nx/detect.d.ts +0 -105
  259. package/nx/detect.d.ts.map +0 -1
  260. package/nx/devkit-loader.d.ts +0 -62
  261. package/nx/devkit-loader.d.ts.map +0 -1
  262. package/nx/index.cjs.js.map +0 -1
  263. package/nx/index.esm.js.map +0 -1
  264. package/nx/project-config.d.ts +0 -111
  265. package/nx/project-config.d.ts.map +0 -1
  266. package/project/config/detect.d.ts +0 -77
  267. package/project/config/detect.d.ts.map +0 -1
  268. package/project/config/index.cjs.js.map +0 -1
  269. package/project/config/index.esm.js.map +0 -1
  270. package/project/config/parse.d.ts +0 -53
  271. package/project/config/parse.d.ts.map +0 -1
  272. package/project/config/patterns.d.ts +0 -31
  273. package/project/config/patterns.d.ts.map +0 -1
  274. package/project/index.cjs.js.map +0 -1
  275. package/project/index.esm.js.map +0 -1
  276. package/project/package/dependencies.d.ts +0 -101
  277. package/project/package/dependencies.d.ts.map +0 -1
  278. package/project/package/index.cjs.js.map +0 -1
  279. package/project/package/index.esm.js.map +0 -1
  280. package/project/package/read.d.ts +0 -67
  281. package/project/package/read.d.ts.map +0 -1
  282. package/project/root/detect.d.ts +0 -65
  283. package/project/root/detect.d.ts.map +0 -1
  284. package/project/root/index.cjs.js.map +0 -1
  285. package/project/root/index.esm.js.map +0 -1
  286. package/project/traversal/index.cjs.js.map +0 -1
  287. package/project/traversal/index.esm.js.map +0 -1
  288. package/project/traversal/search.d.ts +0 -59
  289. package/project/traversal/search.d.ts.map +0 -1
  290. package/project/traversal/walk.d.ts +0 -63
  291. package/project/traversal/walk.d.ts.map +0 -1
  292. package/tech/backend/detect-all.d.ts +0 -13
  293. package/tech/backend/detect-all.d.ts.map +0 -1
  294. package/tech/backend/express.d.ts +0 -11
  295. package/tech/backend/express.d.ts.map +0 -1
  296. package/tech/backend/fastify.d.ts +0 -11
  297. package/tech/backend/fastify.d.ts.map +0 -1
  298. package/tech/backend/hono.d.ts +0 -11
  299. package/tech/backend/hono.d.ts.map +0 -1
  300. package/tech/backend/index.cjs.js.map +0 -1
  301. package/tech/backend/index.esm.js.map +0 -1
  302. package/tech/backend/koa.d.ts +0 -11
  303. package/tech/backend/koa.d.ts.map +0 -1
  304. package/tech/backend/nestjs.d.ts +0 -11
  305. package/tech/backend/nestjs.d.ts.map +0 -1
  306. package/tech/backend/types.d.ts +0 -31
  307. package/tech/backend/types.d.ts.map +0 -1
  308. package/tech/build/babel.d.ts +0 -13
  309. package/tech/build/babel.d.ts.map +0 -1
  310. package/tech/build/detect-all.d.ts +0 -13
  311. package/tech/build/detect-all.d.ts.map +0 -1
  312. package/tech/build/esbuild.d.ts +0 -11
  313. package/tech/build/esbuild.d.ts.map +0 -1
  314. package/tech/build/index.cjs.js.map +0 -1
  315. package/tech/build/index.esm.js.map +0 -1
  316. package/tech/build/parcel.d.ts +0 -13
  317. package/tech/build/parcel.d.ts.map +0 -1
  318. package/tech/build/rollup.d.ts +0 -13
  319. package/tech/build/rollup.d.ts.map +0 -1
  320. package/tech/build/swc.d.ts +0 -13
  321. package/tech/build/swc.d.ts.map +0 -1
  322. package/tech/build/types.d.ts +0 -31
  323. package/tech/build/types.d.ts.map +0 -1
  324. package/tech/build/vite.d.ts +0 -13
  325. package/tech/build/vite.d.ts.map +0 -1
  326. package/tech/build/webpack.d.ts +0 -13
  327. package/tech/build/webpack.d.ts.map +0 -1
  328. package/tech/frontend/angular.d.ts +0 -11
  329. package/tech/frontend/angular.d.ts.map +0 -1
  330. package/tech/frontend/astro.d.ts +0 -11
  331. package/tech/frontend/astro.d.ts.map +0 -1
  332. package/tech/frontend/detect-all.d.ts +0 -13
  333. package/tech/frontend/detect-all.d.ts.map +0 -1
  334. package/tech/frontend/gatsby.d.ts +0 -11
  335. package/tech/frontend/gatsby.d.ts.map +0 -1
  336. package/tech/frontend/index.cjs.js.map +0 -1
  337. package/tech/frontend/index.esm.js.map +0 -1
  338. package/tech/frontend/nextjs.d.ts +0 -11
  339. package/tech/frontend/nextjs.d.ts.map +0 -1
  340. package/tech/frontend/nuxt.d.ts +0 -11
  341. package/tech/frontend/nuxt.d.ts.map +0 -1
  342. package/tech/frontend/qwik.d.ts +0 -11
  343. package/tech/frontend/qwik.d.ts.map +0 -1
  344. package/tech/frontend/react.d.ts +0 -11
  345. package/tech/frontend/react.d.ts.map +0 -1
  346. package/tech/frontend/remix.d.ts +0 -11
  347. package/tech/frontend/remix.d.ts.map +0 -1
  348. package/tech/frontend/solid.d.ts +0 -11
  349. package/tech/frontend/solid.d.ts.map +0 -1
  350. package/tech/frontend/svelte.d.ts +0 -11
  351. package/tech/frontend/svelte.d.ts.map +0 -1
  352. package/tech/frontend/sveltekit.d.ts +0 -11
  353. package/tech/frontend/sveltekit.d.ts.map +0 -1
  354. package/tech/frontend/types.d.ts +0 -35
  355. package/tech/frontend/types.d.ts.map +0 -1
  356. package/tech/frontend/vue.d.ts +0 -11
  357. package/tech/frontend/vue.d.ts.map +0 -1
  358. package/tech/index.cjs.js.map +0 -1
  359. package/tech/index.esm.js.map +0 -1
  360. package/tech/legacy/angularjs.d.ts +0 -12
  361. package/tech/legacy/angularjs.d.ts.map +0 -1
  362. package/tech/legacy/backbone.d.ts +0 -11
  363. package/tech/legacy/backbone.d.ts.map +0 -1
  364. package/tech/legacy/detect-all.d.ts +0 -13
  365. package/tech/legacy/detect-all.d.ts.map +0 -1
  366. package/tech/legacy/ember.d.ts +0 -11
  367. package/tech/legacy/ember.d.ts.map +0 -1
  368. package/tech/legacy/index.cjs.js.map +0 -1
  369. package/tech/legacy/index.esm.js.map +0 -1
  370. package/tech/legacy/jquery.d.ts +0 -11
  371. package/tech/legacy/jquery.d.ts.map +0 -1
  372. package/tech/legacy/types.d.ts +0 -33
  373. package/tech/legacy/types.d.ts.map +0 -1
  374. package/tech/linting/biome.d.ts +0 -11
  375. package/tech/linting/biome.d.ts.map +0 -1
  376. package/tech/linting/detect-all.d.ts +0 -13
  377. package/tech/linting/detect-all.d.ts.map +0 -1
  378. package/tech/linting/eslint.d.ts +0 -13
  379. package/tech/linting/eslint.d.ts.map +0 -1
  380. package/tech/linting/index.cjs.js.map +0 -1
  381. package/tech/linting/index.esm.js.map +0 -1
  382. package/tech/linting/prettier.d.ts +0 -13
  383. package/tech/linting/prettier.d.ts.map +0 -1
  384. package/tech/linting/stylelint.d.ts +0 -13
  385. package/tech/linting/stylelint.d.ts.map +0 -1
  386. package/tech/linting/types.d.ts +0 -31
  387. package/tech/linting/types.d.ts.map +0 -1
  388. package/tech/monorepo/detect-all.d.ts +0 -13
  389. package/tech/monorepo/detect-all.d.ts.map +0 -1
  390. package/tech/monorepo/index.cjs.js.map +0 -1
  391. package/tech/monorepo/index.esm.js.map +0 -1
  392. package/tech/monorepo/lerna.d.ts +0 -11
  393. package/tech/monorepo/lerna.d.ts.map +0 -1
  394. package/tech/monorepo/npm-workspaces.d.ts +0 -11
  395. package/tech/monorepo/npm-workspaces.d.ts.map +0 -1
  396. package/tech/monorepo/nx.d.ts +0 -11
  397. package/tech/monorepo/nx.d.ts.map +0 -1
  398. package/tech/monorepo/pnpm-workspaces.d.ts +0 -9
  399. package/tech/monorepo/pnpm-workspaces.d.ts.map +0 -1
  400. package/tech/monorepo/rush.d.ts +0 -11
  401. package/tech/monorepo/rush.d.ts.map +0 -1
  402. package/tech/monorepo/turborepo.d.ts +0 -11
  403. package/tech/monorepo/turborepo.d.ts.map +0 -1
  404. package/tech/monorepo/types.d.ts +0 -39
  405. package/tech/monorepo/types.d.ts.map +0 -1
  406. package/tech/monorepo/yarn-workspaces.d.ts +0 -11
  407. package/tech/monorepo/yarn-workspaces.d.ts.map +0 -1
  408. package/tech/shared-utils/detector-helpers.d.ts +0 -52
  409. package/tech/shared-utils/detector-helpers.d.ts.map +0 -1
  410. package/tech/shared-utils/types.d.ts +0 -41
  411. package/tech/shared-utils/types.d.ts.map +0 -1
  412. package/tech/testing/cypress.d.ts +0 -13
  413. package/tech/testing/cypress.d.ts.map +0 -1
  414. package/tech/testing/detect-all.d.ts +0 -13
  415. package/tech/testing/detect-all.d.ts.map +0 -1
  416. package/tech/testing/index.cjs.js.map +0 -1
  417. package/tech/testing/index.esm.js.map +0 -1
  418. package/tech/testing/jest.d.ts +0 -13
  419. package/tech/testing/jest.d.ts.map +0 -1
  420. package/tech/testing/mocha.d.ts +0 -13
  421. package/tech/testing/mocha.d.ts.map +0 -1
  422. package/tech/testing/playwright.d.ts +0 -13
  423. package/tech/testing/playwright.d.ts.map +0 -1
  424. package/tech/testing/types.d.ts +0 -35
  425. package/tech/testing/types.d.ts.map +0 -1
  426. package/tech/testing/vitest.d.ts +0 -13
  427. package/tech/testing/vitest.d.ts.map +0 -1
  428. package/tech/types/detectors.d.ts +0 -67
  429. package/tech/types/detectors.d.ts.map +0 -1
  430. package/tech/types/index.cjs.js.map +0 -1
  431. package/tech/types/index.esm.js.map +0 -1
  432. package/vfs/commit.d.ts +0 -32
  433. package/vfs/commit.d.ts.map +0 -1
  434. package/vfs/diff.d.ts +0 -73
  435. package/vfs/diff.d.ts.map +0 -1
  436. package/vfs/factory.d.ts +0 -37
  437. package/vfs/factory.d.ts.map +0 -1
  438. package/vfs/fs-tree.d.ts +0 -13
  439. package/vfs/fs-tree.d.ts.map +0 -1
  440. package/vfs/index.cjs.js.map +0 -1
  441. package/vfs/index.esm.js.map +0 -1
  442. package/vfs/types.d.ts +0 -179
  443. package/vfs/types.d.ts.map +0 -1
@@ -1,555 +1,28 @@
1
1
  'use strict';
2
2
 
3
- var node_path = require('node:path');
4
- var node_fs = require('node:fs');
5
-
6
- /**
7
- * Safe copies of Map built-in via factory function.
8
- *
9
- * Since constructors cannot be safely captured via Object.assign, this module
10
- * provides a factory function that uses Reflect.construct internally.
11
- *
12
- * These references are captured at module initialization time to protect against
13
- * prototype pollution attacks. Import only what you need for tree-shaking.
14
- *
15
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/map
16
- */
17
- const _Map = globalThis.Map;
18
- const _Reflect$2 = globalThis.Reflect;
19
- /**
20
- * (Safe copy) Creates a new Map using the captured Map constructor.
21
- * Use this instead of `new Map()`.
22
- *
23
- * @param iterable - Optional iterable of key-value pairs.
24
- * @returns A new Map instance.
25
- */
26
- const createMap = (iterable) => _Reflect$2.construct(_Map, iterable ? [iterable] : []);
27
-
28
- /**
29
- * Safe copies of Object built-in methods.
30
- *
31
- * These references are captured at module initialization time to protect against
32
- * prototype pollution attacks. Import only what you need for tree-shaking.
33
- *
34
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/object
35
- */
36
- const _Object = globalThis.Object;
37
- /**
38
- * (Safe copy) Prevents modification of existing property attributes and values,
39
- * and prevents the addition of new properties.
40
- */
41
- const freeze = _Object.freeze;
42
- /**
43
- * (Safe copy) Returns the names of the enumerable string properties and methods of an object.
44
- */
45
- const keys = _Object.keys;
46
- /**
47
- * (Safe copy) Returns an array of key/values of the enumerable own properties of an object.
48
- */
49
- const entries = _Object.entries;
50
- /**
51
- * (Safe copy) Returns an array of values of the enumerable own properties of an object.
52
- */
53
- const values = _Object.values;
54
- /**
55
- * (Safe copy) Adds one or more properties to an object, and/or modifies attributes of existing properties.
56
- */
57
- const defineProperties = _Object.defineProperties;
58
-
59
- /**
60
- * Safe copies of Set built-in via factory function.
61
- *
62
- * Since constructors cannot be safely captured via Object.assign, this module
63
- * provides a factory function that uses Reflect.construct internally.
64
- *
65
- * These references are captured at module initialization time to protect against
66
- * prototype pollution attacks. Import only what you need for tree-shaking.
67
- *
68
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/set
69
- */
70
- const _Set = globalThis.Set;
71
- const _Reflect$1 = globalThis.Reflect;
72
- /**
73
- * (Safe copy) Creates a new Set using the captured Set constructor.
74
- * Use this instead of `new Set()`.
75
- *
76
- * @param iterable - Optional iterable of values.
77
- * @returns A new Set instance.
78
- */
79
- const createSet = (iterable) => _Reflect$1.construct(_Set, iterable ? [iterable] : []);
80
-
81
- /**
82
- * Global registry of all caches for bulk operations.
83
- */
84
- const cacheRegistry = createSet();
85
- /**
86
- * Create a cache with optional TTL and size limits.
87
- *
88
- * The cache provides a simple key-value store with:
89
- * - Optional TTL (time-to-live) for automatic expiration
90
- * - Optional maxSize for limiting cache size with FIFO eviction
91
- * - Lazy expiration (entries are checked on access)
92
- *
93
- * @param options - Cache configuration options
94
- * @returns Cache instance
95
- *
96
- * @example
97
- * ```typescript
98
- * // Basic cache
99
- * const cache = createCache<string, number>()
100
- * cache.set('answer', 42)
101
- * cache.get('answer') // 42
102
- *
103
- * // Cache with TTL (expires after 60 seconds)
104
- * const ttlCache = createCache<string, object>({ ttl: 60000 })
105
- *
106
- * // Cache with max size (evicts oldest when full)
107
- * const lruCache = createCache<string, object>({ maxSize: 100 })
108
- *
109
- * // Combined options
110
- * const configCache = createCache<string, object>({
111
- * ttl: 30000,
112
- * maxSize: 50
113
- * })
114
- * ```
115
- */
116
- function createCache(options) {
117
- const { ttl, maxSize } = options ?? {};
118
- const store = createMap();
119
- const insertionOrder = [];
120
- /**
121
- * Check if an entry is expired.
122
- *
123
- * @param entry - Cache entry to check
124
- * @returns True if entry is expired
125
- */
126
- function isExpired(entry) {
127
- if (ttl === undefined)
128
- return false;
129
- // eslint-disable-next-line workspace/no-unsafe-builtin-methods -- Date.now() is needed for Jest fake timers compatibility
130
- return Date.now() - entry.timestamp > ttl;
131
- }
132
- /**
133
- * Evict oldest entries to make room for new ones.
134
- */
135
- function evictIfNeeded() {
136
- if (maxSize === undefined)
137
- return;
138
- while (store.size >= maxSize && insertionOrder.length > 0) {
139
- const oldestKey = insertionOrder.shift();
140
- if (oldestKey !== undefined) {
141
- store.delete(oldestKey);
142
- }
143
- }
144
- }
145
- /**
146
- * Remove key from insertion order tracking.
147
- *
148
- * @param key - Key to remove from order tracking
149
- */
150
- function removeFromOrder(key) {
151
- const index = insertionOrder.indexOf(key);
152
- if (index !== -1) {
153
- insertionOrder.splice(index, 1);
154
- }
155
- }
156
- const cache = {
157
- get(key) {
158
- const entry = store.get(key);
159
- if (!entry)
160
- return undefined;
161
- if (isExpired(entry)) {
162
- store.delete(key);
163
- removeFromOrder(key);
164
- return undefined;
165
- }
166
- return entry.value;
167
- },
168
- set(key, value) {
169
- if (store.has(key)) {
170
- removeFromOrder(key);
171
- }
172
- else {
173
- evictIfNeeded();
174
- }
175
- // eslint-disable-next-line workspace/no-unsafe-builtin-methods -- Date.now() is needed for Jest fake timers compatibility
176
- store.set(key, { value, timestamp: Date.now() });
177
- insertionOrder.push(key);
178
- },
179
- has(key) {
180
- const entry = store.get(key);
181
- if (!entry)
182
- return false;
183
- if (isExpired(entry)) {
184
- store.delete(key);
185
- removeFromOrder(key);
186
- return false;
187
- }
188
- return true;
189
- },
190
- delete(key) {
191
- removeFromOrder(key);
192
- return store.delete(key);
193
- },
194
- clear() {
195
- store.clear();
196
- insertionOrder.length = 0;
197
- },
198
- size() {
199
- return store.size;
200
- },
201
- keys() {
202
- return [...insertionOrder];
203
- },
204
- };
205
- cacheRegistry.add(cache);
206
- return freeze(cache);
207
- }
208
-
209
- /**
210
- * Safe copies of Array built-in static methods.
211
- *
212
- * These references are captured at module initialization time to protect against
213
- * prototype pollution attacks. Import only what you need for tree-shaking.
214
- *
215
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/array
216
- */
217
- const _Array = globalThis.Array;
218
- /**
219
- * (Safe copy) Determines whether the passed value is an Array.
220
- */
221
- const isArray = _Array.isArray;
222
-
223
- /**
224
- * Safe copies of Console built-in methods.
225
- *
226
- * These references are captured at module initialization time to protect against
227
- * prototype pollution attacks. Import only what you need for tree-shaking.
228
- *
229
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/console
230
- */
231
- const _console = globalThis.console;
232
- /**
233
- * (Safe copy) Outputs a message to the console.
234
- */
235
- const log = _console.log.bind(_console);
236
- /**
237
- * (Safe copy) Outputs a warning message to the console.
238
- */
239
- const warn = _console.warn.bind(_console);
240
- /**
241
- * (Safe copy) Outputs an error message to the console.
242
- */
243
- const error = _console.error.bind(_console);
244
- /**
245
- * (Safe copy) Outputs an informational message to the console.
246
- */
247
- const info = _console.info.bind(_console);
248
- /**
249
- * (Safe copy) Outputs a debug message to the console.
250
- */
251
- const debug = _console.debug.bind(_console);
252
- /**
253
- * (Safe copy) Outputs a stack trace to the console.
254
- */
255
- _console.trace.bind(_console);
256
- /**
257
- * (Safe copy) Displays an interactive listing of the properties of a specified object.
258
- */
259
- _console.dir.bind(_console);
260
- /**
261
- * (Safe copy) Displays tabular data as a table.
262
- */
263
- _console.table.bind(_console);
264
- /**
265
- * (Safe copy) Writes an error message to the console if the assertion is false.
266
- */
267
- _console.assert.bind(_console);
268
- /**
269
- * (Safe copy) Clears the console.
270
- */
271
- _console.clear.bind(_console);
272
- /**
273
- * (Safe copy) Logs the number of times that this particular call to count() has been called.
274
- */
275
- _console.count.bind(_console);
276
- /**
277
- * (Safe copy) Resets the counter used with console.count().
278
- */
279
- _console.countReset.bind(_console);
280
- /**
281
- * (Safe copy) Creates a new inline group in the console.
282
- */
283
- _console.group.bind(_console);
284
- /**
285
- * (Safe copy) Creates a new inline group in the console that is initially collapsed.
286
- */
287
- _console.groupCollapsed.bind(_console);
288
- /**
289
- * (Safe copy) Exits the current inline group.
290
- */
291
- _console.groupEnd.bind(_console);
292
- /**
293
- * (Safe copy) Starts a timer with a name specified as an input parameter.
294
- */
295
- _console.time.bind(_console);
296
- /**
297
- * (Safe copy) Stops a timer that was previously started.
298
- */
299
- _console.timeEnd.bind(_console);
300
- /**
301
- * (Safe copy) Logs the current value of a timer that was previously started.
302
- */
303
- _console.timeLog.bind(_console);
304
-
305
- /**
306
- * Safe copies of JSON built-in methods.
307
- *
308
- * These references are captured at module initialization time to protect against
309
- * prototype pollution attacks. Import only what you need for tree-shaking.
310
- *
311
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/json
312
- */
313
- const _JSON = globalThis.JSON;
314
- /**
315
- * (Safe copy) Converts a JavaScript Object Notation (JSON) string into an object.
316
- */
317
- const parse = _JSON.parse;
318
- /**
319
- * (Safe copy) Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
320
- */
321
- const stringify = _JSON.stringify;
322
-
323
- const registeredClasses = [];
324
-
325
- /**
326
- * Returns the data type of the target.
327
- * Uses native `typeof` operator, however, makes distinction between `null`, `array`, and `object`.
328
- * Also, when classes are registered via `registerClass`, it checks if objects are instance of any known registered class.
329
- *
330
- * @param target - The target to get the data type of.
331
- * @returns The data type of the target.
332
- */
333
- const getType = (target) => {
334
- if (target === null)
335
- return 'null';
336
- const nativeDataType = typeof target;
337
- if (nativeDataType === 'object') {
338
- if (isArray(target))
339
- return 'array';
340
- for (const registeredClass of registeredClasses) {
341
- if (target instanceof registeredClass)
342
- return registeredClass.name;
343
- }
344
- }
345
- return nativeDataType;
346
- };
347
-
348
- /**
349
- * Safe copies of Error built-ins via factory functions.
350
- *
351
- * Since constructors cannot be safely captured via Object.assign, this module
352
- * provides factory functions that use Reflect.construct internally.
353
- *
354
- * These references are captured at module initialization time to protect against
355
- * prototype pollution attacks. Import only what you need for tree-shaking.
356
- *
357
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/error
358
- */
359
- const _Error = globalThis.Error;
360
- const _Reflect = globalThis.Reflect;
361
- /**
362
- * (Safe copy) Creates a new Error using the captured Error constructor.
363
- * Use this instead of `new Error()`.
364
- *
365
- * @param message - Optional error message.
366
- * @param options - Optional error options.
367
- * @returns A new Error instance.
368
- */
369
- const createError = (message, options) => _Reflect.construct(_Error, [message, options]);
370
-
371
- /**
372
- * Safe copies of Math built-in methods.
373
- *
374
- * These references are captured at module initialization time to protect against
375
- * prototype pollution attacks. Import only what you need for tree-shaking.
376
- *
377
- * @module @hyperfrontend/immutable-api-utils/built-in-copy/math
378
- */
379
- const _Math = globalThis.Math;
380
- /**
381
- * (Safe copy) Returns the smaller of zero or more numbers.
382
- */
383
- const min = _Math.min;
384
-
385
- /* eslint-disable @typescript-eslint/no-explicit-any */
386
- /**
387
- * Creates a wrapper function that only executes the wrapped function if the condition function returns true.
388
- *
389
- * @param func - The function to be conditionally executed.
390
- * @param conditionFunc - A function that returns a boolean, determining if `func` should be executed.
391
- * @returns A wrapped version of `func` that executes conditionally.
392
- */
393
- function createConditionalExecutionFunction(func, conditionFunc) {
394
- return function (...args) {
395
- if (conditionFunc()) {
396
- return func(...args);
397
- }
398
- };
399
- }
400
-
401
- /* eslint-disable @typescript-eslint/no-explicit-any */
402
- /**
403
- * Creates a wrapper function that silently ignores any errors thrown by the wrapped void function.
404
- * This function is specifically for wrapping functions that do not return a value (void functions).
405
- * Exceptions are swallowed without any logging or handling.
406
- *
407
- * @param func - The void function to be wrapped.
408
- * @returns A wrapped version of the input function that ignores errors.
409
- */
410
- function createErrorIgnoringFunction(func) {
411
- return function (...args) {
412
- try {
413
- func(...args);
414
- }
415
- catch {
416
- // Deliberately swallowing/ignoring the exception
417
- }
418
- };
419
- }
420
-
421
- /* eslint-disable @typescript-eslint/no-unused-vars */
422
- /**
423
- * A no-operation function (noop) that does nothing regardless of the arguments passed.
424
- * It is designed to be as permissive as possible in its typing without using the `Function` keyword.
425
- *
426
- * @param args - Any arguments passed to the function (ignored)
427
- */
428
- const noop = (...args) => {
429
- // Intentionally does nothing
430
- };
431
-
432
- const logLevels = ['none', 'error', 'warn', 'log', 'info', 'debug'];
433
- const priority = {
434
- error: 4,
435
- warn: 3,
436
- log: 2,
437
- info: 1,
438
- debug: 0,
439
- };
440
- /**
441
- * Validates whether a given string is a valid log level.
442
- *
443
- * @param level - The log level to validate
444
- * @returns True if the level is valid, false otherwise
445
- */
446
- function isValidLogLevel(level) {
447
- return logLevels.includes(level);
448
- }
449
- /**
450
- * Creates a log level configuration manager for controlling logging behavior.
451
- * Provides methods to get, set, and evaluate log levels based on priority.
452
- *
453
- * @param level - The initial log level (defaults to 'error')
454
- * @returns A configuration object with log level management methods
455
- * @throws {Error} When the provided level is not a valid log level
456
- */
457
- function createLogLevelConfig(level = 'error') {
458
- if (!isValidLogLevel(level)) {
459
- throw createError('Cannot create log level configuration with a valid default log level');
460
- }
461
- const state = { level };
462
- const getLogLevel = () => state.level;
463
- const setLogLevel = (level) => {
464
- if (!isValidLogLevel(level)) {
465
- throw createError(`Cannot set value '${level}' level. Expected levels are ${logLevels}.`);
466
- }
467
- state.level = level;
468
- };
469
- const shouldLog = (level) => {
470
- if (state.level === 'none' || level === 'none' || !isValidLogLevel(level)) {
471
- return false;
472
- }
473
- return priority[level] >= priority[state.level];
474
- };
475
- return freeze({
476
- getLogLevel,
477
- setLogLevel,
478
- shouldLog,
479
- });
480
- }
481
-
482
- /**
483
- * Creates a logger instance with configurable log level filtering.
484
- * Each log function is wrapped to respect the current log level setting.
485
- *
486
- * @param error - Function to handle error-level logs (required)
487
- * @param warn - Function to handle warning-level logs (optional, defaults to noop)
488
- * @param log - Function to handle standard logs (optional, defaults to noop)
489
- * @param info - Function to handle info-level logs (optional, defaults to noop)
490
- * @param debug - Function to handle debug-level logs (optional, defaults to noop)
491
- * @returns A frozen logger object with log methods and level control
492
- * @throws {ErrorLevelFn} When any provided log function is invalid
493
- */
494
- function createLogger(error, warn = noop, log = noop, info = noop, debug = noop) {
495
- if (notValidLogFn(error)) {
496
- throw createError(notFnMsg('error'));
497
- }
498
- if (notValidLogFn(warn)) {
499
- throw createError(notFnMsg('warn'));
500
- }
501
- if (notValidLogFn(log)) {
502
- throw createError(notFnMsg('log'));
503
- }
504
- if (notValidLogFn(info)) {
505
- throw createError(notFnMsg('info'));
506
- }
507
- if (notValidLogFn(debug)) {
508
- throw createError(notFnMsg('debug'));
509
- }
510
- const { setLogLevel, getLogLevel, shouldLog } = createLogLevelConfig();
511
- const wrapLogFn = (fn, level) => {
512
- if (fn === noop)
513
- return fn;
514
- const condition = () => shouldLog(level);
515
- return createConditionalExecutionFunction(createErrorIgnoringFunction(fn), condition);
516
- };
517
- return freeze({
518
- error: wrapLogFn(error, 'error'),
519
- warn: wrapLogFn(warn, 'warn'),
520
- log: wrapLogFn(log, 'log'),
521
- info: wrapLogFn(info, 'info'),
522
- debug: wrapLogFn(debug, 'debug'),
523
- setLogLevel,
524
- getLogLevel,
525
- });
526
- }
527
- /**
528
- * Validates whether a given value is a valid log function.
529
- *
530
- * @param fn - The value to validate
531
- * @returns True if the value is not a function (invalid), false if it is valid
532
- */
533
- function notValidLogFn(fn) {
534
- return getType(fn) !== 'function' && fn !== noop;
535
- }
536
- /**
537
- * Generates an error message for invalid log function parameters.
538
- *
539
- * @param label - The name of the log function that failed validation
540
- * @returns A formatted error message string
541
- */
542
- function notFnMsg(label) {
543
- return `Cannot create a logger when ${label} is not a function`;
544
- }
545
-
546
- createLogger(error, warn, log, info, debug);
3
+ const index_cjs_js$1 = require('../../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/map/index.cjs.js');
4
+ const index_cjs_js$2 = require('../../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/object/index.cjs.js');
5
+ const index_cjs_js = require('../../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/set/index.cjs.js');
6
+ const index_cjs_js$5 = require('../../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/array/index.cjs.js');
7
+ const index_cjs_js$4 = require('../../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/console/index.cjs.js');
8
+ const index_cjs_js$6 = require('../../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/json/index.cjs.js');
9
+ const index_cjs_js$3 = require('../../_dependencies/@hyperfrontend/logging/index.cjs.js');
10
+ const node_path = require('node:path');
11
+ const index_cjs_js$7 = require('../../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/error/index.cjs.js');
12
+ const node_fs = require('node:fs');
13
+ const index_cjs_js$8 = require('../../_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/math/index.cjs.js');
14
+ const { isSafePath } = require('../../_shared/core/fs/guard/index.cjs.js');
15
+ const { isDirectory, exists } = require('../../_shared/core/fs/stat/index.cjs.js');
16
+ const { join } = require('../../_shared/core/path/join/index.cjs.js');
17
+ const { createCache } = require('../../_shared/core/cache/index.cjs.js');
18
+ const { collectAllDependencies, parseVersionString, locateConfigFile, filterScriptsByCommand } = require('../../_shared/tech/shared-utils/detector-helpers/index.cjs.js');
19
+ const { pnpmWorkspacesDetector } = require('../../_shared/tech/monorepo/pnpm-workspaces/index.cjs.js');
547
20
 
548
21
  /**
549
22
  * Global log level registry.
550
23
  * Tracks all created scoped loggers to allow global log level changes.
551
24
  */
552
- const loggerRegistry = createSet();
25
+ const loggerRegistry = index_cjs_js.createSet();
553
26
  /** Redacted placeholder for sensitive values */
554
27
  const REDACTED = '[REDACTED]';
555
28
  /**
@@ -583,17 +56,24 @@ function isSensitiveKey(key) {
583
56
  *
584
57
  * @param obj - Object to sanitize
585
58
  * @returns New object with sensitive values redacted
59
+ *
60
+ * @example Sanitizing sensitive data
61
+ * ```typescript
62
+ * const config = { apiKey: 'secret123', endpoint: 'https://api.example.com' }
63
+ * const safe = sanitize(config)
64
+ * // => { apiKey: '[REDACTED]', endpoint: 'https://api.example.com' }
65
+ * ```
586
66
  */
587
67
  function sanitize(obj) {
588
68
  if (obj === null || obj === undefined) {
589
69
  return obj;
590
70
  }
591
- if (isArray(obj)) {
71
+ if (index_cjs_js$5.isArray(obj)) {
592
72
  return obj.map((item) => sanitize(item));
593
73
  }
594
74
  if (typeof obj === 'object') {
595
75
  const result = {};
596
- for (const [key, value] of entries(obj)) {
76
+ for (const [key, value] of index_cjs_js$2.entries(obj)) {
597
77
  if (isSensitiveKey(key)) {
598
78
  result[key] = REDACTED;
599
79
  }
@@ -618,9 +98,9 @@ function sanitize(obj) {
618
98
  */
619
99
  function formatMessage(namespace, message, meta) {
620
100
  const prefix = `[${namespace}]`;
621
- if (meta && keys(meta).length > 0) {
101
+ if (meta && index_cjs_js$2.keys(meta).length > 0) {
622
102
  const sanitizedMeta = sanitize(meta);
623
- return `${prefix} ${message} ${stringify(sanitizedMeta)}`;
103
+ return `${prefix} ${message} ${index_cjs_js$6.stringify(sanitizedMeta)}`;
624
104
  }
625
105
  return `${prefix} ${message}`;
626
106
  }
@@ -633,7 +113,7 @@ function formatMessage(namespace, message, meta) {
633
113
  * @param options - Logger configuration options
634
114
  * @returns A configured scoped logger instance
635
115
  *
636
- * @example
116
+ * @example Creating a scoped logger
637
117
  * ```typescript
638
118
  * const logger = createScopedLogger('project-scope')
639
119
  * logger.setLogLevel('debug')
@@ -652,9 +132,9 @@ function createScopedLogger(namespace, options = {}) {
652
132
  const processedMeta = sanitizeSecrets && meta ? sanitize(meta) : meta;
653
133
  baseFn(formatMessage(namespace, message, processedMeta));
654
134
  };
655
- const baseLogger = createLogger(createLogFn(error), createLogFn(warn), createLogFn(log), createLogFn(info), createLogFn(debug));
135
+ const baseLogger = index_cjs_js$3.createLogger(createLogFn(index_cjs_js$4.error), createLogFn(index_cjs_js$4.warn), createLogFn(index_cjs_js$4.log), createLogFn(index_cjs_js$4.info), createLogFn(index_cjs_js$4.debug));
656
136
  baseLogger.setLogLevel(level);
657
- const scopedLogger = freeze({
137
+ const scopedLogger = index_cjs_js$2.freeze({
658
138
  error: (message, meta) => baseLogger.error(message, meta),
659
139
  warn: (message, meta) => baseLogger.warn(message, meta),
660
140
  log: (message, meta) => baseLogger.log(message, meta),
@@ -670,7 +150,7 @@ function createScopedLogger(namespace, options = {}) {
670
150
  * Default logger instance for the project-scope library.
671
151
  * Use this for general logging within the library.
672
152
  *
673
- * @example
153
+ * @example Using the default logger
674
154
  * ```typescript
675
155
  * import { logger } from '@hyperfrontend/project-scope/core'
676
156
  *
@@ -688,10 +168,19 @@ createScopedLogger('project-scope:fs');
688
168
  * @param code - The category code for this type of filesystem failure
689
169
  * @param context - Additional context including path, operation, and cause
690
170
  * @returns A configured Error object with code and context properties
171
+ *
172
+ * @example Creating a file system error
173
+ * ```typescript
174
+ * throw createFileSystemError(
175
+ * 'Cannot read file',
176
+ * 'FS_READ_ERROR',
177
+ * { path: './missing.txt', operation: 'read' }
178
+ * )
179
+ * ```
691
180
  */
692
181
  function createFileSystemError(message, code, context) {
693
- const error = createError(message);
694
- defineProperties(error, {
182
+ const error = index_cjs_js$7.createError(message);
183
+ index_cjs_js$2.defineProperties(error, {
695
184
  code: { value: code, enumerable: true },
696
185
  context: { value: context, enumerable: true },
697
186
  });
@@ -703,9 +192,17 @@ function createFileSystemError(message, code, context) {
703
192
  * @param filePath - Path to file
704
193
  * @param encoding - File encoding (default: utf-8)
705
194
  * @returns File contents or null if file doesn't exist
195
+ *
196
+ * @example Reading file if it exists
197
+ * ```typescript
198
+ * const content = readFileIfExists('./optional-config.json')
199
+ * if (content) {
200
+ * // File existed, use content
201
+ * }
202
+ * ```
706
203
  */
707
204
  function readFileIfExists(filePath, encoding = 'utf-8') {
708
- if (!node_fs.existsSync(filePath)) {
205
+ if (!isSafePath(filePath) || !node_fs.existsSync(filePath)) {
709
206
  return null;
710
207
  }
711
208
  try {
@@ -716,56 +213,6 @@ function readFileIfExists(filePath, encoding = 'utf-8') {
716
213
  }
717
214
  }
718
215
 
719
- createScopedLogger('project-scope:fs:write');
720
-
721
- /**
722
- * Get file stats with error handling.
723
- *
724
- * @param filePath - Path to file
725
- * @param followSymlinks - Whether to follow symlinks (default: true)
726
- * @returns File stats or null if path doesn't exist
727
- */
728
- function getFileStat(filePath, followSymlinks = true) {
729
- if (!node_fs.existsSync(filePath)) {
730
- return null;
731
- }
732
- try {
733
- const stat = followSymlinks ? node_fs.statSync(filePath) : node_fs.lstatSync(filePath);
734
- return {
735
- isFile: stat.isFile(),
736
- isDirectory: stat.isDirectory(),
737
- isSymlink: stat.isSymbolicLink(),
738
- size: stat.size,
739
- created: stat.birthtime,
740
- modified: stat.mtime,
741
- accessed: stat.atime,
742
- mode: stat.mode,
743
- };
744
- }
745
- catch {
746
- return null;
747
- }
748
- }
749
- /**
750
- * Check if path is a directory.
751
- *
752
- * @param dirPath - Path to check
753
- * @returns True if path is a directory
754
- */
755
- function isDirectory(dirPath) {
756
- const stats = getFileStat(dirPath);
757
- return stats?.isDirectory ?? false;
758
- }
759
- /**
760
- * Check if path exists.
761
- *
762
- * @param filePath - Path to check
763
- * @returns True if path exists
764
- */
765
- function exists(filePath) {
766
- return node_fs.existsSync(filePath);
767
- }
768
-
769
216
  const fsDirLogger = createScopedLogger('project-scope:fs:dir');
770
217
  /**
771
218
  * List immediate contents of a directory.
@@ -774,7 +221,7 @@ const fsDirLogger = createScopedLogger('project-scope:fs:dir');
774
221
  * @returns Array of entries with metadata for each file/directory
775
222
  * @throws {Error} If directory doesn't exist or isn't a directory
776
223
  *
777
- * @example
224
+ * @example Listing directory contents
778
225
  * ```typescript
779
226
  * import { readDirectory } from '@hyperfrontend/project-scope'
780
227
  *
@@ -815,19 +262,10 @@ function readDirectory(dirPath) {
815
262
  }
816
263
  }
817
264
 
818
- /**
819
- * Join path segments.
820
- * Uses platform-specific separators (e.g., / or \).
821
- *
822
- * @param paths - Path segments to join
823
- * @returns Joined path
824
- */
825
- function join(...paths) {
826
- return node_path.join(...paths);
827
- }
828
-
829
265
  createScopedLogger('project-scope:fs:traversal');
830
266
 
267
+ createScopedLogger('project-scope:fs:write');
268
+
831
269
  const packageLogger = createScopedLogger('project-scope:project:package');
832
270
  /**
833
271
  * Verifies that a value is an object with only string values,
@@ -839,7 +277,7 @@ const packageLogger = createScopedLogger('project-scope:project:package');
839
277
  function isStringRecord(value) {
840
278
  if (typeof value !== 'object' || value === null)
841
279
  return false;
842
- return values(value).every((v) => typeof v === 'string');
280
+ return index_cjs_js$2.values(value).every((v) => typeof v === 'string');
843
281
  }
844
282
  /**
845
283
  * Extracts and normalizes the workspaces field from package.json,
@@ -849,12 +287,12 @@ function isStringRecord(value) {
849
287
  * @returns Normalized workspace patterns or undefined if invalid
850
288
  */
851
289
  function parseWorkspaces(value) {
852
- if (isArray(value) && value.every((v) => typeof v === 'string')) {
290
+ if (index_cjs_js$5.isArray(value) && value.every((v) => typeof v === 'string')) {
853
291
  return value;
854
292
  }
855
293
  if (typeof value === 'object' && value !== null) {
856
294
  const obj = value;
857
- if (isArray(obj['packages'])) {
295
+ if (index_cjs_js$5.isArray(obj['packages'])) {
858
296
  return { packages: obj['packages'] };
859
297
  }
860
298
  }
@@ -868,7 +306,7 @@ function parseWorkspaces(value) {
868
306
  */
869
307
  function validatePackageJson(data) {
870
308
  if (typeof data !== 'object' || data === null) {
871
- throw createError('package.json must be an object');
309
+ throw index_cjs_js$7.createError('package.json must be an object');
872
310
  }
873
311
  const pkg = data;
874
312
  return {
@@ -897,6 +335,16 @@ function validatePackageJson(data) {
897
335
  *
898
336
  * @param projectPath - Project directory path or path to package.json
899
337
  * @returns Parsed package.json or null if not found
338
+ *
339
+ * @example Reading package.json if it exists
340
+ * ```typescript
341
+ * import { readPackageJsonIfExists } from '@hyperfrontend/project-scope'
342
+ *
343
+ * const pkg = readPackageJsonIfExists('/path/to/project')
344
+ * if (pkg) {
345
+ * console.log('Found:', pkg.name)
346
+ * }
347
+ * ```
900
348
  */
901
349
  function readPackageJsonIfExists(projectPath) {
902
350
  const packageJsonPath = projectPath.endsWith('package.json') ? projectPath : node_path.join(projectPath, 'package.json');
@@ -906,7 +354,7 @@ function readPackageJsonIfExists(projectPath) {
906
354
  return null;
907
355
  }
908
356
  try {
909
- const validated = validatePackageJson(parse(content));
357
+ const validated = validatePackageJson(index_cjs_js$6.parse(content));
910
358
  packageLogger.debug('Package.json loaded', { path: packageJsonPath, name: validated.name });
911
359
  return validated;
912
360
  }
@@ -917,79 +365,31 @@ function readPackageJsonIfExists(projectPath) {
917
365
  }
918
366
 
919
367
  /**
920
- * Get combined dependencies from package.json.
921
- * Merges dependencies, devDependencies, peerDependencies, and optionalDependencies.
368
+ * Detect Express in project.
922
369
  *
923
- * @param packageJson - The package.json object to extract dependencies from
924
- * @returns Combined dependencies as a single record
925
- */
926
- function collectAllDependencies(packageJson) {
927
- return {
928
- ...packageJson?.dependencies,
929
- ...packageJson?.devDependencies,
930
- ...packageJson?.peerDependencies,
931
- ...packageJson?.optionalDependencies,
932
- };
933
- }
934
- /**
935
- * Extract clean version from dependency version string.
936
- * Removes semver prefixes like ^, ~, >=, etc.
937
- * Uses character-by-character parsing to avoid ReDoS vulnerabilities.
370
+ * @param projectPath - Project directory path
371
+ * @param packageJson - Optional pre-loaded package.json
372
+ * @returns Detection result or null if not detected
373
+ * @example Detecting Express framework
374
+ * ```typescript
375
+ * const pkg = {
376
+ * dependencies: { express: '^4.18.2', cors: '^2.8.5' },
377
+ * devDependencies: { '@types/express': '^4.17.17' },
378
+ * }
938
379
  *
939
- * @param versionString - The version string with optional prefix characters
940
- * @returns The cleaned version string without prefix characters
941
- */
942
- function parseVersionString(versionString) {
943
- if (versionString === undefined || versionString === null)
944
- return undefined;
945
- let start = 0;
946
- while (start < versionString.length) {
947
- const char = versionString[start];
948
- if (char !== '^' && char !== '~' && char !== '>' && char !== '=' && char !== '<') {
949
- break;
950
- }
951
- start++;
952
- }
953
- return versionString.slice(start);
954
- }
955
- /**
956
- * Find first matching config file in project.
957
- * Note: Name avoids similarity to fs.readFile/fs.readFileSync.
958
- *
959
- * @param projectPath - The project directory path
960
- * @param patterns - Array of config file patterns to search for
961
- * @returns The first matching config file path or undefined
962
- */
963
- function locateConfigFile(projectPath, patterns) {
964
- for (const pattern of patterns) {
965
- const fullPath = join(projectPath, pattern);
966
- if (exists(fullPath)) {
967
- return pattern;
968
- }
969
- }
970
- return undefined;
971
- }
972
- /**
973
- * Find scripts containing a specific command.
974
- *
975
- * @param scripts - The scripts object from package.json
976
- * @param command - The command string to search for
977
- * @returns Array of script names that contain the command
978
- */
979
- function filterScriptsByCommand(scripts, command) {
980
- if (!scripts)
981
- return [];
982
- return entries(scripts)
983
- .filter(([, script]) => script.includes(command))
984
- .map(([name]) => name);
985
- }
986
-
987
- /**
988
- * Detect Express in project.
989
- *
990
- * @param projectPath - Project directory path
991
- * @param packageJson - Optional pre-loaded package.json
992
- * @returns Detection result or null if not detected
380
+ * const result = expressDetector('/path/to/project', pkg)
381
+ * // => {
382
+ * // id: 'express',
383
+ * // name: 'Express',
384
+ * // version: '4.18.2',
385
+ * // confidence: 100,
386
+ * // detectedFrom: [
387
+ * // { type: 'package.json', field: 'dependencies.express' },
388
+ * // { type: 'package.json', field: 'dependencies.@types/express' },
389
+ * // { type: 'package.json', field: 'dependencies (express middleware)' },
390
+ * // ],
391
+ * // }
392
+ * ```
993
393
  */
994
394
  function expressDetector(projectPath, packageJson) {
995
395
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -1006,7 +406,7 @@ function expressDetector(projectPath, packageJson) {
1006
406
  confidence += 10;
1007
407
  sources.push({ type: 'package.json', field: 'dependencies.@types/express' });
1008
408
  }
1009
- const expressMiddleware = keys(deps).filter((d) => d.includes('express-') || d === 'body-parser' || d === 'cors' || d === 'helmet' || d === 'morgan');
409
+ const expressMiddleware = index_cjs_js$2.keys(deps).filter((d) => d.includes('express-') || d === 'body-parser' || d === 'cors' || d === 'helmet' || d === 'morgan');
1010
410
  if (expressMiddleware.length > 0) {
1011
411
  confidence += 10;
1012
412
  sources.push({ type: 'package.json', field: 'dependencies (express middleware)' });
@@ -1018,92 +418,117 @@ function expressDetector(projectPath, packageJson) {
1018
418
  id: 'express',
1019
419
  name: 'Express',
1020
420
  version,
1021
- confidence: min(confidence, 100),
421
+ confidence: index_cjs_js$8.min(confidence, 100),
1022
422
  detectedFrom: sources,
1023
423
  };
1024
424
  }
1025
425
 
1026
426
  /**
1027
- * Detect NestJS in project.
427
+ * Detect Fastify in project.
1028
428
  *
1029
429
  * @param projectPath - Project directory path
1030
430
  * @param packageJson - Optional pre-loaded package.json
1031
431
  * @returns Detection result or null if not detected
432
+ * @example Detecting Fastify framework
433
+ * ```typescript
434
+ * const pkg = {
435
+ * dependencies: { fastify: '^4.24.0', '@fastify/cors': '^8.4.0' },
436
+ * }
437
+ *
438
+ * const result = fastifyDetector('/path/to/project', pkg)
439
+ * // => {
440
+ * // id: 'fastify',
441
+ * // name: 'Fastify',
442
+ * // version: '4.24.0',
443
+ * // confidence: 95,
444
+ * // detectedFrom: [
445
+ * // { type: 'package.json', field: 'dependencies.fastify' },
446
+ * // { type: 'package.json', field: 'dependencies (fastify plugins)' },
447
+ * // ],
448
+ * // }
449
+ * ```
1032
450
  */
1033
- function nestDetector(projectPath, packageJson) {
451
+ function fastifyDetector(projectPath, packageJson) {
1034
452
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1035
453
  const sources = [];
1036
454
  let confidence = 0;
1037
455
  let version;
1038
- let configPath;
1039
456
  const deps = collectAllDependencies(pkg);
1040
- if (deps['@nestjs/core']) {
1041
- confidence += 70;
1042
- version = parseVersionString(deps['@nestjs/core']);
1043
- sources.push({ type: 'package.json', field: 'dependencies.@nestjs/core' });
1044
- }
1045
- if (deps['@nestjs/common']) {
1046
- confidence += 15;
1047
- sources.push({ type: 'package.json', field: 'dependencies.@nestjs/common' });
457
+ if (deps['fastify']) {
458
+ confidence += 80;
459
+ version = parseVersionString(deps['fastify']);
460
+ sources.push({ type: 'package.json', field: 'dependencies.fastify' });
1048
461
  }
1049
- if (exists(node_path.join(projectPath, 'nest-cli.json'))) {
462
+ const fastifyPlugins = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('@fastify/') || d.startsWith('fastify-'));
463
+ if (fastifyPlugins.length > 0) {
1050
464
  confidence += 15;
1051
- configPath = 'nest-cli.json';
1052
- sources.push({ type: 'config-file', path: 'nest-cli.json' });
465
+ sources.push({ type: 'package.json', field: 'dependencies (fastify plugins)' });
1053
466
  }
1054
- const nestPackages = keys(deps).filter((d) => d.startsWith('@nestjs/'));
1055
- if (nestPackages.length > 2) {
467
+ if (deps['@types/fastify']) {
1056
468
  confidence += 5;
1057
- sources.push({ type: 'package.json', field: 'dependencies (@nestjs packages)' });
469
+ sources.push({ type: 'package.json', field: 'dependencies.@types/fastify' });
1058
470
  }
1059
471
  if (confidence === 0) {
1060
472
  return null;
1061
473
  }
1062
474
  return {
1063
- id: 'nestjs',
1064
- name: 'NestJS',
475
+ id: 'fastify',
476
+ name: 'Fastify',
1065
477
  version,
1066
- configPath,
1067
- confidence: min(confidence, 100),
478
+ confidence: index_cjs_js$8.min(confidence, 100),
1068
479
  detectedFrom: sources,
1069
480
  };
1070
481
  }
1071
482
 
1072
483
  /**
1073
- * Detect Fastify in project.
484
+ * Detect Hono in project.
1074
485
  *
1075
486
  * @param projectPath - Project directory path
1076
487
  * @param packageJson - Optional pre-loaded package.json
1077
488
  * @returns Detection result or null if not detected
489
+ * @example Detecting Hono framework
490
+ * ```typescript
491
+ * const pkg = {
492
+ * dependencies: { hono: '^3.11.0', '@hono/node-server': '^1.3.0' },
493
+ * }
494
+ *
495
+ * const result = honoDetector('/path/to/project', pkg)
496
+ * // => {
497
+ * // id: 'hono',
498
+ * // name: 'Hono',
499
+ * // version: '3.11.0',
500
+ * // confidence: 100,
501
+ * // detectedFrom: [
502
+ * // { type: 'package.json', field: 'dependencies.hono' },
503
+ * // { type: 'package.json', field: 'dependencies (@hono adapters)' },
504
+ * // ],
505
+ * // }
506
+ * ```
1078
507
  */
1079
- function fastifyDetector(projectPath, packageJson) {
508
+ function honoDetector(projectPath, packageJson) {
1080
509
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1081
510
  const sources = [];
1082
511
  let confidence = 0;
1083
512
  let version;
1084
513
  const deps = collectAllDependencies(pkg);
1085
- if (deps['fastify']) {
1086
- confidence += 80;
1087
- version = parseVersionString(deps['fastify']);
1088
- sources.push({ type: 'package.json', field: 'dependencies.fastify' });
514
+ if (deps['hono']) {
515
+ confidence += 85;
516
+ version = parseVersionString(deps['hono']);
517
+ sources.push({ type: 'package.json', field: 'dependencies.hono' });
1089
518
  }
1090
- const fastifyPlugins = keys(deps).filter((d) => d.startsWith('@fastify/') || d.startsWith('fastify-'));
1091
- if (fastifyPlugins.length > 0) {
519
+ const honoAdapters = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('@hono/'));
520
+ if (honoAdapters.length > 0) {
1092
521
  confidence += 15;
1093
- sources.push({ type: 'package.json', field: 'dependencies (fastify plugins)' });
1094
- }
1095
- if (deps['@types/fastify']) {
1096
- confidence += 5;
1097
- sources.push({ type: 'package.json', field: 'dependencies.@types/fastify' });
522
+ sources.push({ type: 'package.json', field: 'dependencies (@hono adapters)' });
1098
523
  }
1099
524
  if (confidence === 0) {
1100
525
  return null;
1101
526
  }
1102
527
  return {
1103
- id: 'fastify',
1104
- name: 'Fastify',
528
+ id: 'hono',
529
+ name: 'Hono',
1105
530
  version,
1106
- confidence: min(confidence, 100),
531
+ confidence: index_cjs_js$8.min(confidence, 100),
1107
532
  detectedFrom: sources,
1108
533
  };
1109
534
  }
@@ -1114,6 +539,26 @@ function fastifyDetector(projectPath, packageJson) {
1114
539
  * @param projectPath - Project directory path
1115
540
  * @param packageJson - Optional pre-loaded package.json
1116
541
  * @returns Detection result or null if not detected
542
+ * @example Detecting Koa framework
543
+ * ```typescript
544
+ * const pkg = {
545
+ * dependencies: { koa: '^2.14.2', 'koa-router': '^12.0.0' },
546
+ * devDependencies: { '@types/koa': '^2.13.9' },
547
+ * }
548
+ *
549
+ * const result = koaDetector('/path/to/project', pkg)
550
+ * // => {
551
+ * // id: 'koa',
552
+ * // name: 'Koa',
553
+ * // version: '2.14.2',
554
+ * // confidence: 100,
555
+ * // detectedFrom: [
556
+ * // { type: 'package.json', field: 'dependencies.koa' },
557
+ * // { type: 'package.json', field: 'dependencies.@types/koa' },
558
+ * // { type: 'package.json', field: 'dependencies (koa middleware)' },
559
+ * // ],
560
+ * // }
561
+ * ```
1117
562
  */
1118
563
  function koaDetector(projectPath, packageJson) {
1119
564
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -1130,7 +575,7 @@ function koaDetector(projectPath, packageJson) {
1130
575
  confidence += 10;
1131
576
  sources.push({ type: 'package.json', field: 'dependencies.@types/koa' });
1132
577
  }
1133
- const koaMiddleware = keys(deps).filter((d) => d.startsWith('koa-') || d.startsWith('@koa/'));
578
+ const koaMiddleware = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('koa-') || d.startsWith('@koa/'));
1134
579
  if (koaMiddleware.length > 0) {
1135
580
  confidence += 10;
1136
581
  sources.push({ type: 'package.json', field: 'dependencies (koa middleware)' });
@@ -1142,42 +587,79 @@ function koaDetector(projectPath, packageJson) {
1142
587
  id: 'koa',
1143
588
  name: 'Koa',
1144
589
  version,
1145
- confidence: min(confidence, 100),
590
+ confidence: index_cjs_js$8.min(confidence, 100),
1146
591
  detectedFrom: sources,
1147
592
  };
1148
593
  }
1149
594
 
1150
595
  /**
1151
- * Detect Hono in project.
596
+ * Detect NestJS in project.
1152
597
  *
1153
598
  * @param projectPath - Project directory path
1154
599
  * @param packageJson - Optional pre-loaded package.json
1155
600
  * @returns Detection result or null if not detected
601
+ * @example Detecting NestJS framework
602
+ * ```typescript
603
+ * // Project with nest-cli.json and NestJS packages
604
+ * const pkg = {
605
+ * dependencies: {
606
+ * '@nestjs/core': '^10.2.0',
607
+ * '@nestjs/common': '^10.2.0',
608
+ * '@nestjs/platform-express': '^10.2.0',
609
+ * },
610
+ * }
611
+ *
612
+ * const result = nestDetector('/path/to/nest-project', pkg)
613
+ * // => {
614
+ * // id: 'nestjs',
615
+ * // name: 'NestJS',
616
+ * // version: '10.2.0',
617
+ * // configPath: 'nest-cli.json', // if present
618
+ * // confidence: 100,
619
+ * // detectedFrom: [
620
+ * // { type: 'package.json', field: 'dependencies.@nestjs/core' },
621
+ * // { type: 'package.json', field: 'dependencies.@nestjs/common' },
622
+ * // { type: 'config-file', path: 'nest-cli.json' },
623
+ * // { type: 'package.json', field: 'dependencies (@nestjs packages)' },
624
+ * // ],
625
+ * // }
626
+ * ```
1156
627
  */
1157
- function honoDetector(projectPath, packageJson) {
628
+ function nestDetector(projectPath, packageJson) {
1158
629
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1159
630
  const sources = [];
1160
631
  let confidence = 0;
1161
632
  let version;
633
+ let configPath;
1162
634
  const deps = collectAllDependencies(pkg);
1163
- if (deps['hono']) {
1164
- confidence += 85;
1165
- version = parseVersionString(deps['hono']);
1166
- sources.push({ type: 'package.json', field: 'dependencies.hono' });
635
+ if (deps['@nestjs/core']) {
636
+ confidence += 70;
637
+ version = parseVersionString(deps['@nestjs/core']);
638
+ sources.push({ type: 'package.json', field: 'dependencies.@nestjs/core' });
1167
639
  }
1168
- const honoAdapters = keys(deps).filter((d) => d.startsWith('@hono/'));
1169
- if (honoAdapters.length > 0) {
640
+ if (deps['@nestjs/common']) {
1170
641
  confidence += 15;
1171
- sources.push({ type: 'package.json', field: 'dependencies (@hono adapters)' });
642
+ sources.push({ type: 'package.json', field: 'dependencies.@nestjs/common' });
643
+ }
644
+ if (exists(node_path.join(projectPath, 'nest-cli.json'))) {
645
+ confidence += 15;
646
+ configPath = 'nest-cli.json';
647
+ sources.push({ type: 'config-file', path: 'nest-cli.json' });
648
+ }
649
+ const nestPackages = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('@nestjs/'));
650
+ if (nestPackages.length > 2) {
651
+ confidence += 5;
652
+ sources.push({ type: 'package.json', field: 'dependencies (@nestjs packages)' });
1172
653
  }
1173
654
  if (confidence === 0) {
1174
655
  return null;
1175
656
  }
1176
657
  return {
1177
- id: 'hono',
1178
- name: 'Hono',
658
+ id: 'nestjs',
659
+ name: 'NestJS',
1179
660
  version,
1180
- confidence: min(confidence, 100),
661
+ configPath,
662
+ confidence: index_cjs_js$8.min(confidence, 100),
1181
663
  detectedFrom: sources,
1182
664
  };
1183
665
  }
@@ -1191,102 +673,194 @@ const backendDetectors = [
1191
673
  { id: 'hono', name: 'Hono', detect: honoDetector },
1192
674
  ];
1193
675
 
1194
- /** Config patterns for Webpack */
1195
- const WEBPACK_CONFIG_PATTERNS = [
1196
- 'webpack.config.js',
1197
- 'webpack.config.ts',
1198
- 'webpack.config.cjs',
1199
- 'webpack.config.mjs',
1200
- 'webpack.config.babel.js',
1201
- ];
676
+ /** Config patterns for Babel */
677
+ const BABEL_CONFIG_PATTERNS = ['babel.config.js', 'babel.config.cjs', 'babel.config.mjs', 'babel.config.json', '.babelrc', '.babelrc.json', '.babelrc.js'];
1202
678
  /**
1203
- * Detect Webpack in project.
679
+ * Detect Babel in project.
1204
680
  *
1205
681
  * @param projectPath - Project directory path
1206
682
  * @param packageJson - Optional pre-loaded package.json
1207
683
  * @returns Detection result or null if not detected
684
+ *
685
+ * @example Detecting Babel compiler
686
+ * ```typescript
687
+ * const result = babelDetector('/path/to/project', {
688
+ * name: 'my-app',
689
+ * devDependencies: { '@babel/core': '^7.23.0', '@babel/preset-env': '^7.23.0' }
690
+ * })
691
+ * // => {
692
+ * // id: 'babel',
693
+ * // name: 'Babel',
694
+ * // version: '7.23.0',
695
+ * // confidence: 60,
696
+ * // detectedFrom: [
697
+ * // { type: 'package.json', field: 'dependencies.@babel/core' },
698
+ * // { type: 'package.json', field: 'dependencies (@babel packages)' }
699
+ * // ]
700
+ * // }
701
+ * ```
1208
702
  */
1209
- function webpackDetector(projectPath, packageJson) {
703
+ function babelDetector(projectPath, packageJson) {
1210
704
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1211
705
  const sources = [];
1212
706
  let confidence = 0;
1213
707
  let version;
1214
708
  const deps = collectAllDependencies(pkg);
1215
- if (deps['webpack']) {
709
+ if (deps['@babel/core']) {
1216
710
  confidence += 50;
1217
- version = parseVersionString(deps['webpack']);
1218
- sources.push({ type: 'package.json', field: 'dependencies.webpack' });
711
+ version = parseVersionString(deps['@babel/core']);
712
+ sources.push({ type: 'package.json', field: 'dependencies.@babel/core' });
1219
713
  }
1220
- const configPath = locateConfigFile(projectPath, WEBPACK_CONFIG_PATTERNS);
714
+ const configPath = locateConfigFile(projectPath, BABEL_CONFIG_PATTERNS);
1221
715
  if (configPath) {
1222
716
  confidence += 40;
1223
717
  sources.push({ type: 'config-file', path: configPath });
1224
718
  }
1225
- if (deps['webpack-cli']) {
719
+ if (pkg && 'babel' in pkg) {
720
+ confidence += 30;
721
+ sources.push({ type: 'package.json', field: 'babel' });
722
+ }
723
+ const babelPackages = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('@babel/'));
724
+ if (babelPackages.length > 1) {
1226
725
  confidence += 10;
1227
- sources.push({ type: 'package.json', field: 'dependencies.webpack-cli' });
726
+ sources.push({ type: 'package.json', field: 'dependencies (@babel packages)' });
1228
727
  }
1229
- const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'webpack');
728
+ if (confidence === 0) {
729
+ return null;
730
+ }
731
+ return {
732
+ id: 'babel',
733
+ name: 'Babel',
734
+ version,
735
+ configPath,
736
+ confidence: index_cjs_js$8.min(confidence, 100),
737
+ detectedFrom: sources,
738
+ };
739
+ }
740
+
741
+ /**
742
+ * Detect esbuild in project.
743
+ *
744
+ * @param projectPath - Project directory path
745
+ * @param packageJson - Optional pre-loaded package.json
746
+ * @returns Detection result or null if not detected
747
+ *
748
+ * @example Detecting esbuild bundler
749
+ * ```typescript
750
+ * const result = esbuildDetector('/path/to/project', {
751
+ * name: 'my-lib',
752
+ * devDependencies: { 'esbuild': '^0.19.0' },
753
+ * scripts: { 'build': 'esbuild src/index.ts --bundle --outfile=dist/index.js' }
754
+ * })
755
+ * // => {
756
+ * // id: 'esbuild',
757
+ * // name: 'esbuild',
758
+ * // version: '0.19.0',
759
+ * // confidence: 80,
760
+ * // detectedFrom: [
761
+ * // { type: 'package.json', field: 'dependencies.esbuild' },
762
+ * // { type: 'package.json', field: 'scripts.build' }
763
+ * // ]
764
+ * // }
765
+ * ```
766
+ */
767
+ function esbuildDetector(projectPath, packageJson) {
768
+ const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
769
+ const sources = [];
770
+ let confidence = 0;
771
+ let version;
772
+ const deps = collectAllDependencies(pkg);
773
+ if (deps['esbuild']) {
774
+ confidence += 70;
775
+ version = parseVersionString(deps['esbuild']);
776
+ sources.push({ type: 'package.json', field: 'dependencies.esbuild' });
777
+ }
778
+ const esbuildPlugins = index_cjs_js$2.keys(deps).filter((d) => d.includes('esbuild-plugin') || d.includes('esbuild-'));
779
+ if (esbuildPlugins.length > 0) {
780
+ confidence += 15;
781
+ sources.push({ type: 'package.json', field: 'dependencies (esbuild plugins)' });
782
+ }
783
+ const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'esbuild');
1230
784
  for (const name of scriptMatches) {
1231
- confidence = min(confidence + 5, 100);
785
+ confidence = index_cjs_js$8.min(confidence + 10, 100);
1232
786
  sources.push({ type: 'package.json', field: `scripts.${name}` });
1233
787
  }
1234
788
  if (confidence === 0) {
1235
789
  return null;
1236
790
  }
1237
791
  return {
1238
- id: 'webpack',
1239
- name: 'Webpack',
792
+ id: 'esbuild',
793
+ name: 'esbuild',
1240
794
  version,
1241
- configPath,
1242
- confidence: min(confidence, 100),
795
+ confidence: index_cjs_js$8.min(confidence, 100),
1243
796
  detectedFrom: sources,
1244
797
  };
1245
798
  }
1246
799
 
1247
- /** Config patterns for Vite */
1248
- const VITE_CONFIG_PATTERNS = ['vite.config.js', 'vite.config.ts', 'vite.config.mjs', 'vite.config.cjs'];
800
+ /** Config patterns for Parcel */
801
+ const PARCEL_CONFIG_PATTERNS = ['.parcelrc'];
1249
802
  /**
1250
- * Detect Vite in project.
803
+ * Detect Parcel in project.
1251
804
  *
1252
805
  * @param projectPath - Project directory path
1253
806
  * @param packageJson - Optional pre-loaded package.json
1254
807
  * @returns Detection result or null if not detected
808
+ *
809
+ * @example Detecting Parcel bundler
810
+ * ```typescript
811
+ * const result = parcelDetector('/path/to/project', {
812
+ * name: 'my-app',
813
+ * devDependencies: { 'parcel': '^2.10.0' },
814
+ * scripts: { 'dev': 'parcel src/index.html', 'build': 'parcel build src/index.html' }
815
+ * })
816
+ * // => {
817
+ * // id: 'parcel',
818
+ * // name: 'Parcel',
819
+ * // version: '2.10.0',
820
+ * // confidence: 80,
821
+ * // detectedFrom: [
822
+ * // { type: 'package.json', field: 'dependencies.parcel' },
823
+ * // { type: 'package.json', field: 'scripts.dev' },
824
+ * // { type: 'package.json', field: 'scripts.build' }
825
+ * // ]
826
+ * // }
827
+ * ```
1255
828
  */
1256
- function viteDetector(projectPath, packageJson) {
829
+ function parcelDetector(projectPath, packageJson) {
1257
830
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1258
831
  const sources = [];
1259
832
  let confidence = 0;
1260
833
  let version;
1261
834
  const deps = collectAllDependencies(pkg);
1262
- if (deps['vite']) {
835
+ if (deps['parcel']) {
1263
836
  confidence += 60;
1264
- version = parseVersionString(deps['vite']);
1265
- sources.push({ type: 'package.json', field: 'dependencies.vite' });
837
+ version = parseVersionString(deps['parcel']);
838
+ sources.push({ type: 'package.json', field: 'dependencies.parcel' });
1266
839
  }
1267
- const configPath = locateConfigFile(projectPath, VITE_CONFIG_PATTERNS);
840
+ if (deps['parcel-bundler']) {
841
+ confidence += 60;
842
+ version = parseVersionString(deps['parcel-bundler']);
843
+ sources.push({ type: 'package.json', field: 'dependencies.parcel-bundler' });
844
+ }
845
+ const configPath = locateConfigFile(projectPath, PARCEL_CONFIG_PATTERNS);
1268
846
  if (configPath) {
1269
- confidence += 35;
847
+ confidence += 30;
1270
848
  sources.push({ type: 'config-file', path: configPath });
1271
849
  }
1272
- if (deps['vitest']) {
1273
- confidence += 10;
1274
- sources.push({ type: 'package.json', field: 'dependencies.vitest' });
1275
- }
1276
- const vitePlugins = keys(deps).filter((d) => d.startsWith('vite-plugin-') || d.startsWith('@vitejs/'));
1277
- if (vitePlugins.length > 0) {
1278
- confidence += 10;
1279
- sources.push({ type: 'package.json', field: 'dependencies (vite plugins)' });
850
+ const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'parcel');
851
+ for (const name of scriptMatches) {
852
+ confidence = index_cjs_js$8.min(confidence + 10, 100);
853
+ sources.push({ type: 'package.json', field: `scripts.${name}` });
1280
854
  }
1281
855
  if (confidence === 0) {
1282
856
  return null;
1283
857
  }
1284
858
  return {
1285
- id: 'vite',
1286
- name: 'Vite',
859
+ id: 'parcel',
860
+ name: 'Parcel',
1287
861
  version,
1288
862
  configPath,
1289
- confidence: min(confidence, 100),
863
+ confidence: index_cjs_js$8.min(confidence, 100),
1290
864
  detectedFrom: sources,
1291
865
  };
1292
866
  }
@@ -1299,6 +873,28 @@ const ROLLUP_CONFIG_PATTERNS = ['rollup.config.js', 'rollup.config.ts', 'rollup.
1299
873
  * @param projectPath - Project directory path
1300
874
  * @param packageJson - Optional pre-loaded package.json
1301
875
  * @returns Detection result or null if not detected
876
+ *
877
+ * @example Detecting Rollup bundler
878
+ * ```typescript
879
+ * const result = rollupDetector('/path/to/project', {
880
+ * name: 'my-lib',
881
+ * devDependencies: {
882
+ * 'rollup': '^4.0.0',
883
+ * '@rollup/plugin-node-resolve': '^15.0.0',
884
+ * '@rollup/plugin-commonjs': '^25.0.0'
885
+ * }
886
+ * })
887
+ * // => {
888
+ * // id: 'rollup',
889
+ * // name: 'Rollup',
890
+ * // version: '4.0.0',
891
+ * // confidence: 65,
892
+ * // detectedFrom: [
893
+ * // { type: 'package.json', field: 'dependencies.rollup' },
894
+ * // { type: 'package.json', field: 'dependencies (rollup plugins)' }
895
+ * // ]
896
+ * // }
897
+ * ```
1302
898
  */
1303
899
  function rollupDetector(projectPath, packageJson) {
1304
900
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -1316,14 +912,14 @@ function rollupDetector(projectPath, packageJson) {
1316
912
  confidence += 40;
1317
913
  sources.push({ type: 'config-file', path: configPath });
1318
914
  }
1319
- const rollupPlugins = keys(deps).filter((d) => d.startsWith('@rollup/') || d.startsWith('rollup-plugin-'));
915
+ const rollupPlugins = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('@rollup/') || d.startsWith('rollup-plugin-'));
1320
916
  if (rollupPlugins.length > 0) {
1321
917
  confidence += 10;
1322
918
  sources.push({ type: 'package.json', field: 'dependencies (rollup plugins)' });
1323
919
  }
1324
920
  const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'rollup');
1325
921
  for (const name of scriptMatches) {
1326
- confidence = min(confidence + 5, 100);
922
+ confidence = index_cjs_js$8.min(confidence + 5, 100);
1327
923
  sources.push({ type: 'package.json', field: `scripts.${name}` });
1328
924
  }
1329
925
  if (confidence === 0) {
@@ -1334,280 +930,412 @@ function rollupDetector(projectPath, packageJson) {
1334
930
  name: 'Rollup',
1335
931
  version,
1336
932
  configPath,
1337
- confidence: min(confidence, 100),
933
+ confidence: index_cjs_js$8.min(confidence, 100),
1338
934
  detectedFrom: sources,
1339
935
  };
1340
936
  }
1341
937
 
938
+ /** Config patterns for SWC */
939
+ const SWC_CONFIG_PATTERNS = ['.swcrc', 'swc.config.js'];
1342
940
  /**
1343
- * Detect esbuild in project.
941
+ * Detect SWC in project.
1344
942
  *
1345
943
  * @param projectPath - Project directory path
1346
944
  * @param packageJson - Optional pre-loaded package.json
1347
945
  * @returns Detection result or null if not detected
946
+ *
947
+ * @example Detecting SWC compiler
948
+ * ```typescript
949
+ * const result = swcDetector('/path/to/project', {
950
+ * name: 'my-app',
951
+ * devDependencies: { '@swc/core': '^1.3.0', '@swc/cli': '^0.1.0' }
952
+ * })
953
+ * // => {
954
+ * // id: 'swc',
955
+ * // name: 'SWC',
956
+ * // version: '1.3.0',
957
+ * // confidence: 70,
958
+ * // detectedFrom: [
959
+ * // { type: 'package.json', field: 'dependencies.@swc/core' },
960
+ * // { type: 'package.json', field: 'dependencies.@swc/cli' }
961
+ * // ]
962
+ * // }
963
+ * ```
1348
964
  */
1349
- function esbuildDetector(projectPath, packageJson) {
965
+ function swcDetector(projectPath, packageJson) {
1350
966
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1351
967
  const sources = [];
1352
968
  let confidence = 0;
1353
969
  let version;
1354
970
  const deps = collectAllDependencies(pkg);
1355
- if (deps['esbuild']) {
1356
- confidence += 70;
1357
- version = parseVersionString(deps['esbuild']);
1358
- sources.push({ type: 'package.json', field: 'dependencies.esbuild' });
971
+ if (deps['@swc/core']) {
972
+ confidence += 60;
973
+ version = parseVersionString(deps['@swc/core']);
974
+ sources.push({ type: 'package.json', field: 'dependencies.@swc/core' });
1359
975
  }
1360
- const esbuildPlugins = keys(deps).filter((d) => d.includes('esbuild-plugin') || d.includes('esbuild-'));
1361
- if (esbuildPlugins.length > 0) {
1362
- confidence += 15;
1363
- sources.push({ type: 'package.json', field: 'dependencies (esbuild plugins)' });
976
+ const configPath = locateConfigFile(projectPath, SWC_CONFIG_PATTERNS);
977
+ if (configPath) {
978
+ confidence += 35;
979
+ sources.push({ type: 'config-file', path: configPath });
1364
980
  }
1365
- const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'esbuild');
1366
- for (const name of scriptMatches) {
1367
- confidence = min(confidence + 10, 100);
1368
- sources.push({ type: 'package.json', field: `scripts.${name}` });
981
+ if (deps['@swc/cli']) {
982
+ confidence += 10;
983
+ sources.push({ type: 'package.json', field: 'dependencies.@swc/cli' });
984
+ }
985
+ const swcPlugins = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('@swc/') || d.includes('swc-plugin'));
986
+ if (swcPlugins.length > 1) {
987
+ confidence += 5;
988
+ sources.push({ type: 'package.json', field: 'dependencies (@swc packages)' });
1369
989
  }
1370
990
  if (confidence === 0) {
1371
991
  return null;
1372
992
  }
1373
993
  return {
1374
- id: 'esbuild',
1375
- name: 'esbuild',
994
+ id: 'swc',
995
+ name: 'SWC',
1376
996
  version,
1377
- confidence: min(confidence, 100),
997
+ configPath,
998
+ confidence: index_cjs_js$8.min(confidence, 100),
1378
999
  detectedFrom: sources,
1379
1000
  };
1380
1001
  }
1381
1002
 
1382
- /** Config patterns for Babel */
1383
- const BABEL_CONFIG_PATTERNS = ['babel.config.js', 'babel.config.cjs', 'babel.config.mjs', 'babel.config.json', '.babelrc', '.babelrc.json', '.babelrc.js'];
1003
+ /** Config patterns for Vite */
1004
+ const VITE_CONFIG_PATTERNS = ['vite.config.js', 'vite.config.ts', 'vite.config.mjs', 'vite.config.cjs'];
1384
1005
  /**
1385
- * Detect Babel in project.
1006
+ * Detect Vite in project.
1386
1007
  *
1387
1008
  * @param projectPath - Project directory path
1388
1009
  * @param packageJson - Optional pre-loaded package.json
1389
1010
  * @returns Detection result or null if not detected
1011
+ *
1012
+ * @example Detecting Vite build tool
1013
+ * ```typescript
1014
+ * const result = viteDetector('/path/to/project', {
1015
+ * name: 'my-app',
1016
+ * devDependencies: {
1017
+ * 'vite': '^5.0.0',
1018
+ * '@vitejs/plugin-react': '^4.0.0',
1019
+ * 'vitest': '^1.0.0'
1020
+ * }
1021
+ * })
1022
+ * // => {
1023
+ * // id: 'vite',
1024
+ * // name: 'Vite',
1025
+ * // version: '5.0.0',
1026
+ * // confidence: 80,
1027
+ * // detectedFrom: [
1028
+ * // { type: 'package.json', field: 'dependencies.vite' },
1029
+ * // { type: 'package.json', field: 'dependencies.vitest' },
1030
+ * // { type: 'package.json', field: 'dependencies (vite plugins)' }
1031
+ * // ]
1032
+ * // }
1033
+ * ```
1390
1034
  */
1391
- function babelDetector(projectPath, packageJson) {
1035
+ function viteDetector(projectPath, packageJson) {
1392
1036
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1393
1037
  const sources = [];
1394
1038
  let confidence = 0;
1395
1039
  let version;
1396
1040
  const deps = collectAllDependencies(pkg);
1397
- if (deps['@babel/core']) {
1398
- confidence += 50;
1399
- version = parseVersionString(deps['@babel/core']);
1400
- sources.push({ type: 'package.json', field: 'dependencies.@babel/core' });
1041
+ if (deps['vite']) {
1042
+ confidence += 60;
1043
+ version = parseVersionString(deps['vite']);
1044
+ sources.push({ type: 'package.json', field: 'dependencies.vite' });
1401
1045
  }
1402
- const configPath = locateConfigFile(projectPath, BABEL_CONFIG_PATTERNS);
1046
+ const configPath = locateConfigFile(projectPath, VITE_CONFIG_PATTERNS);
1403
1047
  if (configPath) {
1404
- confidence += 40;
1048
+ confidence += 35;
1405
1049
  sources.push({ type: 'config-file', path: configPath });
1406
1050
  }
1407
- if (pkg && 'babel' in pkg) {
1408
- confidence += 30;
1409
- sources.push({ type: 'package.json', field: 'babel' });
1051
+ if (deps['vitest']) {
1052
+ confidence += 10;
1053
+ sources.push({ type: 'package.json', field: 'dependencies.vitest' });
1410
1054
  }
1411
- const babelPackages = keys(deps).filter((d) => d.startsWith('@babel/'));
1412
- if (babelPackages.length > 1) {
1055
+ const vitePlugins = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('vite-plugin-') || d.startsWith('@vitejs/'));
1056
+ if (vitePlugins.length > 0) {
1413
1057
  confidence += 10;
1414
- sources.push({ type: 'package.json', field: 'dependencies (@babel packages)' });
1058
+ sources.push({ type: 'package.json', field: 'dependencies (vite plugins)' });
1415
1059
  }
1416
1060
  if (confidence === 0) {
1417
1061
  return null;
1418
1062
  }
1419
1063
  return {
1420
- id: 'babel',
1421
- name: 'Babel',
1064
+ id: 'vite',
1065
+ name: 'Vite',
1422
1066
  version,
1423
1067
  configPath,
1424
- confidence: min(confidence, 100),
1068
+ confidence: index_cjs_js$8.min(confidence, 100),
1425
1069
  detectedFrom: sources,
1426
1070
  };
1427
1071
  }
1428
1072
 
1429
- /** Config patterns for SWC */
1430
- const SWC_CONFIG_PATTERNS = ['.swcrc', 'swc.config.js'];
1073
+ /** Config patterns for Webpack */
1074
+ const WEBPACK_CONFIG_PATTERNS = [
1075
+ 'webpack.config.js',
1076
+ 'webpack.config.ts',
1077
+ 'webpack.config.cjs',
1078
+ 'webpack.config.mjs',
1079
+ 'webpack.config.babel.js',
1080
+ ];
1431
1081
  /**
1432
- * Detect SWC in project.
1082
+ * Detect Webpack in project.
1433
1083
  *
1434
1084
  * @param projectPath - Project directory path
1435
1085
  * @param packageJson - Optional pre-loaded package.json
1436
1086
  * @returns Detection result or null if not detected
1087
+ *
1088
+ * @example Detecting Webpack bundler
1089
+ * ```typescript
1090
+ * const result = webpackDetector('/path/to/project', {
1091
+ * name: 'my-app',
1092
+ * devDependencies: { 'webpack': '^5.89.0', 'webpack-cli': '^5.1.0' },
1093
+ * scripts: { 'build': 'webpack --mode production' }
1094
+ * })
1095
+ * // => {
1096
+ * // id: 'webpack',
1097
+ * // name: 'Webpack',
1098
+ * // version: '5.89.0',
1099
+ * // confidence: 65,
1100
+ * // detectedFrom: [
1101
+ * // { type: 'package.json', field: 'dependencies.webpack' },
1102
+ * // { type: 'package.json', field: 'dependencies.webpack-cli' },
1103
+ * // { type: 'package.json', field: 'scripts.build' }
1104
+ * // ]
1105
+ * // }
1106
+ * ```
1437
1107
  */
1438
- function swcDetector(projectPath, packageJson) {
1108
+ function webpackDetector(projectPath, packageJson) {
1439
1109
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1440
1110
  const sources = [];
1441
1111
  let confidence = 0;
1442
1112
  let version;
1443
1113
  const deps = collectAllDependencies(pkg);
1444
- if (deps['@swc/core']) {
1445
- confidence += 60;
1446
- version = parseVersionString(deps['@swc/core']);
1447
- sources.push({ type: 'package.json', field: 'dependencies.@swc/core' });
1114
+ if (deps['webpack']) {
1115
+ confidence += 50;
1116
+ version = parseVersionString(deps['webpack']);
1117
+ sources.push({ type: 'package.json', field: 'dependencies.webpack' });
1448
1118
  }
1449
- const configPath = locateConfigFile(projectPath, SWC_CONFIG_PATTERNS);
1119
+ const configPath = locateConfigFile(projectPath, WEBPACK_CONFIG_PATTERNS);
1450
1120
  if (configPath) {
1451
- confidence += 35;
1121
+ confidence += 40;
1452
1122
  sources.push({ type: 'config-file', path: configPath });
1453
1123
  }
1454
- if (deps['@swc/cli']) {
1124
+ if (deps['webpack-cli']) {
1455
1125
  confidence += 10;
1456
- sources.push({ type: 'package.json', field: 'dependencies.@swc/cli' });
1126
+ sources.push({ type: 'package.json', field: 'dependencies.webpack-cli' });
1457
1127
  }
1458
- const swcPlugins = keys(deps).filter((d) => d.startsWith('@swc/') || d.includes('swc-plugin'));
1459
- if (swcPlugins.length > 1) {
1460
- confidence += 5;
1461
- sources.push({ type: 'package.json', field: 'dependencies (@swc packages)' });
1128
+ const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'webpack');
1129
+ for (const name of scriptMatches) {
1130
+ confidence = index_cjs_js$8.min(confidence + 5, 100);
1131
+ sources.push({ type: 'package.json', field: `scripts.${name}` });
1462
1132
  }
1463
1133
  if (confidence === 0) {
1464
1134
  return null;
1465
1135
  }
1466
1136
  return {
1467
- id: 'swc',
1468
- name: 'SWC',
1137
+ id: 'webpack',
1138
+ name: 'Webpack',
1469
1139
  version,
1470
1140
  configPath,
1471
- confidence: min(confidence, 100),
1141
+ confidence: index_cjs_js$8.min(confidence, 100),
1472
1142
  detectedFrom: sources,
1473
1143
  };
1474
1144
  }
1475
1145
 
1476
- /** Config patterns for Parcel */
1477
- const PARCEL_CONFIG_PATTERNS = ['.parcelrc'];
1146
+ /** All build tool detectors */
1147
+ const buildToolDetectors = [
1148
+ { id: 'webpack', name: 'Webpack', detect: webpackDetector },
1149
+ { id: 'vite', name: 'Vite', detect: viteDetector },
1150
+ { id: 'rollup', name: 'Rollup', detect: rollupDetector },
1151
+ { id: 'esbuild', name: 'esbuild', detect: esbuildDetector },
1152
+ { id: 'babel', name: 'Babel', detect: babelDetector },
1153
+ { id: 'swc', name: 'SWC', detect: swcDetector },
1154
+ { id: 'parcel', name: 'Parcel', detect: parcelDetector },
1155
+ ];
1156
+
1478
1157
  /**
1479
- * Detect Parcel in project.
1158
+ * Detect Angular in project.
1480
1159
  *
1481
1160
  * @param projectPath - Project directory path
1482
1161
  * @param packageJson - Optional pre-loaded package.json
1483
1162
  * @returns Detection result or null if not detected
1163
+ *
1164
+ * @example Detecting Angular framework
1165
+ * ```typescript
1166
+ * const result = angularDetector('/path/to/angular-app', {
1167
+ * dependencies: { '@angular/core': '^17.0.0', '@angular/cli': '^17.0.0' }
1168
+ * })
1169
+ * // => {
1170
+ * // id: 'angular',
1171
+ * // name: 'Angular',
1172
+ * // category: 'frontend',
1173
+ * // version: '17.0.0',
1174
+ * // confidence: 85,
1175
+ * // detectedFrom: [
1176
+ * // { type: 'package.json', field: 'dependencies.@angular/core' },
1177
+ * // { type: 'package.json', field: 'dependencies.@angular/cli' }
1178
+ * // ]
1179
+ * // }
1180
+ * ```
1484
1181
  */
1485
- function parcelDetector(projectPath, packageJson) {
1182
+ function angularDetector(projectPath, packageJson) {
1486
1183
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1487
1184
  const sources = [];
1488
1185
  let confidence = 0;
1489
1186
  let version;
1490
1187
  const deps = collectAllDependencies(pkg);
1491
- if (deps['parcel']) {
1492
- confidence += 60;
1493
- version = parseVersionString(deps['parcel']);
1494
- sources.push({ type: 'package.json', field: 'dependencies.parcel' });
1188
+ if (deps['@angular/core']) {
1189
+ confidence += 70;
1190
+ version = parseVersionString(deps['@angular/core']);
1191
+ sources.push({ type: 'package.json', field: 'dependencies.@angular/core' });
1495
1192
  }
1496
- if (deps['parcel-bundler']) {
1497
- confidence += 60;
1498
- version = parseVersionString(deps['parcel-bundler']);
1499
- sources.push({ type: 'package.json', field: 'dependencies.parcel-bundler' });
1193
+ if (deps['@angular/cli']) {
1194
+ confidence += 15;
1195
+ sources.push({ type: 'package.json', field: 'dependencies.@angular/cli' });
1500
1196
  }
1501
- const configPath = locateConfigFile(projectPath, PARCEL_CONFIG_PATTERNS);
1502
- if (configPath) {
1503
- confidence += 30;
1504
- sources.push({ type: 'config-file', path: configPath });
1197
+ if (exists(node_path.join(projectPath, 'angular.json'))) {
1198
+ confidence += 15;
1199
+ sources.push({ type: 'config-file', path: 'angular.json' });
1505
1200
  }
1506
- const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'parcel');
1507
- for (const name of scriptMatches) {
1508
- confidence = min(confidence + 10, 100);
1509
- sources.push({ type: 'package.json', field: `scripts.${name}` });
1201
+ if (deps['angular'] && !deps['@angular/core']) {
1202
+ return {
1203
+ id: 'angularjs',
1204
+ name: 'AngularJS (Legacy)',
1205
+ category: 'frontend',
1206
+ version: parseVersionString(deps['angular']),
1207
+ confidence: 80,
1208
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.angular' }],
1209
+ };
1510
1210
  }
1511
1211
  if (confidence === 0) {
1512
1212
  return null;
1513
1213
  }
1514
1214
  return {
1515
- id: 'parcel',
1516
- name: 'Parcel',
1215
+ id: 'angular',
1216
+ name: 'Angular',
1217
+ category: 'frontend',
1517
1218
  version,
1518
- configPath,
1519
- confidence: min(confidence, 100),
1219
+ confidence: index_cjs_js$8.min(confidence, 100),
1520
1220
  detectedFrom: sources,
1521
1221
  };
1522
1222
  }
1523
1223
 
1524
- /** All build tool detectors */
1525
- const buildToolDetectors = [
1526
- { id: 'webpack', name: 'Webpack', detect: webpackDetector },
1527
- { id: 'vite', name: 'Vite', detect: viteDetector },
1528
- { id: 'rollup', name: 'Rollup', detect: rollupDetector },
1529
- { id: 'esbuild', name: 'esbuild', detect: esbuildDetector },
1530
- { id: 'babel', name: 'Babel', detect: babelDetector },
1531
- { id: 'swc', name: 'SWC', detect: swcDetector },
1532
- { id: 'parcel', name: 'Parcel', detect: parcelDetector },
1533
- ];
1534
-
1535
1224
  /**
1536
- * Detect React in project.
1225
+ * Detect Astro in project.
1537
1226
  *
1538
1227
  * @param projectPath - Project directory path
1539
1228
  * @param packageJson - Optional pre-loaded package.json
1540
1229
  * @returns Detection result or null if not detected
1230
+ *
1231
+ * @example Detecting Astro framework
1232
+ * ```typescript
1233
+ * const result = astroDetector('/path/to/astro-project', {
1234
+ * dependencies: { 'astro': '^4.0.0' }
1235
+ * })
1236
+ * // => {
1237
+ * // id: 'astro',
1238
+ * // name: 'Astro',
1239
+ * // category: 'meta-framework',
1240
+ * // version: '4.0.0',
1241
+ * // confidence: 70,
1242
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.astro' }]
1243
+ * // }
1244
+ * ```
1541
1245
  */
1542
- function reactDetector(projectPath, packageJson) {
1246
+ function astroDetector(projectPath, packageJson) {
1543
1247
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1544
1248
  const sources = [];
1545
1249
  let confidence = 0;
1546
1250
  let version;
1547
- const metaFrameworks = [];
1548
1251
  const deps = collectAllDependencies(pkg);
1549
- if (deps['react']) {
1550
- confidence += 60;
1551
- version = parseVersionString(deps['react']);
1552
- sources.push({ type: 'package.json', field: 'dependencies.react' });
1553
- }
1554
- if (deps['react-dom']) {
1555
- confidence += 20;
1556
- sources.push({ type: 'package.json', field: 'dependencies.react-dom' });
1252
+ if (deps['astro']) {
1253
+ confidence += 70;
1254
+ version = parseVersionString(deps['astro']);
1255
+ sources.push({ type: 'package.json', field: 'dependencies.astro' });
1557
1256
  }
1558
- if (deps['react-native']) {
1559
- confidence += 20;
1560
- sources.push({ type: 'package.json', field: 'dependencies.react-native' });
1257
+ if (exists(node_path.join(projectPath, 'astro.config.mjs')) ||
1258
+ exists(node_path.join(projectPath, 'astro.config.ts')) ||
1259
+ exists(node_path.join(projectPath, 'astro.config.js'))) {
1260
+ confidence += 25;
1261
+ sources.push({ type: 'config-file', path: 'astro.config.*' });
1561
1262
  }
1562
- const hasJsxFiles = exists(node_path.join(projectPath, 'src', 'App.tsx')) ||
1563
- exists(node_path.join(projectPath, 'src', 'App.jsx')) ||
1564
- exists(node_path.join(projectPath, 'src', 'index.tsx')) ||
1565
- exists(node_path.join(projectPath, 'src', 'index.jsx'));
1566
- if (hasJsxFiles) {
1567
- confidence += 10;
1568
- sources.push({ type: 'directory', path: 'src/*.tsx or src/*.jsx' });
1263
+ if (exists(node_path.join(projectPath, 'src', 'pages'))) {
1264
+ confidence += 5;
1265
+ sources.push({ type: 'directory', path: 'src/pages/' });
1569
1266
  }
1570
- if (deps['next']) {
1571
- metaFrameworks.push({
1572
- id: 'nextjs',
1573
- name: 'Next.js',
1574
- category: 'meta-framework',
1575
- version: parseVersionString(deps['next']),
1576
- confidence: 90,
1577
- detectedFrom: [{ type: 'package.json', field: 'dependencies.next' }],
1578
- });
1267
+ if (confidence === 0) {
1268
+ return null;
1579
1269
  }
1270
+ return {
1271
+ id: 'astro',
1272
+ name: 'Astro',
1273
+ category: 'meta-framework',
1274
+ version,
1275
+ confidence: index_cjs_js$8.min(confidence, 100),
1276
+ detectedFrom: sources,
1277
+ };
1278
+ }
1279
+
1280
+ /**
1281
+ * Detect Gatsby in project.
1282
+ *
1283
+ * @param projectPath - Project directory path
1284
+ * @param packageJson - Optional pre-loaded package.json
1285
+ * @returns Detection result or null if not detected
1286
+ *
1287
+ * @example Detecting Gatsby framework
1288
+ * ```typescript
1289
+ * const result = gatsbyDetector('/path/to/gatsby-blog', {
1290
+ * dependencies: {
1291
+ * 'gatsby': '^5.0.0',
1292
+ * 'gatsby-plugin-image': '^3.0.0',
1293
+ * 'gatsby-source-filesystem': '^5.0.0'
1294
+ * }
1295
+ * })
1296
+ * // => {
1297
+ * // id: 'gatsby',
1298
+ * // name: 'Gatsby',
1299
+ * // category: 'meta-framework',
1300
+ * // version: '5.0.0',
1301
+ * // confidence: 75,
1302
+ * // detectedFrom: [
1303
+ * // { type: 'package.json', field: 'dependencies.gatsby' },
1304
+ * // { type: 'package.json', field: 'dependencies (gatsby plugins)' }
1305
+ * // ]
1306
+ * // }
1307
+ * ```
1308
+ */
1309
+ function gatsbyDetector(projectPath, packageJson) {
1310
+ const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1311
+ const sources = [];
1312
+ let confidence = 0;
1313
+ let version;
1314
+ const deps = collectAllDependencies(pkg);
1580
1315
  if (deps['gatsby']) {
1581
- metaFrameworks.push({
1582
- id: 'gatsby',
1583
- name: 'Gatsby',
1584
- category: 'meta-framework',
1585
- version: parseVersionString(deps['gatsby']),
1586
- confidence: 90,
1587
- detectedFrom: [{ type: 'package.json', field: 'dependencies.gatsby' }],
1588
- });
1316
+ confidence += 70;
1317
+ version = parseVersionString(deps['gatsby']);
1318
+ sources.push({ type: 'package.json', field: 'dependencies.gatsby' });
1589
1319
  }
1590
- if (deps['@remix-run/react'] || deps['remix']) {
1591
- metaFrameworks.push({
1592
- id: 'remix',
1593
- name: 'Remix',
1594
- category: 'meta-framework',
1595
- version: parseVersionString(deps['@remix-run/react'] ?? deps['remix']),
1596
- confidence: 90,
1597
- detectedFrom: [{ type: 'package.json', field: 'dependencies.@remix-run/react' }],
1598
- });
1320
+ if (exists(node_path.join(projectPath, 'gatsby-config.js')) || exists(node_path.join(projectPath, 'gatsby-config.ts'))) {
1321
+ confidence += 25;
1322
+ sources.push({ type: 'config-file', path: 'gatsby-config.*' });
1323
+ }
1324
+ const gatsbyPlugins = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('gatsby-plugin-') || d.startsWith('gatsby-source-'));
1325
+ if (gatsbyPlugins.length > 0) {
1326
+ confidence += 5;
1327
+ sources.push({ type: 'package.json', field: 'dependencies (gatsby plugins)' });
1599
1328
  }
1600
1329
  if (confidence === 0) {
1601
1330
  return null;
1602
1331
  }
1603
1332
  return {
1604
- id: 'react',
1605
- name: 'React',
1606
- category: 'frontend',
1333
+ id: 'gatsby',
1334
+ name: 'Gatsby',
1335
+ category: 'meta-framework',
1607
1336
  version,
1608
- confidence: min(confidence, 100),
1337
+ confidence: index_cjs_js$8.min(confidence, 100),
1609
1338
  detectedFrom: sources,
1610
- metaFrameworks: metaFrameworks.length > 0 ? metaFrameworks : undefined,
1611
1339
  };
1612
1340
  }
1613
1341
 
@@ -1617,6 +1345,21 @@ function reactDetector(projectPath, packageJson) {
1617
1345
  * @param projectPath - Project directory path
1618
1346
  * @param packageJson - Optional pre-loaded package.json
1619
1347
  * @returns Detection result or null if not detected
1348
+ *
1349
+ * @example Detecting Next.js framework
1350
+ * ```typescript
1351
+ * const result = nextjsDetector('/path/to/nextjs-app', {
1352
+ * dependencies: { 'next': '^14.0.0', 'react': '^18.0.0' }
1353
+ * })
1354
+ * // => {
1355
+ * // id: 'nextjs',
1356
+ * // name: 'Next.js',
1357
+ * // category: 'meta-framework',
1358
+ * // version: '14.0.0',
1359
+ * // confidence: 70,
1360
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.next' }]
1361
+ * // }
1362
+ * ```
1620
1363
  */
1621
1364
  function nextjsDetector(projectPath, packageJson) {
1622
1365
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -1650,230 +1393,335 @@ function nextjsDetector(projectPath, packageJson) {
1650
1393
  name: 'Next.js',
1651
1394
  category: 'meta-framework',
1652
1395
  version,
1653
- confidence: min(confidence, 100),
1396
+ confidence: index_cjs_js$8.min(confidence, 100),
1654
1397
  detectedFrom: sources,
1655
1398
  };
1656
1399
  }
1657
1400
 
1658
1401
  /**
1659
- * Detect Remix in project.
1402
+ * Detect Nuxt in project.
1660
1403
  *
1661
1404
  * @param projectPath - Project directory path
1662
1405
  * @param packageJson - Optional pre-loaded package.json
1663
1406
  * @returns Detection result or null if not detected
1407
+ *
1408
+ * @example Detecting Nuxt framework
1409
+ * ```typescript
1410
+ * const result = nuxtDetector('/path/to/nuxt-app', {
1411
+ * dependencies: { 'nuxt': '^3.0.0', 'vue': '^3.0.0' }
1412
+ * })
1413
+ * // => {
1414
+ * // id: 'nuxt',
1415
+ * // name: 'Nuxt',
1416
+ * // category: 'meta-framework',
1417
+ * // version: '3.0.0',
1418
+ * // confidence: 70,
1419
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.nuxt' }]
1420
+ * // }
1421
+ * ```
1664
1422
  */
1665
- function remixDetector(projectPath, packageJson) {
1423
+ function nuxtDetector(projectPath, packageJson) {
1666
1424
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1667
1425
  const sources = [];
1668
1426
  let confidence = 0;
1669
1427
  let version;
1670
1428
  const deps = collectAllDependencies(pkg);
1671
- if (deps['@remix-run/react']) {
1429
+ if (deps['nuxt'] || deps['nuxt3']) {
1672
1430
  confidence += 70;
1673
- version = parseVersionString(deps['@remix-run/react']);
1674
- sources.push({ type: 'package.json', field: 'dependencies.@remix-run/react' });
1431
+ version = parseVersionString(deps['nuxt'] ?? deps['nuxt3']);
1432
+ sources.push({ type: 'package.json', field: 'dependencies.nuxt' });
1675
1433
  }
1676
- if (deps['@remix-run/node'] || deps['@remix-run/cloudflare'] || deps['@remix-run/deno']) {
1677
- confidence += 20;
1678
- sources.push({ type: 'package.json', field: 'dependencies.@remix-run/*' });
1434
+ if (exists(node_path.join(projectPath, 'nuxt.config.js')) || exists(node_path.join(projectPath, 'nuxt.config.ts'))) {
1435
+ confidence += 25;
1436
+ sources.push({ type: 'config-file', path: 'nuxt.config.*' });
1679
1437
  }
1680
- if (exists(node_path.join(projectPath, 'remix.config.js')) || exists(node_path.join(projectPath, 'remix.config.ts'))) {
1681
- confidence += 10;
1682
- sources.push({ type: 'config-file', path: 'remix.config.*' });
1438
+ if (exists(node_path.join(projectPath, 'pages'))) {
1439
+ confidence += 5;
1440
+ sources.push({ type: 'directory', path: 'pages/' });
1683
1441
  }
1684
1442
  if (confidence === 0) {
1685
1443
  return null;
1686
1444
  }
1687
1445
  return {
1688
- id: 'remix',
1689
- name: 'Remix',
1446
+ id: 'nuxt',
1447
+ name: 'Nuxt',
1690
1448
  category: 'meta-framework',
1691
1449
  version,
1692
- confidence: min(confidence, 100),
1450
+ confidence: index_cjs_js$8.min(confidence, 100),
1693
1451
  detectedFrom: sources,
1694
1452
  };
1695
1453
  }
1696
1454
 
1697
1455
  /**
1698
- * Detect Gatsby in project.
1456
+ * Detect Qwik in project.
1699
1457
  *
1700
1458
  * @param projectPath - Project directory path
1701
1459
  * @param packageJson - Optional pre-loaded package.json
1702
1460
  * @returns Detection result or null if not detected
1461
+ *
1462
+ * @example Detecting Qwik framework
1463
+ * ```typescript
1464
+ * const result = qwikDetector('/path/to/qwik-app', {
1465
+ * dependencies: {
1466
+ * '@builder.io/qwik': '^1.0.0',
1467
+ * '@builder.io/qwik-city': '^1.0.0'
1468
+ * }
1469
+ * })
1470
+ * // => {
1471
+ * // id: 'qwik',
1472
+ * // name: 'Qwik',
1473
+ * // category: 'frontend',
1474
+ * // version: '1.0.0',
1475
+ * // confidence: 90,
1476
+ * // detectedFrom: [
1477
+ * // { type: 'package.json', field: 'dependencies.@builder.io/qwik' },
1478
+ * // { type: 'package.json', field: 'dependencies.@builder.io/qwik-city' }
1479
+ * // ]
1480
+ * // }
1481
+ * ```
1703
1482
  */
1704
- function gatsbyDetector(projectPath, packageJson) {
1483
+ function qwikDetector(projectPath, packageJson) {
1705
1484
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1706
1485
  const sources = [];
1707
1486
  let confidence = 0;
1708
1487
  let version;
1709
1488
  const deps = collectAllDependencies(pkg);
1710
- if (deps['gatsby']) {
1489
+ if (deps['@builder.io/qwik']) {
1711
1490
  confidence += 70;
1712
- version = parseVersionString(deps['gatsby']);
1713
- sources.push({ type: 'package.json', field: 'dependencies.gatsby' });
1491
+ version = parseVersionString(deps['@builder.io/qwik']);
1492
+ sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik' });
1714
1493
  }
1715
- if (exists(node_path.join(projectPath, 'gatsby-config.js')) || exists(node_path.join(projectPath, 'gatsby-config.ts'))) {
1716
- confidence += 25;
1717
- sources.push({ type: 'config-file', path: 'gatsby-config.*' });
1494
+ if (deps['@builder.io/qwik-city']) {
1495
+ confidence += 20;
1496
+ sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik-city' });
1718
1497
  }
1719
- const gatsbyPlugins = keys(deps).filter((d) => d.startsWith('gatsby-plugin-') || d.startsWith('gatsby-source-'));
1720
- if (gatsbyPlugins.length > 0) {
1721
- confidence += 5;
1722
- sources.push({ type: 'package.json', field: 'dependencies (gatsby plugins)' });
1498
+ if (exists(node_path.join(projectPath, 'qwik.config.ts')) || exists(node_path.join(projectPath, 'qwik.config.js'))) {
1499
+ confidence += 10;
1500
+ sources.push({ type: 'config-file', path: 'qwik.config.*' });
1723
1501
  }
1724
1502
  if (confidence === 0) {
1725
1503
  return null;
1726
1504
  }
1727
1505
  return {
1728
- id: 'gatsby',
1729
- name: 'Gatsby',
1730
- category: 'meta-framework',
1506
+ id: 'qwik',
1507
+ name: 'Qwik',
1508
+ category: 'frontend',
1731
1509
  version,
1732
- confidence: min(confidence, 100),
1510
+ confidence: index_cjs_js$8.min(confidence, 100),
1733
1511
  detectedFrom: sources,
1734
1512
  };
1735
1513
  }
1736
1514
 
1737
1515
  /**
1738
- * Detect Vue in project.
1516
+ * Detect React in project.
1739
1517
  *
1740
1518
  * @param projectPath - Project directory path
1741
1519
  * @param packageJson - Optional pre-loaded package.json
1742
1520
  * @returns Detection result or null if not detected
1521
+ *
1522
+ * @example Detecting React library
1523
+ * ```typescript
1524
+ * const result = reactDetector('/path/to/react-app', {
1525
+ * dependencies: { 'react': '^18.0.0', 'react-dom': '^18.0.0' }
1526
+ * })
1527
+ * // => {
1528
+ * // id: 'react',
1529
+ * // name: 'React',
1530
+ * // category: 'frontend',
1531
+ * // version: '18.0.0',
1532
+ * // confidence: 80,
1533
+ * // detectedFrom: [
1534
+ * // { type: 'package.json', field: 'dependencies.react' },
1535
+ * // { type: 'package.json', field: 'dependencies.react-dom' }
1536
+ * // ]
1537
+ * // }
1538
+ * ```
1743
1539
  */
1744
- function vueDetector(projectPath, packageJson) {
1540
+ function reactDetector(projectPath, packageJson) {
1745
1541
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1746
1542
  const sources = [];
1747
1543
  let confidence = 0;
1748
1544
  let version;
1749
1545
  const metaFrameworks = [];
1750
1546
  const deps = collectAllDependencies(pkg);
1751
- if (deps['vue']) {
1752
- confidence += 70;
1753
- version = parseVersionString(deps['vue']);
1754
- sources.push({ type: 'package.json', field: 'dependencies.vue' });
1547
+ if (deps['react']) {
1548
+ confidence += 60;
1549
+ version = parseVersionString(deps['react']);
1550
+ sources.push({ type: 'package.json', field: 'dependencies.react' });
1755
1551
  }
1756
- if (deps['@vue/cli-service']) {
1757
- confidence += 15;
1758
- sources.push({ type: 'package.json', field: 'dependencies.@vue/cli-service' });
1552
+ if (deps['react-dom']) {
1553
+ confidence += 20;
1554
+ sources.push({ type: 'package.json', field: 'dependencies.react-dom' });
1759
1555
  }
1760
- const hasVueFiles = exists(node_path.join(projectPath, 'src', 'App.vue')) || exists(node_path.join(projectPath, 'src', 'main.vue'));
1761
- if (hasVueFiles) {
1556
+ if (deps['react-native']) {
1557
+ confidence += 20;
1558
+ sources.push({ type: 'package.json', field: 'dependencies.react-native' });
1559
+ }
1560
+ const hasJsxFiles = exists(node_path.join(projectPath, 'src', 'App.tsx')) ||
1561
+ exists(node_path.join(projectPath, 'src', 'App.jsx')) ||
1562
+ exists(node_path.join(projectPath, 'src', 'index.tsx')) ||
1563
+ exists(node_path.join(projectPath, 'src', 'index.jsx'));
1564
+ if (hasJsxFiles) {
1762
1565
  confidence += 10;
1763
- sources.push({ type: 'directory', path: 'src/*.vue' });
1566
+ sources.push({ type: 'directory', path: 'src/*.tsx or src/*.jsx' });
1764
1567
  }
1765
- if (exists(node_path.join(projectPath, 'vue.config.js'))) {
1766
- confidence += 5;
1767
- sources.push({ type: 'config-file', path: 'vue.config.js' });
1568
+ if (deps['next']) {
1569
+ metaFrameworks.push({
1570
+ id: 'nextjs',
1571
+ name: 'Next.js',
1572
+ category: 'meta-framework',
1573
+ version: parseVersionString(deps['next']),
1574
+ confidence: 90,
1575
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.next' }],
1576
+ });
1768
1577
  }
1769
- if (deps['nuxt'] || deps['nuxt3']) {
1578
+ if (deps['gatsby']) {
1770
1579
  metaFrameworks.push({
1771
- id: 'nuxt',
1772
- name: 'Nuxt',
1580
+ id: 'gatsby',
1581
+ name: 'Gatsby',
1773
1582
  category: 'meta-framework',
1774
- version: parseVersionString(deps['nuxt'] ?? deps['nuxt3']),
1583
+ version: parseVersionString(deps['gatsby']),
1775
1584
  confidence: 90,
1776
- detectedFrom: [{ type: 'package.json', field: 'dependencies.nuxt' }],
1585
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.gatsby' }],
1586
+ });
1587
+ }
1588
+ if (deps['@remix-run/react'] || deps['remix']) {
1589
+ metaFrameworks.push({
1590
+ id: 'remix',
1591
+ name: 'Remix',
1592
+ category: 'meta-framework',
1593
+ version: parseVersionString(deps['@remix-run/react'] ?? deps['remix']),
1594
+ confidence: 90,
1595
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.@remix-run/react' }],
1777
1596
  });
1778
1597
  }
1779
1598
  if (confidence === 0) {
1780
1599
  return null;
1781
1600
  }
1782
1601
  return {
1783
- id: 'vue',
1784
- name: 'Vue',
1602
+ id: 'react',
1603
+ name: 'React',
1785
1604
  category: 'frontend',
1786
1605
  version,
1787
- confidence: min(confidence, 100),
1606
+ confidence: index_cjs_js$8.min(confidence, 100),
1788
1607
  detectedFrom: sources,
1789
1608
  metaFrameworks: metaFrameworks.length > 0 ? metaFrameworks : undefined,
1790
1609
  };
1791
1610
  }
1792
1611
 
1793
1612
  /**
1794
- * Detect Nuxt in project.
1613
+ * Detect Remix in project.
1795
1614
  *
1796
1615
  * @param projectPath - Project directory path
1797
1616
  * @param packageJson - Optional pre-loaded package.json
1798
1617
  * @returns Detection result or null if not detected
1618
+ *
1619
+ * @example Detecting Remix framework
1620
+ * ```typescript
1621
+ * const result = remixDetector('/path/to/remix-app', {
1622
+ * dependencies: {
1623
+ * '@remix-run/react': '^2.0.0',
1624
+ * '@remix-run/node': '^2.0.0'
1625
+ * }
1626
+ * })
1627
+ * // => {
1628
+ * // id: 'remix',
1629
+ * // name: 'Remix',
1630
+ * // category: 'meta-framework',
1631
+ * // version: '2.0.0',
1632
+ * // confidence: 90,
1633
+ * // detectedFrom: [
1634
+ * // { type: 'package.json', field: 'dependencies.@remix-run/react' },
1635
+ * // { type: 'package.json', field: 'dependencies.@remix-run/*' }
1636
+ * // ]
1637
+ * // }
1638
+ * ```
1799
1639
  */
1800
- function nuxtDetector(projectPath, packageJson) {
1640
+ function remixDetector(projectPath, packageJson) {
1801
1641
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1802
1642
  const sources = [];
1803
1643
  let confidence = 0;
1804
1644
  let version;
1805
1645
  const deps = collectAllDependencies(pkg);
1806
- if (deps['nuxt'] || deps['nuxt3']) {
1646
+ if (deps['@remix-run/react']) {
1807
1647
  confidence += 70;
1808
- version = parseVersionString(deps['nuxt'] ?? deps['nuxt3']);
1809
- sources.push({ type: 'package.json', field: 'dependencies.nuxt' });
1648
+ version = parseVersionString(deps['@remix-run/react']);
1649
+ sources.push({ type: 'package.json', field: 'dependencies.@remix-run/react' });
1810
1650
  }
1811
- if (exists(node_path.join(projectPath, 'nuxt.config.js')) || exists(node_path.join(projectPath, 'nuxt.config.ts'))) {
1812
- confidence += 25;
1813
- sources.push({ type: 'config-file', path: 'nuxt.config.*' });
1651
+ if (deps['@remix-run/node'] || deps['@remix-run/cloudflare'] || deps['@remix-run/deno']) {
1652
+ confidence += 20;
1653
+ sources.push({ type: 'package.json', field: 'dependencies.@remix-run/*' });
1814
1654
  }
1815
- if (exists(node_path.join(projectPath, 'pages'))) {
1816
- confidence += 5;
1817
- sources.push({ type: 'directory', path: 'pages/' });
1655
+ if (exists(node_path.join(projectPath, 'remix.config.js')) || exists(node_path.join(projectPath, 'remix.config.ts'))) {
1656
+ confidence += 10;
1657
+ sources.push({ type: 'config-file', path: 'remix.config.*' });
1818
1658
  }
1819
1659
  if (confidence === 0) {
1820
1660
  return null;
1821
1661
  }
1822
1662
  return {
1823
- id: 'nuxt',
1824
- name: 'Nuxt',
1663
+ id: 'remix',
1664
+ name: 'Remix',
1825
1665
  category: 'meta-framework',
1826
1666
  version,
1827
- confidence: min(confidence, 100),
1667
+ confidence: index_cjs_js$8.min(confidence, 100),
1828
1668
  detectedFrom: sources,
1829
1669
  };
1830
1670
  }
1831
1671
 
1832
1672
  /**
1833
- * Detect Angular in project.
1673
+ * Detect Solid in project.
1834
1674
  *
1835
1675
  * @param projectPath - Project directory path
1836
1676
  * @param packageJson - Optional pre-loaded package.json
1837
1677
  * @returns Detection result or null if not detected
1678
+ *
1679
+ * @example Detecting Solid.js framework
1680
+ * ```typescript
1681
+ * const result = solidDetector('/path/to/solid-app', {
1682
+ * dependencies: { 'solid-js': '^1.8.0', 'vite-plugin-solid': '^2.0.0' }
1683
+ * })
1684
+ * // => {
1685
+ * // id: 'solid',
1686
+ * // name: 'Solid',
1687
+ * // category: 'frontend',
1688
+ * // version: '1.8.0',
1689
+ * // confidence: 90,
1690
+ * // detectedFrom: [
1691
+ * // { type: 'package.json', field: 'dependencies.solid-js' },
1692
+ * // { type: 'package.json', field: 'dependencies.vite-plugin-solid' }
1693
+ * // ]
1694
+ * // }
1695
+ * ```
1838
1696
  */
1839
- function angularDetector(projectPath, packageJson) {
1697
+ function solidDetector(projectPath, packageJson) {
1840
1698
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1841
1699
  const sources = [];
1842
1700
  let confidence = 0;
1843
1701
  let version;
1844
1702
  const deps = collectAllDependencies(pkg);
1845
- if (deps['@angular/core']) {
1703
+ if (deps['solid-js']) {
1846
1704
  confidence += 70;
1847
- version = parseVersionString(deps['@angular/core']);
1848
- sources.push({ type: 'package.json', field: 'dependencies.@angular/core' });
1849
- }
1850
- if (deps['@angular/cli']) {
1851
- confidence += 15;
1852
- sources.push({ type: 'package.json', field: 'dependencies.@angular/cli' });
1705
+ version = parseVersionString(deps['solid-js']);
1706
+ sources.push({ type: 'package.json', field: 'dependencies.solid-js' });
1853
1707
  }
1854
- if (exists(node_path.join(projectPath, 'angular.json'))) {
1855
- confidence += 15;
1856
- sources.push({ type: 'config-file', path: 'angular.json' });
1708
+ if (deps['vite-plugin-solid']) {
1709
+ confidence += 20;
1710
+ sources.push({ type: 'package.json', field: 'dependencies.vite-plugin-solid' });
1857
1711
  }
1858
- if (deps['angular'] && !deps['@angular/core']) {
1859
- return {
1860
- id: 'angularjs',
1861
- name: 'AngularJS (Legacy)',
1862
- category: 'frontend',
1863
- version: parseVersionString(deps['angular']),
1864
- confidence: 80,
1865
- detectedFrom: [{ type: 'package.json', field: 'dependencies.angular' }],
1866
- };
1712
+ if (deps['solid-start'] || deps['@solidjs/start']) {
1713
+ confidence += 10;
1714
+ sources.push({ type: 'package.json', field: 'dependencies.solid-start' });
1867
1715
  }
1868
1716
  if (confidence === 0) {
1869
1717
  return null;
1870
1718
  }
1871
1719
  return {
1872
- id: 'angular',
1873
- name: 'Angular',
1720
+ id: 'solid',
1721
+ name: 'Solid',
1874
1722
  category: 'frontend',
1875
1723
  version,
1876
- confidence: min(confidence, 100),
1724
+ confidence: index_cjs_js$8.min(confidence, 100),
1877
1725
  detectedFrom: sources,
1878
1726
  };
1879
1727
  }
@@ -1884,6 +1732,21 @@ function angularDetector(projectPath, packageJson) {
1884
1732
  * @param projectPath - Project directory path
1885
1733
  * @param packageJson - Optional pre-loaded package.json
1886
1734
  * @returns Detection result or null if not detected
1735
+ *
1736
+ * @example Detecting Svelte framework
1737
+ * ```typescript
1738
+ * const result = svelteDetector('/path/to/svelte-app', {
1739
+ * devDependencies: { 'svelte': '^4.0.0' }
1740
+ * })
1741
+ * // => {
1742
+ * // id: 'svelte',
1743
+ * // name: 'Svelte',
1744
+ * // category: 'frontend',
1745
+ * // version: '4.0.0',
1746
+ * // confidence: 70,
1747
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.svelte' }]
1748
+ * // }
1749
+ * ```
1887
1750
  */
1888
1751
  function svelteDetector(projectPath, packageJson) {
1889
1752
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -1924,7 +1787,7 @@ function svelteDetector(projectPath, packageJson) {
1924
1787
  name: 'Svelte',
1925
1788
  category: 'frontend',
1926
1789
  version,
1927
- confidence: min(confidence, 100),
1790
+ confidence: index_cjs_js$8.min(confidence, 100),
1928
1791
  detectedFrom: sources,
1929
1792
  metaFrameworks: metaFrameworks.length > 0 ? metaFrameworks : undefined,
1930
1793
  };
@@ -1936,6 +1799,21 @@ function svelteDetector(projectPath, packageJson) {
1936
1799
  * @param projectPath - Project directory path
1937
1800
  * @param packageJson - Optional pre-loaded package.json
1938
1801
  * @returns Detection result or null if not detected
1802
+ *
1803
+ * @example Detecting SvelteKit framework
1804
+ * ```typescript
1805
+ * const result = sveltekitDetector('/path/to/sveltekit-app', {
1806
+ * devDependencies: { '@sveltejs/kit': '^2.0.0', 'svelte': '^4.0.0' }
1807
+ * })
1808
+ * // => {
1809
+ * // id: 'sveltekit',
1810
+ * // name: 'SvelteKit',
1811
+ * // category: 'meta-framework',
1812
+ * // version: '2.0.0',
1813
+ * // confidence: 70,
1814
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.@sveltejs/kit' }]
1815
+ * // }
1816
+ * ```
1939
1817
  */
1940
1818
  function sveltekitDetector(projectPath, packageJson) {
1941
1819
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -1964,127 +1842,82 @@ function sveltekitDetector(projectPath, packageJson) {
1964
1842
  name: 'SvelteKit',
1965
1843
  category: 'meta-framework',
1966
1844
  version,
1967
- confidence: min(confidence, 100),
1845
+ confidence: index_cjs_js$8.min(confidence, 100),
1968
1846
  detectedFrom: sources,
1969
1847
  };
1970
1848
  }
1971
1849
 
1972
1850
  /**
1973
- * Detect Solid in project.
1851
+ * Detect Vue in project.
1974
1852
  *
1975
1853
  * @param projectPath - Project directory path
1976
1854
  * @param packageJson - Optional pre-loaded package.json
1977
1855
  * @returns Detection result or null if not detected
1978
- */
1979
- function solidDetector(projectPath, packageJson) {
1980
- const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1981
- const sources = [];
1982
- let confidence = 0;
1983
- let version;
1984
- const deps = collectAllDependencies(pkg);
1985
- if (deps['solid-js']) {
1986
- confidence += 70;
1987
- version = parseVersionString(deps['solid-js']);
1988
- sources.push({ type: 'package.json', field: 'dependencies.solid-js' });
1989
- }
1990
- if (deps['vite-plugin-solid']) {
1991
- confidence += 20;
1992
- sources.push({ type: 'package.json', field: 'dependencies.vite-plugin-solid' });
1993
- }
1994
- if (deps['solid-start'] || deps['@solidjs/start']) {
1995
- confidence += 10;
1996
- sources.push({ type: 'package.json', field: 'dependencies.solid-start' });
1997
- }
1998
- if (confidence === 0) {
1999
- return null;
2000
- }
2001
- return {
2002
- id: 'solid',
2003
- name: 'Solid',
2004
- category: 'frontend',
2005
- version,
2006
- confidence: min(confidence, 100),
2007
- detectedFrom: sources,
2008
- };
2009
- }
2010
-
2011
- /**
2012
- * Detect Qwik in project.
2013
1856
  *
2014
- * @param projectPath - Project directory path
2015
- * @param packageJson - Optional pre-loaded package.json
2016
- * @returns Detection result or null if not detected
1857
+ * @example Detecting Vue.js framework
1858
+ * ```typescript
1859
+ * const result = vueDetector('/path/to/vue-app', {
1860
+ * dependencies: { 'vue': '^3.0.0', '@vue/cli-service': '^5.0.0' }
1861
+ * })
1862
+ * // => {
1863
+ * // id: 'vue',
1864
+ * // name: 'Vue',
1865
+ * // category: 'frontend',
1866
+ * // version: '3.0.0',
1867
+ * // confidence: 85,
1868
+ * // detectedFrom: [
1869
+ * // { type: 'package.json', field: 'dependencies.vue' },
1870
+ * // { type: 'package.json', field: 'dependencies.@vue/cli-service' }
1871
+ * // ]
1872
+ * // }
1873
+ * ```
2017
1874
  */
2018
- function qwikDetector(projectPath, packageJson) {
1875
+ function vueDetector(projectPath, packageJson) {
2019
1876
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2020
1877
  const sources = [];
2021
1878
  let confidence = 0;
2022
1879
  let version;
1880
+ const metaFrameworks = [];
2023
1881
  const deps = collectAllDependencies(pkg);
2024
- if (deps['@builder.io/qwik']) {
1882
+ if (deps['vue']) {
2025
1883
  confidence += 70;
2026
- version = parseVersionString(deps['@builder.io/qwik']);
2027
- sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik' });
1884
+ version = parseVersionString(deps['vue']);
1885
+ sources.push({ type: 'package.json', field: 'dependencies.vue' });
2028
1886
  }
2029
- if (deps['@builder.io/qwik-city']) {
2030
- confidence += 20;
2031
- sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik-city' });
1887
+ if (deps['@vue/cli-service']) {
1888
+ confidence += 15;
1889
+ sources.push({ type: 'package.json', field: 'dependencies.@vue/cli-service' });
2032
1890
  }
2033
- if (exists(node_path.join(projectPath, 'qwik.config.ts')) || exists(node_path.join(projectPath, 'qwik.config.js'))) {
1891
+ const hasVueFiles = exists(node_path.join(projectPath, 'src', 'App.vue')) || exists(node_path.join(projectPath, 'src', 'main.vue'));
1892
+ if (hasVueFiles) {
2034
1893
  confidence += 10;
2035
- sources.push({ type: 'config-file', path: 'qwik.config.*' });
2036
- }
2037
- if (confidence === 0) {
2038
- return null;
2039
- }
2040
- return {
2041
- id: 'qwik',
2042
- name: 'Qwik',
2043
- category: 'frontend',
2044
- version,
2045
- confidence: min(confidence, 100),
2046
- detectedFrom: sources,
2047
- };
2048
- }
2049
-
2050
- /**
2051
- * Detect Astro in project.
2052
- *
2053
- * @param projectPath - Project directory path
2054
- * @param packageJson - Optional pre-loaded package.json
2055
- * @returns Detection result or null if not detected
2056
- */
2057
- function astroDetector(projectPath, packageJson) {
2058
- const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2059
- const sources = [];
2060
- let confidence = 0;
2061
- let version;
2062
- const deps = collectAllDependencies(pkg);
2063
- if (deps['astro']) {
2064
- confidence += 70;
2065
- version = parseVersionString(deps['astro']);
2066
- sources.push({ type: 'package.json', field: 'dependencies.astro' });
2067
- }
2068
- if (exists(node_path.join(projectPath, 'astro.config.mjs')) ||
2069
- exists(node_path.join(projectPath, 'astro.config.ts')) ||
2070
- exists(node_path.join(projectPath, 'astro.config.js'))) {
2071
- confidence += 25;
2072
- sources.push({ type: 'config-file', path: 'astro.config.*' });
1894
+ sources.push({ type: 'directory', path: 'src/*.vue' });
2073
1895
  }
2074
- if (exists(node_path.join(projectPath, 'src', 'pages'))) {
1896
+ if (exists(node_path.join(projectPath, 'vue.config.js'))) {
2075
1897
  confidence += 5;
2076
- sources.push({ type: 'directory', path: 'src/pages/' });
1898
+ sources.push({ type: 'config-file', path: 'vue.config.js' });
1899
+ }
1900
+ if (deps['nuxt'] || deps['nuxt3']) {
1901
+ metaFrameworks.push({
1902
+ id: 'nuxt',
1903
+ name: 'Nuxt',
1904
+ category: 'meta-framework',
1905
+ version: parseVersionString(deps['nuxt'] ?? deps['nuxt3']),
1906
+ confidence: 90,
1907
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.nuxt' }],
1908
+ });
2077
1909
  }
2078
1910
  if (confidence === 0) {
2079
1911
  return null;
2080
1912
  }
2081
1913
  return {
2082
- id: 'astro',
2083
- name: 'Astro',
2084
- category: 'meta-framework',
1914
+ id: 'vue',
1915
+ name: 'Vue',
1916
+ category: 'frontend',
2085
1917
  version,
2086
- confidence: min(confidence, 100),
1918
+ confidence: index_cjs_js$8.min(confidence, 100),
2087
1919
  detectedFrom: sources,
1920
+ metaFrameworks: metaFrameworks.length > 0 ? metaFrameworks : undefined,
2088
1921
  };
2089
1922
  }
2090
1923
 
@@ -2111,6 +1944,14 @@ const frameworkDetectors = [
2111
1944
  * @param projectPath - Project directory path
2112
1945
  * @param packageJson - Optional pre-loaded package.json
2113
1946
  * @returns Detection result or null if not detected
1947
+ *
1948
+ * @example Detecting AngularJS framework
1949
+ * ```typescript
1950
+ * const result = angularJSDetector('/path/to/project', {
1951
+ * dependencies: { angular: '^1.8.0', 'angular-route': '^1.8.0' },
1952
+ * })
1953
+ * // => { id: 'angularjs', name: 'AngularJS', confidence: 85, version: '1.8.0', ... }
1954
+ * ```
2114
1955
  */
2115
1956
  function angularJSDetector(projectPath, packageJson) {
2116
1957
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2143,7 +1984,7 @@ function angularJSDetector(projectPath, packageJson) {
2143
1984
  name: 'AngularJS',
2144
1985
  category: 'legacy-frontend',
2145
1986
  version,
2146
- confidence: min(confidence, 100),
1987
+ confidence: index_cjs_js$8.min(confidence, 100),
2147
1988
  detectedFrom: sources,
2148
1989
  };
2149
1990
  }
@@ -2154,6 +1995,14 @@ function angularJSDetector(projectPath, packageJson) {
2154
1995
  * @param projectPath - Project directory path
2155
1996
  * @param packageJson - Optional pre-loaded package.json
2156
1997
  * @returns Detection result or null if not detected
1998
+ *
1999
+ * @example Detecting Backbone.js framework
2000
+ * ```typescript
2001
+ * const result = backboneDetector('/path/to/project', {
2002
+ * dependencies: { backbone: '^1.4.0', underscore: '^1.13.0' },
2003
+ * })
2004
+ * // => { id: 'backbone', name: 'Backbone.js', confidence: 85, version: '1.4.0', ... }
2005
+ * ```
2157
2006
  */
2158
2007
  function backboneDetector(projectPath, packageJson) {
2159
2008
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2186,7 +2035,7 @@ function backboneDetector(projectPath, packageJson) {
2186
2035
  name: 'Backbone.js',
2187
2036
  category: 'legacy-frontend',
2188
2037
  version,
2189
- confidence: min(confidence, 100),
2038
+ confidence: index_cjs_js$8.min(confidence, 100),
2190
2039
  detectedFrom: sources,
2191
2040
  };
2192
2041
  }
@@ -2197,6 +2046,15 @@ function backboneDetector(projectPath, packageJson) {
2197
2046
  * @param projectPath - Project directory path
2198
2047
  * @param packageJson - Optional pre-loaded package.json
2199
2048
  * @returns Detection result or null if not detected
2049
+ *
2050
+ * @example Detecting Ember.js framework
2051
+ * ```typescript
2052
+ * const result = emberDetector('/path/to/project', {
2053
+ * dependencies: { 'ember-source': '^4.0.0' },
2054
+ * devDependencies: { 'ember-cli': '^4.0.0' },
2055
+ * })
2056
+ * // => { id: 'ember', name: 'Ember.js', confidence: 90, version: '4.0.0', ... }
2057
+ * ```
2200
2058
  */
2201
2059
  function emberDetector(projectPath, packageJson) {
2202
2060
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2225,7 +2083,7 @@ function emberDetector(projectPath, packageJson) {
2225
2083
  name: 'Ember.js',
2226
2084
  category: 'legacy-frontend',
2227
2085
  version,
2228
- confidence: min(confidence, 100),
2086
+ confidence: index_cjs_js$8.min(confidence, 100),
2229
2087
  detectedFrom: sources,
2230
2088
  };
2231
2089
  }
@@ -2236,47 +2094,105 @@ function emberDetector(projectPath, packageJson) {
2236
2094
  * @param projectPath - Project directory path
2237
2095
  * @param packageJson - Optional pre-loaded package.json
2238
2096
  * @returns Detection result or null if not detected
2097
+ *
2098
+ * @example Detecting jQuery library
2099
+ * ```typescript
2100
+ * const result = jqueryDetector('/path/to/project', {
2101
+ * dependencies: { jquery: '^3.6.0', 'jquery-ui': '^1.13.0' },
2102
+ * })
2103
+ * // => { id: 'jquery', name: 'jQuery', confidence: 90, version: '3.6.0', ... }
2104
+ * ```
2105
+ */
2106
+ function jqueryDetector(projectPath, packageJson) {
2107
+ const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2108
+ const sources = [];
2109
+ let confidence = 0;
2110
+ let version;
2111
+ const deps = collectAllDependencies(pkg);
2112
+ if (deps['jquery']) {
2113
+ confidence += 80;
2114
+ version = parseVersionString(deps['jquery']);
2115
+ sources.push({ type: 'package.json', field: 'dependencies.jquery' });
2116
+ }
2117
+ if (deps['jquery-ui']) {
2118
+ confidence += 10;
2119
+ sources.push({ type: 'package.json', field: 'dependencies.jquery-ui' });
2120
+ }
2121
+ if (deps['jquery-validation']) {
2122
+ confidence += 5;
2123
+ sources.push({ type: 'package.json', field: 'dependencies.jquery-validation' });
2124
+ }
2125
+ if (confidence === 0) {
2126
+ return null;
2127
+ }
2128
+ return {
2129
+ id: 'jquery',
2130
+ name: 'jQuery',
2131
+ category: 'legacy-frontend',
2132
+ version,
2133
+ confidence: index_cjs_js$8.min(confidence, 100),
2134
+ detectedFrom: sources,
2135
+ };
2136
+ }
2137
+
2138
+ /** All legacy framework detectors */
2139
+ const legacyDetectors = [
2140
+ { id: 'angularjs', name: 'AngularJS', category: 'legacy-frontend', detect: angularJSDetector },
2141
+ { id: 'backbone', name: 'Backbone.js', category: 'legacy-frontend', detect: backboneDetector },
2142
+ { id: 'ember', name: 'Ember.js', category: 'legacy-frontend', detect: emberDetector },
2143
+ { id: 'jquery', name: 'jQuery', category: 'legacy-frontend', detect: jqueryDetector },
2144
+ ];
2145
+
2146
+ /**
2147
+ * Detect Biome in project.
2148
+ *
2149
+ * @param projectPath - Project directory path
2150
+ * @param packageJson - Optional pre-loaded package.json
2151
+ * @returns Detection result or null if not detected
2152
+ *
2153
+ * @example Detecting Biome linter
2154
+ * ```typescript
2155
+ * const result = biomeDetector('/path/to/project', {
2156
+ * devDependencies: { '@biomejs/biome': '^1.5.0' },
2157
+ * })
2158
+ * // => { id: 'biome', name: 'Biome', confidence: 70, version: '1.5.0', ... }
2159
+ * ```
2239
2160
  */
2240
- function jqueryDetector(projectPath, packageJson) {
2161
+ function biomeDetector(projectPath, packageJson) {
2241
2162
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2242
2163
  const sources = [];
2243
2164
  let confidence = 0;
2165
+ let configPath;
2244
2166
  let version;
2245
2167
  const deps = collectAllDependencies(pkg);
2246
- if (deps['jquery']) {
2247
- confidence += 80;
2248
- version = parseVersionString(deps['jquery']);
2249
- sources.push({ type: 'package.json', field: 'dependencies.jquery' });
2168
+ if (deps['@biomejs/biome']) {
2169
+ confidence += 70;
2170
+ version = parseVersionString(deps['@biomejs/biome']);
2171
+ sources.push({ type: 'package.json', field: 'dependencies.@biomejs/biome' });
2250
2172
  }
2251
- if (deps['jquery-ui']) {
2252
- confidence += 10;
2253
- sources.push({ type: 'package.json', field: 'dependencies.jquery-ui' });
2173
+ if (exists(node_path.join(projectPath, 'biome.json'))) {
2174
+ confidence += 30;
2175
+ configPath = 'biome.json';
2176
+ sources.push({ type: 'config-file', path: 'biome.json' });
2254
2177
  }
2255
- if (deps['jquery-validation']) {
2256
- confidence += 5;
2257
- sources.push({ type: 'package.json', field: 'dependencies.jquery-validation' });
2178
+ if (!configPath && exists(node_path.join(projectPath, 'biome.jsonc'))) {
2179
+ confidence += 30;
2180
+ configPath = 'biome.jsonc';
2181
+ sources.push({ type: 'config-file', path: 'biome.jsonc' });
2258
2182
  }
2259
2183
  if (confidence === 0) {
2260
2184
  return null;
2261
2185
  }
2262
2186
  return {
2263
- id: 'jquery',
2264
- name: 'jQuery',
2265
- category: 'legacy-frontend',
2187
+ id: 'biome',
2188
+ name: 'Biome',
2266
2189
  version,
2267
- confidence: min(confidence, 100),
2190
+ configPath,
2191
+ confidence: index_cjs_js$8.min(confidence, 100),
2268
2192
  detectedFrom: sources,
2269
2193
  };
2270
2194
  }
2271
2195
 
2272
- /** All legacy framework detectors */
2273
- const legacyDetectors = [
2274
- { id: 'angularjs', name: 'AngularJS', category: 'legacy-frontend', detect: angularJSDetector },
2275
- { id: 'backbone', name: 'Backbone.js', category: 'legacy-frontend', detect: backboneDetector },
2276
- { id: 'ember', name: 'Ember.js', category: 'legacy-frontend', detect: emberDetector },
2277
- { id: 'jquery', name: 'jQuery', category: 'legacy-frontend', detect: jqueryDetector },
2278
- ];
2279
-
2280
2196
  /** Config patterns for ESLint */
2281
2197
  const ESLINT_CONFIG_PATTERNS = [
2282
2198
  'eslint.config.js',
@@ -2296,6 +2212,15 @@ const ESLINT_CONFIG_PATTERNS = [
2296
2212
  * @param projectPath - Project directory path
2297
2213
  * @param packageJson - Optional pre-loaded package.json
2298
2214
  * @returns Detection result or null if not detected
2215
+ *
2216
+ * @example Detecting ESLint linter
2217
+ * ```typescript
2218
+ * const result = eslintDetector('/path/to/project', {
2219
+ * devDependencies: { eslint: '^8.50.0', '@typescript-eslint/parser': '^6.0.0' },
2220
+ * scripts: { lint: 'eslint src/' },
2221
+ * })
2222
+ * // => { id: 'eslint', name: 'ESLint', confidence: 65, version: '8.50.0', ... }
2223
+ * ```
2299
2224
  */
2300
2225
  function eslintDetector(projectPath, packageJson) {
2301
2226
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2317,7 +2242,7 @@ function eslintDetector(projectPath, packageJson) {
2317
2242
  confidence += 30;
2318
2243
  sources.push({ type: 'package.json', field: 'eslintConfig' });
2319
2244
  }
2320
- const eslintPlugins = keys(deps).filter((d) => d.startsWith('eslint-plugin-') || d.startsWith('@typescript-eslint/') || d.startsWith('eslint-config-'));
2245
+ const eslintPlugins = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('eslint-plugin-') || d.startsWith('@typescript-eslint/') || d.startsWith('eslint-config-'));
2321
2246
  if (eslintPlugins.length > 0) {
2322
2247
  confidence += 10;
2323
2248
  sources.push({ type: 'package.json', field: 'dependencies (eslint plugins)' });
@@ -2335,7 +2260,7 @@ function eslintDetector(projectPath, packageJson) {
2335
2260
  name: 'ESLint',
2336
2261
  version,
2337
2262
  configPath,
2338
- confidence: min(confidence, 100),
2263
+ confidence: index_cjs_js$8.min(confidence, 100),
2339
2264
  detectedFrom: sources,
2340
2265
  };
2341
2266
  }
@@ -2359,6 +2284,15 @@ const PRETTIER_CONFIG_PATTERNS = [
2359
2284
  * @param projectPath - Project directory path
2360
2285
  * @param packageJson - Optional pre-loaded package.json
2361
2286
  * @returns Detection result or null if not detected
2287
+ *
2288
+ * @example Detecting Prettier formatter
2289
+ * ```typescript
2290
+ * const result = prettierDetector('/path/to/project', {
2291
+ * devDependencies: { prettier: '^3.0.0' },
2292
+ * scripts: { format: 'prettier --write .' },
2293
+ * })
2294
+ * // => { id: 'prettier', name: 'Prettier', confidence: 55, version: '3.0.0', ... }
2295
+ * ```
2362
2296
  */
2363
2297
  function prettierDetector(projectPath, packageJson) {
2364
2298
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2384,7 +2318,7 @@ function prettierDetector(projectPath, packageJson) {
2384
2318
  confidence += 10;
2385
2319
  sources.push({ type: 'config-file', path: '.prettierignore' });
2386
2320
  }
2387
- const prettierPlugins = keys(deps).filter((d) => d.startsWith('prettier-plugin-'));
2321
+ const prettierPlugins = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('prettier-plugin-'));
2388
2322
  if (prettierPlugins.length > 0) {
2389
2323
  confidence += 5;
2390
2324
  sources.push({ type: 'package.json', field: 'dependencies (prettier plugins)' });
@@ -2402,7 +2336,7 @@ function prettierDetector(projectPath, packageJson) {
2402
2336
  name: 'Prettier',
2403
2337
  version,
2404
2338
  configPath,
2405
- confidence: min(confidence, 100),
2339
+ confidence: index_cjs_js$8.min(confidence, 100),
2406
2340
  detectedFrom: sources,
2407
2341
  };
2408
2342
  }
@@ -2421,6 +2355,14 @@ const STYLELINT_CONFIG_PATTERNS = [
2421
2355
  * @param projectPath - Project directory path
2422
2356
  * @param packageJson - Optional pre-loaded package.json
2423
2357
  * @returns Detection result or null if not detected
2358
+ *
2359
+ * @example Detecting Stylelint linter
2360
+ * ```typescript
2361
+ * const result = stylelintDetector('/path/to/project', {
2362
+ * devDependencies: { stylelint: '^15.0.0', 'stylelint-config-standard': '^30.0.0' },
2363
+ * })
2364
+ * // => { id: 'stylelint', name: 'Stylelint', confidence: 65, version: '15.0.0', ... }
2365
+ * ```
2424
2366
  */
2425
2367
  function stylelintDetector(projectPath, packageJson) {
2426
2368
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2442,7 +2384,7 @@ function stylelintDetector(projectPath, packageJson) {
2442
2384
  break;
2443
2385
  }
2444
2386
  }
2445
- const stylelintPlugins = keys(deps).filter((d) => d.startsWith('stylelint-'));
2387
+ const stylelintPlugins = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('stylelint-'));
2446
2388
  if (stylelintPlugins.length > 0) {
2447
2389
  confidence += 5;
2448
2390
  sources.push({ type: 'package.json', field: 'dependencies (stylelint plugins)' });
@@ -2455,49 +2397,7 @@ function stylelintDetector(projectPath, packageJson) {
2455
2397
  name: 'Stylelint',
2456
2398
  version,
2457
2399
  configPath,
2458
- confidence: min(confidence, 100),
2459
- detectedFrom: sources,
2460
- };
2461
- }
2462
-
2463
- /**
2464
- * Detect Biome in project.
2465
- *
2466
- * @param projectPath - Project directory path
2467
- * @param packageJson - Optional pre-loaded package.json
2468
- * @returns Detection result or null if not detected
2469
- */
2470
- function biomeDetector(projectPath, packageJson) {
2471
- const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2472
- const sources = [];
2473
- let confidence = 0;
2474
- let configPath;
2475
- let version;
2476
- const deps = collectAllDependencies(pkg);
2477
- if (deps['@biomejs/biome']) {
2478
- confidence += 70;
2479
- version = parseVersionString(deps['@biomejs/biome']);
2480
- sources.push({ type: 'package.json', field: 'dependencies.@biomejs/biome' });
2481
- }
2482
- if (exists(node_path.join(projectPath, 'biome.json'))) {
2483
- confidence += 30;
2484
- configPath = 'biome.json';
2485
- sources.push({ type: 'config-file', path: 'biome.json' });
2486
- }
2487
- if (!configPath && exists(node_path.join(projectPath, 'biome.jsonc'))) {
2488
- confidence += 30;
2489
- configPath = 'biome.jsonc';
2490
- sources.push({ type: 'config-file', path: 'biome.jsonc' });
2491
- }
2492
- if (confidence === 0) {
2493
- return null;
2494
- }
2495
- return {
2496
- id: 'biome',
2497
- name: 'Biome',
2498
- version,
2499
- configPath,
2500
- confidence: min(confidence, 100),
2400
+ confidence: index_cjs_js$8.min(confidence, 100),
2501
2401
  detectedFrom: sources,
2502
2402
  };
2503
2403
  }
@@ -2511,140 +2411,179 @@ const lintingDetectors = [
2511
2411
  ];
2512
2412
 
2513
2413
  /**
2514
- * Detect NX in project.
2414
+ * Detect Lerna in project.
2515
2415
  *
2516
2416
  * @param workspacePath - Workspace directory path
2517
2417
  * @param packageJson - Optional pre-loaded package.json
2518
2418
  * @returns Detection result or null if not detected
2419
+ *
2420
+ * @example Detecting Lerna monorepo
2421
+ * ```typescript
2422
+ * // Project with lerna.json config file
2423
+ * const result = lernaDetector('/path/to/lerna-project')
2424
+ * // => {
2425
+ * // id: 'lerna',
2426
+ * // name: 'Lerna',
2427
+ * // confidence: 80,
2428
+ * // configPath: 'lerna.json',
2429
+ * // detectedFrom: [{ type: 'config-file', path: 'lerna.json' }]
2430
+ * // }
2431
+ * ```
2519
2432
  */
2520
- function nxDetector(workspacePath, packageJson) {
2433
+ function lernaDetector(workspacePath, packageJson) {
2521
2434
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
2522
2435
  const sources = [];
2523
2436
  let confidence = 0;
2524
2437
  let version;
2525
- let workspaceLayout;
2526
- const nxJsonPath = node_path.join(workspacePath, 'nx.json');
2527
- if (exists(nxJsonPath)) {
2528
- confidence += 70;
2529
- sources.push({ type: 'config-file', path: 'nx.json' });
2438
+ let configPath;
2439
+ const lernaJsonPath = node_path.join(workspacePath, 'lerna.json');
2440
+ if (exists(lernaJsonPath)) {
2441
+ confidence += 80;
2442
+ configPath = 'lerna.json';
2443
+ sources.push({ type: 'config-file', path: 'lerna.json' });
2530
2444
  }
2531
2445
  const deps = collectAllDependencies(pkg);
2532
- if (deps['nx']) {
2533
- confidence += 20;
2534
- version = parseVersionString(deps['nx']);
2535
- sources.push({ type: 'package.json', field: 'dependencies.nx' });
2536
- }
2537
- const hasApps = exists(node_path.join(workspacePath, 'apps'));
2538
- const hasLibs = exists(node_path.join(workspacePath, 'libs'));
2539
- if (hasApps || hasLibs) {
2540
- confidence += 10;
2541
- sources.push({ type: 'directory', path: 'apps/ or libs/' });
2542
- workspaceLayout = {
2543
- appsDir: hasApps ? 'apps' : '',
2544
- libsDir: hasLibs ? 'libs' : '',
2545
- };
2446
+ if (deps['lerna']) {
2447
+ confidence += 15;
2448
+ version = parseVersionString(deps['lerna']);
2449
+ sources.push({ type: 'package.json', field: 'dependencies.lerna' });
2546
2450
  }
2547
- const nxPackages = keys(deps).filter((d) => d.startsWith('@nx/') || d.startsWith('@nrwl/'));
2548
- if (nxPackages.length > 0) {
2549
- confidence += 10;
2550
- sources.push({ type: 'package.json', field: '@nx/* packages' });
2451
+ if (exists(node_path.join(workspacePath, 'packages'))) {
2452
+ confidence += 5;
2453
+ sources.push({ type: 'directory', path: 'packages/' });
2551
2454
  }
2552
2455
  if (confidence === 0) {
2553
2456
  return null;
2554
2457
  }
2555
2458
  return {
2556
- id: 'nx',
2557
- name: 'NX',
2459
+ id: 'lerna',
2460
+ name: 'Lerna',
2558
2461
  version,
2559
- configPath: exists(nxJsonPath) ? 'nx.json' : undefined,
2560
- confidence: min(confidence, 100),
2462
+ configPath,
2463
+ confidence: index_cjs_js$8.min(confidence, 100),
2561
2464
  detectedFrom: sources,
2562
- workspaceLayout,
2563
2465
  };
2564
2466
  }
2565
2467
 
2566
2468
  /**
2567
- * Detect Turborepo in project.
2469
+ * Detect npm workspaces in project.
2568
2470
  *
2569
2471
  * @param workspacePath - Workspace directory path
2570
2472
  * @param packageJson - Optional pre-loaded package.json
2571
2473
  * @returns Detection result or null if not detected
2474
+ *
2475
+ * @example Detecting npm workspaces
2476
+ * ```typescript
2477
+ * // Project with workspaces in package.json and package-lock.json
2478
+ * const result = npmWorkspacesDetector('/path/to/npm-project')
2479
+ * // => {
2480
+ * // id: 'npm-workspaces',
2481
+ * // name: 'npm Workspaces',
2482
+ * // confidence: 90,
2483
+ * // configPath: 'package.json',
2484
+ * // detectedFrom: [
2485
+ * // { type: 'package.json', field: 'workspaces' },
2486
+ * // { type: 'lockfile', path: 'package-lock.json' }
2487
+ * // ]
2488
+ * // }
2489
+ * ```
2572
2490
  */
2573
- function turborepoDetector(workspacePath, packageJson) {
2491
+ function npmWorkspacesDetector(workspacePath, packageJson) {
2574
2492
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
2575
2493
  const sources = [];
2576
2494
  let confidence = 0;
2577
- let version;
2578
- let configPath;
2579
- const turboJsonPath = node_path.join(workspacePath, 'turbo.json');
2580
- if (exists(turboJsonPath)) {
2495
+ if (pkg?.workspaces) {
2581
2496
  confidence += 80;
2582
- configPath = 'turbo.json';
2583
- sources.push({ type: 'config-file', path: 'turbo.json' });
2497
+ sources.push({ type: 'package.json', field: 'workspaces' });
2584
2498
  }
2585
- const deps = collectAllDependencies(pkg);
2586
- if (deps['turbo']) {
2587
- confidence += 15;
2588
- version = parseVersionString(deps['turbo']);
2589
- sources.push({ type: 'package.json', field: 'dependencies.turbo' });
2499
+ if (exists(node_path.join(workspacePath, 'package-lock.json'))) {
2500
+ confidence += 10;
2501
+ sources.push({ type: 'lockfile', path: 'package-lock.json' });
2590
2502
  }
2591
- const scripts = pkg?.scripts ?? {};
2592
- if (values(scripts).some((s) => s?.includes('turbo'))) {
2593
- confidence += 5;
2594
- sources.push({ type: 'package.json', field: 'scripts (turbo commands)' });
2503
+ if (exists(node_path.join(workspacePath, 'yarn.lock'))) {
2504
+ return null;
2595
2505
  }
2596
2506
  if (confidence === 0) {
2597
2507
  return null;
2598
2508
  }
2599
2509
  return {
2600
- id: 'turborepo',
2601
- name: 'Turborepo',
2602
- version,
2603
- configPath,
2604
- confidence: min(confidence, 100),
2510
+ id: 'npm-workspaces',
2511
+ name: 'npm Workspaces',
2512
+ configPath: 'package.json',
2513
+ confidence: index_cjs_js$8.min(confidence, 100),
2605
2514
  detectedFrom: sources,
2606
2515
  };
2607
2516
  }
2608
2517
 
2609
2518
  /**
2610
- * Detect Lerna in project.
2519
+ * Detect NX in project.
2611
2520
  *
2612
2521
  * @param workspacePath - Workspace directory path
2613
2522
  * @param packageJson - Optional pre-loaded package.json
2614
2523
  * @returns Detection result or null if not detected
2524
+ *
2525
+ * @example Detecting NX workspace
2526
+ * ```typescript
2527
+ * // Project with nx.json and apps/libs directories
2528
+ * const result = nxDetector('/path/to/nx-workspace')
2529
+ * // => {
2530
+ * // id: 'nx',
2531
+ * // name: 'NX',
2532
+ * // confidence: 100,
2533
+ * // configPath: 'nx.json',
2534
+ * // version: '17.0.0',
2535
+ * // workspaceLayout: { appsDir: 'apps', libsDir: 'libs' },
2536
+ * // detectedFrom: [
2537
+ * // { type: 'config-file', path: 'nx.json' },
2538
+ * // { type: 'package.json', field: 'dependencies.nx' },
2539
+ * // { type: 'directory', path: 'apps/ or libs/' }
2540
+ * // ]
2541
+ * // }
2542
+ * ```
2615
2543
  */
2616
- function lernaDetector(workspacePath, packageJson) {
2544
+ function nxDetector(workspacePath, packageJson) {
2617
2545
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
2618
2546
  const sources = [];
2619
2547
  let confidence = 0;
2620
2548
  let version;
2621
- let configPath;
2622
- const lernaJsonPath = node_path.join(workspacePath, 'lerna.json');
2623
- if (exists(lernaJsonPath)) {
2624
- confidence += 80;
2625
- configPath = 'lerna.json';
2626
- sources.push({ type: 'config-file', path: 'lerna.json' });
2549
+ let workspaceLayout;
2550
+ const nxJsonPath = node_path.join(workspacePath, 'nx.json');
2551
+ if (exists(nxJsonPath)) {
2552
+ confidence += 70;
2553
+ sources.push({ type: 'config-file', path: 'nx.json' });
2627
2554
  }
2628
2555
  const deps = collectAllDependencies(pkg);
2629
- if (deps['lerna']) {
2630
- confidence += 15;
2631
- version = parseVersionString(deps['lerna']);
2632
- sources.push({ type: 'package.json', field: 'dependencies.lerna' });
2556
+ if (deps['nx']) {
2557
+ confidence += 20;
2558
+ version = parseVersionString(deps['nx']);
2559
+ sources.push({ type: 'package.json', field: 'dependencies.nx' });
2633
2560
  }
2634
- if (exists(node_path.join(workspacePath, 'packages'))) {
2635
- confidence += 5;
2636
- sources.push({ type: 'directory', path: 'packages/' });
2561
+ const hasApps = exists(node_path.join(workspacePath, 'apps'));
2562
+ const hasLibs = exists(node_path.join(workspacePath, 'libs'));
2563
+ if (hasApps || hasLibs) {
2564
+ confidence += 10;
2565
+ sources.push({ type: 'directory', path: 'apps/ or libs/' });
2566
+ workspaceLayout = {
2567
+ appsDir: hasApps ? 'apps' : '',
2568
+ libsDir: hasLibs ? 'libs' : '',
2569
+ };
2570
+ }
2571
+ const nxPackages = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('@nx/') || d.startsWith('@nrwl/'));
2572
+ if (nxPackages.length > 0) {
2573
+ confidence += 10;
2574
+ sources.push({ type: 'package.json', field: '@nx/* packages' });
2637
2575
  }
2638
2576
  if (confidence === 0) {
2639
2577
  return null;
2640
2578
  }
2641
2579
  return {
2642
- id: 'lerna',
2643
- name: 'Lerna',
2580
+ id: 'nx',
2581
+ name: 'NX',
2644
2582
  version,
2645
- configPath,
2646
- confidence: min(confidence, 100),
2583
+ configPath: exists(nxJsonPath) ? 'nx.json' : undefined,
2584
+ confidence: index_cjs_js$8.min(confidence, 100),
2647
2585
  detectedFrom: sources,
2586
+ workspaceLayout,
2648
2587
  };
2649
2588
  }
2650
2589
 
@@ -2654,6 +2593,19 @@ function lernaDetector(workspacePath, packageJson) {
2654
2593
  * @param workspacePath - Workspace directory path
2655
2594
  * @param packageJson - Optional pre-loaded package.json
2656
2595
  * @returns Detection result or null if not detected
2596
+ *
2597
+ * @example Detecting Rush monorepo
2598
+ * ```typescript
2599
+ * // Project with rush.json config file
2600
+ * const result = rushDetector('/path/to/rush-project')
2601
+ * // => {
2602
+ * // id: 'rush',
2603
+ * // name: 'Rush',
2604
+ * // confidence: 90,
2605
+ * // configPath: 'rush.json',
2606
+ * // detectedFrom: [{ type: 'config-file', path: 'rush.json' }]
2607
+ * // }
2608
+ * ```
2657
2609
  */
2658
2610
  function rushDetector(workspacePath, packageJson) {
2659
2611
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
@@ -2682,76 +2634,70 @@ function rushDetector(workspacePath, packageJson) {
2682
2634
  }
2683
2635
  return {
2684
2636
  id: 'rush',
2685
- name: 'Rush',
2686
- version,
2687
- configPath,
2688
- confidence: min(confidence, 100),
2689
- detectedFrom: sources,
2690
- };
2691
- }
2692
-
2693
- /**
2694
- * Detect pnpm workspaces in project.
2695
- *
2696
- * @param workspacePath - Workspace directory path
2697
- * @returns Detection result or null if not detected
2698
- */
2699
- function pnpmWorkspacesDetector(workspacePath) {
2700
- const sources = [];
2701
- let confidence = 0;
2702
- let configPath;
2703
- const pnpmWorkspacePath = node_path.join(workspacePath, 'pnpm-workspace.yaml');
2704
- if (exists(pnpmWorkspacePath)) {
2705
- confidence += 90;
2706
- configPath = 'pnpm-workspace.yaml';
2707
- sources.push({ type: 'config-file', path: 'pnpm-workspace.yaml' });
2708
- }
2709
- if (exists(node_path.join(workspacePath, 'pnpm-lock.yaml'))) {
2710
- confidence += 10;
2711
- sources.push({ type: 'lockfile', path: 'pnpm-lock.yaml' });
2712
- }
2713
- if (confidence === 0) {
2714
- return null;
2715
- }
2716
- return {
2717
- id: 'pnpm-workspaces',
2718
- name: 'pnpm Workspaces',
2637
+ name: 'Rush',
2638
+ version,
2719
2639
  configPath,
2720
- confidence: min(confidence, 100),
2640
+ confidence: index_cjs_js$8.min(confidence, 100),
2721
2641
  detectedFrom: sources,
2722
2642
  };
2723
2643
  }
2724
2644
 
2725
2645
  /**
2726
- * Detect npm workspaces in project.
2646
+ * Detect Turborepo in project.
2727
2647
  *
2728
2648
  * @param workspacePath - Workspace directory path
2729
2649
  * @param packageJson - Optional pre-loaded package.json
2730
2650
  * @returns Detection result or null if not detected
2651
+ *
2652
+ * @example Detecting Turborepo monorepo
2653
+ * ```typescript
2654
+ * // Project with turbo.json and turbo dependency
2655
+ * const result = turborepoDetector('/path/to/turbo-project')
2656
+ * // => {
2657
+ * // id: 'turborepo',
2658
+ * // name: 'Turborepo',
2659
+ * // confidence: 95,
2660
+ * // configPath: 'turbo.json',
2661
+ * // version: '2.0.0',
2662
+ * // detectedFrom: [
2663
+ * // { type: 'config-file', path: 'turbo.json' },
2664
+ * // { type: 'package.json', field: 'dependencies.turbo' }
2665
+ * // ]
2666
+ * // }
2667
+ * ```
2731
2668
  */
2732
- function npmWorkspacesDetector(workspacePath, packageJson) {
2669
+ function turborepoDetector(workspacePath, packageJson) {
2733
2670
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
2734
2671
  const sources = [];
2735
2672
  let confidence = 0;
2736
- if (pkg?.workspaces) {
2673
+ let version;
2674
+ let configPath;
2675
+ const turboJsonPath = node_path.join(workspacePath, 'turbo.json');
2676
+ if (exists(turboJsonPath)) {
2737
2677
  confidence += 80;
2738
- sources.push({ type: 'package.json', field: 'workspaces' });
2678
+ configPath = 'turbo.json';
2679
+ sources.push({ type: 'config-file', path: 'turbo.json' });
2739
2680
  }
2740
- if (exists(node_path.join(workspacePath, 'package-lock.json'))) {
2741
- confidence += 10;
2742
- sources.push({ type: 'lockfile', path: 'package-lock.json' });
2681
+ const deps = collectAllDependencies(pkg);
2682
+ if (deps['turbo']) {
2683
+ confidence += 15;
2684
+ version = parseVersionString(deps['turbo']);
2685
+ sources.push({ type: 'package.json', field: 'dependencies.turbo' });
2743
2686
  }
2744
- if (exists(node_path.join(workspacePath, 'yarn.lock'))) {
2745
- return null;
2687
+ const scripts = pkg?.scripts ?? {};
2688
+ if (index_cjs_js$2.values(scripts).some((s) => s?.includes('turbo'))) {
2689
+ confidence += 5;
2690
+ sources.push({ type: 'package.json', field: 'scripts (turbo commands)' });
2746
2691
  }
2747
2692
  if (confidence === 0) {
2748
2693
  return null;
2749
2694
  }
2750
2695
  return {
2751
- id: 'npm-workspaces',
2752
- name: 'npm Workspaces',
2753
- configPath: 'package.json',
2754
- confidence: min(confidence, 100),
2696
+ id: 'turborepo',
2697
+ name: 'Turborepo',
2698
+ version,
2699
+ configPath,
2700
+ confidence: index_cjs_js$8.min(confidence, 100),
2755
2701
  detectedFrom: sources,
2756
2702
  };
2757
2703
  }
@@ -2762,6 +2708,23 @@ function npmWorkspacesDetector(workspacePath, packageJson) {
2762
2708
  * @param workspacePath - Workspace directory path
2763
2709
  * @param packageJson - Optional pre-loaded package.json
2764
2710
  * @returns Detection result or null if not detected
2711
+ *
2712
+ * @example Detecting yarn workspaces
2713
+ * ```typescript
2714
+ * // Project with workspaces in package.json and yarn.lock
2715
+ * const result = yarnWorkspacesDetector('/path/to/yarn-project')
2716
+ * // => {
2717
+ * // id: 'yarn-workspaces',
2718
+ * // name: 'Yarn Workspaces',
2719
+ * // confidence: 100,
2720
+ * // configPath: 'package.json',
2721
+ * // detectedFrom: [
2722
+ * // { type: 'package.json', field: 'workspaces' },
2723
+ * // { type: 'lockfile', path: 'yarn.lock' },
2724
+ * // { type: 'config-file', path: '.yarnrc.yml' }
2725
+ * // ]
2726
+ * // }
2727
+ * ```
2765
2728
  */
2766
2729
  function yarnWorkspacesDetector(workspacePath, packageJson) {
2767
2730
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
@@ -2786,7 +2749,7 @@ function yarnWorkspacesDetector(workspacePath, packageJson) {
2786
2749
  id: 'yarn-workspaces',
2787
2750
  name: 'Yarn Workspaces',
2788
2751
  configPath: 'package.json',
2789
- confidence: min(confidence, 100),
2752
+ confidence: index_cjs_js$8.min(confidence, 100),
2790
2753
  detectedFrom: sources,
2791
2754
  };
2792
2755
  }
@@ -2802,111 +2765,129 @@ const monorepoDetectors = [
2802
2765
  { id: 'yarn-workspaces', name: 'Yarn Workspaces', detect: yarnWorkspacesDetector },
2803
2766
  ];
2804
2767
 
2805
- /** Config patterns for Jest */
2806
- const JEST_CONFIG_PATTERNS = ['jest.config.js', 'jest.config.ts', 'jest.config.mjs', 'jest.config.cjs', 'jest.config.json'];
2768
+ /** Config patterns for Cypress */
2769
+ const CYPRESS_CONFIG_PATTERNS = ['cypress.config.js', 'cypress.config.ts', 'cypress.config.mjs', 'cypress.json'];
2807
2770
  /**
2808
- * Detect Jest in project.
2771
+ * Detect Cypress in project.
2809
2772
  *
2810
2773
  * @param projectPath - Project directory path
2811
2774
  * @param packageJson - Optional pre-loaded package.json
2812
2775
  * @returns Detection result or null if not detected
2776
+ *
2777
+ * @example Detecting Cypress testing framework
2778
+ * ```typescript
2779
+ * import { cypressDetector } from '@hyperfrontend/project-scope'
2780
+ *
2781
+ * const result = cypressDetector('./my-project')
2782
+ * if (result) {
2783
+ * console.log(`Cypress ${result.version} detected (${result.confidence}% confidence)`)
2784
+ * // => "Cypress 13.6.0 detected (95% confidence)"
2785
+ * }
2786
+ * ```
2813
2787
  */
2814
- function jestDetector(projectPath, packageJson) {
2788
+ function cypressDetector(projectPath, packageJson) {
2815
2789
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2816
2790
  const sources = [];
2817
2791
  let confidence = 0;
2818
2792
  let version;
2819
2793
  const deps = collectAllDependencies(pkg);
2820
- if (deps['jest']) {
2794
+ if (deps['cypress']) {
2821
2795
  confidence += 60;
2822
- version = parseVersionString(deps['jest']);
2823
- sources.push({ type: 'package.json', field: 'dependencies.jest' });
2796
+ version = parseVersionString(deps['cypress']);
2797
+ sources.push({ type: 'package.json', field: 'dependencies.cypress' });
2824
2798
  }
2825
- const configPath = locateConfigFile(projectPath, JEST_CONFIG_PATTERNS);
2799
+ const configPath = locateConfigFile(projectPath, CYPRESS_CONFIG_PATTERNS);
2826
2800
  if (configPath) {
2827
2801
  confidence += 30;
2828
2802
  sources.push({ type: 'config-file', path: configPath });
2829
2803
  }
2830
- if (pkg && 'jest' in pkg) {
2831
- confidence += 20;
2832
- sources.push({ type: 'package.json', field: 'jest' });
2833
- }
2834
- const testScript = pkg?.scripts?.['test'] ?? '';
2835
- if (testScript.includes('jest')) {
2804
+ if (exists(node_path.join(projectPath, 'cypress'))) {
2836
2805
  confidence += 10;
2837
- sources.push({ type: 'package.json', field: 'scripts.test' });
2838
- }
2839
- if (deps['@types/jest']) {
2840
- confidence += 5;
2841
- sources.push({ type: 'package.json', field: 'dependencies.@types/jest' });
2806
+ sources.push({ type: 'directory', path: 'cypress/' });
2842
2807
  }
2843
- if (deps['ts-jest']) {
2808
+ const e2eScript = pkg?.scripts?.['e2e'] ?? pkg?.scripts?.['test:e2e'] ?? '';
2809
+ if (e2eScript.includes('cypress')) {
2844
2810
  confidence += 5;
2845
- sources.push({ type: 'package.json', field: 'dependencies.ts-jest' });
2811
+ sources.push({ type: 'package.json', field: 'scripts.e2e or scripts.test:e2e' });
2846
2812
  }
2847
2813
  if (confidence === 0) {
2848
2814
  return null;
2849
2815
  }
2850
2816
  return {
2851
- id: 'jest',
2852
- name: 'Jest',
2853
- type: 'unit',
2817
+ id: 'cypress',
2818
+ name: 'Cypress',
2819
+ type: 'e2e',
2854
2820
  version,
2855
2821
  configPath,
2856
- confidence: min(confidence, 100),
2822
+ confidence: index_cjs_js$8.min(confidence, 100),
2857
2823
  detectedFrom: sources,
2858
2824
  };
2859
2825
  }
2860
2826
 
2861
- /** Config patterns for Vitest */
2862
- const VITEST_CONFIG_PATTERNS = ['vitest.config.js', 'vitest.config.ts', 'vitest.config.mjs'];
2827
+ /** Config patterns for Jest */
2828
+ const JEST_CONFIG_PATTERNS = ['jest.config.js', 'jest.config.ts', 'jest.config.mjs', 'jest.config.cjs', 'jest.config.json'];
2863
2829
  /**
2864
- * Detect Vitest in project.
2830
+ * Detect Jest in project.
2865
2831
  *
2866
2832
  * @param projectPath - Project directory path
2867
2833
  * @param packageJson - Optional pre-loaded package.json
2868
2834
  * @returns Detection result or null if not detected
2835
+ *
2836
+ * @example Detecting Jest testing framework
2837
+ * ```typescript
2838
+ * import { jestDetector } from '@hyperfrontend/project-scope'
2839
+ *
2840
+ * const result = jestDetector('./my-project')
2841
+ * if (result) {
2842
+ * console.log(`Jest ${result.version} detected`)
2843
+ * console.log('Sources:', result.detectedFrom.map(s => s.type))
2844
+ * // => "Sources: ['package.json', 'config-file']"
2845
+ * }
2846
+ * ```
2869
2847
  */
2870
- function vitestDetector(projectPath, packageJson) {
2848
+ function jestDetector(projectPath, packageJson) {
2871
2849
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2872
2850
  const sources = [];
2873
2851
  let confidence = 0;
2874
2852
  let version;
2875
2853
  const deps = collectAllDependencies(pkg);
2876
- if (deps['vitest']) {
2877
- confidence += 70;
2878
- version = parseVersionString(deps['vitest']);
2879
- sources.push({ type: 'package.json', field: 'dependencies.vitest' });
2854
+ if (deps['jest']) {
2855
+ confidence += 60;
2856
+ version = parseVersionString(deps['jest']);
2857
+ sources.push({ type: 'package.json', field: 'dependencies.jest' });
2880
2858
  }
2881
- const configPath = locateConfigFile(projectPath, VITEST_CONFIG_PATTERNS);
2859
+ const configPath = locateConfigFile(projectPath, JEST_CONFIG_PATTERNS);
2882
2860
  if (configPath) {
2883
- confidence += 25;
2861
+ confidence += 30;
2884
2862
  sources.push({ type: 'config-file', path: configPath });
2885
2863
  }
2886
- if (!configPath) {
2887
- const viteConfig = exists(node_path.join(projectPath, 'vite.config.ts')) ||
2888
- exists(node_path.join(projectPath, 'vite.config.js')) ||
2889
- exists(node_path.join(projectPath, 'vite.config.mjs'));
2890
- if (viteConfig && deps['vitest']) {
2891
- confidence += 5;
2892
- sources.push({ type: 'config-file', path: 'vite.config.*' });
2893
- }
2864
+ if (pkg && 'jest' in pkg) {
2865
+ confidence += 20;
2866
+ sources.push({ type: 'package.json', field: 'jest' });
2894
2867
  }
2895
2868
  const testScript = pkg?.scripts?.['test'] ?? '';
2896
- if (testScript.includes('vitest')) {
2869
+ if (testScript.includes('jest')) {
2897
2870
  confidence += 10;
2898
2871
  sources.push({ type: 'package.json', field: 'scripts.test' });
2899
2872
  }
2873
+ if (deps['@types/jest']) {
2874
+ confidence += 5;
2875
+ sources.push({ type: 'package.json', field: 'dependencies.@types/jest' });
2876
+ }
2877
+ if (deps['ts-jest']) {
2878
+ confidence += 5;
2879
+ sources.push({ type: 'package.json', field: 'dependencies.ts-jest' });
2880
+ }
2900
2881
  if (confidence === 0) {
2901
2882
  return null;
2902
2883
  }
2903
2884
  return {
2904
- id: 'vitest',
2905
- name: 'Vitest',
2885
+ id: 'jest',
2886
+ name: 'Jest',
2906
2887
  type: 'unit',
2907
2888
  version,
2908
2889
  configPath,
2909
- confidence: min(confidence, 100),
2890
+ confidence: index_cjs_js$8.min(confidence, 100),
2910
2891
  detectedFrom: sources,
2911
2892
  };
2912
2893
  }
@@ -2919,6 +2900,17 @@ const MOCHA_CONFIG_PATTERNS = ['.mocharc.js', '.mocharc.json', '.mocharc.yaml',
2919
2900
  * @param projectPath - Project directory path
2920
2901
  * @param packageJson - Optional pre-loaded package.json
2921
2902
  * @returns Detection result or null if not detected
2903
+ *
2904
+ * @example Detecting Mocha testing framework
2905
+ * ```typescript
2906
+ * import { mochaDetector } from '@hyperfrontend/project-scope'
2907
+ *
2908
+ * const result = mochaDetector('./my-project')
2909
+ * if (result) {
2910
+ * console.log(`Mocha ${result.version} detected (${result.confidence}%)`)
2911
+ * // => "Mocha 10.2.0 detected (95%)"
2912
+ * }
2913
+ * ```
2922
2914
  */
2923
2915
  function mochaDetector(projectPath, packageJson) {
2924
2916
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2958,42 +2950,58 @@ function mochaDetector(projectPath, packageJson) {
2958
2950
  type: 'unit',
2959
2951
  version,
2960
2952
  configPath,
2961
- confidence: min(confidence, 100),
2953
+ confidence: index_cjs_js$8.min(confidence, 100),
2962
2954
  detectedFrom: sources,
2963
2955
  };
2964
2956
  }
2965
2957
 
2966
- /** Config patterns for Cypress */
2967
- const CYPRESS_CONFIG_PATTERNS = ['cypress.config.js', 'cypress.config.ts', 'cypress.config.mjs', 'cypress.json'];
2958
+ /** Config patterns for Playwright */
2959
+ const PLAYWRIGHT_CONFIG_PATTERNS = ['playwright.config.js', 'playwright.config.ts', 'playwright.config.mjs'];
2968
2960
  /**
2969
- * Detect Cypress in project.
2961
+ * Detect Playwright in project.
2970
2962
  *
2971
2963
  * @param projectPath - Project directory path
2972
2964
  * @param packageJson - Optional pre-loaded package.json
2973
2965
  * @returns Detection result or null if not detected
2966
+ *
2967
+ * @example Detecting Playwright testing framework
2968
+ * ```typescript
2969
+ * import { playwrightDetector } from '@hyperfrontend/project-scope'
2970
+ *
2971
+ * const result = playwrightDetector('./my-project')
2972
+ * if (result) {
2973
+ * console.log(`Playwright ${result.version} (${result.type} tests)`)
2974
+ * // => "Playwright 1.42.0 (e2e tests)"
2975
+ * }
2976
+ * ```
2974
2977
  */
2975
- function cypressDetector(projectPath, packageJson) {
2978
+ function playwrightDetector(projectPath, packageJson) {
2976
2979
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2977
2980
  const sources = [];
2978
2981
  let confidence = 0;
2979
2982
  let version;
2980
2983
  const deps = collectAllDependencies(pkg);
2981
- if (deps['cypress']) {
2982
- confidence += 60;
2983
- version = parseVersionString(deps['cypress']);
2984
- sources.push({ type: 'package.json', field: 'dependencies.cypress' });
2984
+ if (deps['@playwright/test']) {
2985
+ confidence += 70;
2986
+ version = parseVersionString(deps['@playwright/test']);
2987
+ sources.push({ type: 'package.json', field: 'dependencies.@playwright/test' });
2985
2988
  }
2986
- const configPath = locateConfigFile(projectPath, CYPRESS_CONFIG_PATTERNS);
2989
+ if (deps['playwright']) {
2990
+ confidence += 50;
2991
+ version = version ?? parseVersionString(deps['playwright']);
2992
+ sources.push({ type: 'package.json', field: 'dependencies.playwright' });
2993
+ }
2994
+ const configPath = locateConfigFile(projectPath, PLAYWRIGHT_CONFIG_PATTERNS);
2987
2995
  if (configPath) {
2988
- confidence += 30;
2996
+ confidence += 25;
2989
2997
  sources.push({ type: 'config-file', path: configPath });
2990
2998
  }
2991
- if (exists(node_path.join(projectPath, 'cypress'))) {
2992
- confidence += 10;
2993
- sources.push({ type: 'directory', path: 'cypress/' });
2999
+ if (exists(node_path.join(projectPath, 'e2e')) || exists(node_path.join(projectPath, 'tests'))) {
3000
+ confidence += 5;
3001
+ sources.push({ type: 'directory', path: 'e2e/ or tests/' });
2994
3002
  }
2995
3003
  const e2eScript = pkg?.scripts?.['e2e'] ?? pkg?.scripts?.['test:e2e'] ?? '';
2996
- if (e2eScript.includes('cypress')) {
3004
+ if (e2eScript.includes('playwright')) {
2997
3005
  confidence += 5;
2998
3006
  sources.push({ type: 'package.json', field: 'scripts.e2e or scripts.test:e2e' });
2999
3007
  }
@@ -3001,65 +3009,77 @@ function cypressDetector(projectPath, packageJson) {
3001
3009
  return null;
3002
3010
  }
3003
3011
  return {
3004
- id: 'cypress',
3005
- name: 'Cypress',
3012
+ id: 'playwright',
3013
+ name: 'Playwright',
3006
3014
  type: 'e2e',
3007
3015
  version,
3008
3016
  configPath,
3009
- confidence: min(confidence, 100),
3017
+ confidence: index_cjs_js$8.min(confidence, 100),
3010
3018
  detectedFrom: sources,
3011
3019
  };
3012
3020
  }
3013
3021
 
3014
- /** Config patterns for Playwright */
3015
- const PLAYWRIGHT_CONFIG_PATTERNS = ['playwright.config.js', 'playwright.config.ts', 'playwright.config.mjs'];
3022
+ /** Config patterns for Vitest */
3023
+ const VITEST_CONFIG_PATTERNS = ['vitest.config.js', 'vitest.config.ts', 'vitest.config.mjs'];
3016
3024
  /**
3017
- * Detect Playwright in project.
3025
+ * Detect Vitest in project.
3018
3026
  *
3019
3027
  * @param projectPath - Project directory path
3020
3028
  * @param packageJson - Optional pre-loaded package.json
3021
3029
  * @returns Detection result or null if not detected
3030
+ *
3031
+ * @example Detecting Vitest testing framework
3032
+ * ```typescript
3033
+ * import { vitestDetector } from '@hyperfrontend/project-scope'
3034
+ *
3035
+ * const result = vitestDetector('./my-project')
3036
+ * if (result) {
3037
+ * console.log(`Vitest ${result.version} detected`)
3038
+ * console.log('Config:', result.configPath)
3039
+ * // => "Config: vitest.config.ts"
3040
+ * }
3041
+ * ```
3022
3042
  */
3023
- function playwrightDetector(projectPath, packageJson) {
3043
+ function vitestDetector(projectPath, packageJson) {
3024
3044
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
3025
3045
  const sources = [];
3026
3046
  let confidence = 0;
3027
3047
  let version;
3028
3048
  const deps = collectAllDependencies(pkg);
3029
- if (deps['@playwright/test']) {
3049
+ if (deps['vitest']) {
3030
3050
  confidence += 70;
3031
- version = parseVersionString(deps['@playwright/test']);
3032
- sources.push({ type: 'package.json', field: 'dependencies.@playwright/test' });
3033
- }
3034
- if (deps['playwright']) {
3035
- confidence += 50;
3036
- version = version ?? parseVersionString(deps['playwright']);
3037
- sources.push({ type: 'package.json', field: 'dependencies.playwright' });
3051
+ version = parseVersionString(deps['vitest']);
3052
+ sources.push({ type: 'package.json', field: 'dependencies.vitest' });
3038
3053
  }
3039
- const configPath = locateConfigFile(projectPath, PLAYWRIGHT_CONFIG_PATTERNS);
3054
+ const configPath = locateConfigFile(projectPath, VITEST_CONFIG_PATTERNS);
3040
3055
  if (configPath) {
3041
3056
  confidence += 25;
3042
3057
  sources.push({ type: 'config-file', path: configPath });
3043
3058
  }
3044
- if (exists(node_path.join(projectPath, 'e2e')) || exists(node_path.join(projectPath, 'tests'))) {
3045
- confidence += 5;
3046
- sources.push({ type: 'directory', path: 'e2e/ or tests/' });
3059
+ if (!configPath) {
3060
+ const viteConfig = exists(node_path.join(projectPath, 'vite.config.ts')) ||
3061
+ exists(node_path.join(projectPath, 'vite.config.js')) ||
3062
+ exists(node_path.join(projectPath, 'vite.config.mjs'));
3063
+ if (viteConfig && deps['vitest']) {
3064
+ confidence += 5;
3065
+ sources.push({ type: 'config-file', path: 'vite.config.*' });
3066
+ }
3047
3067
  }
3048
- const e2eScript = pkg?.scripts?.['e2e'] ?? pkg?.scripts?.['test:e2e'] ?? '';
3049
- if (e2eScript.includes('playwright')) {
3050
- confidence += 5;
3051
- sources.push({ type: 'package.json', field: 'scripts.e2e or scripts.test:e2e' });
3068
+ const testScript = pkg?.scripts?.['test'] ?? '';
3069
+ if (testScript.includes('vitest')) {
3070
+ confidence += 10;
3071
+ sources.push({ type: 'package.json', field: 'scripts.test' });
3052
3072
  }
3053
3073
  if (confidence === 0) {
3054
3074
  return null;
3055
3075
  }
3056
3076
  return {
3057
- id: 'playwright',
3058
- name: 'Playwright',
3059
- type: 'e2e',
3077
+ id: 'vitest',
3078
+ name: 'Vitest',
3079
+ type: 'unit',
3060
3080
  version,
3061
3081
  configPath,
3062
- confidence: min(confidence, 100),
3082
+ confidence: index_cjs_js$8.min(confidence, 100),
3063
3083
  detectedFrom: sources,
3064
3084
  };
3065
3085
  }
@@ -3086,7 +3106,7 @@ function checkTsConfigStrict(projectPath) {
3086
3106
  return undefined;
3087
3107
  try {
3088
3108
  const cleanContent = content.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, '');
3089
- const parsed = parse(cleanContent);
3109
+ const parsed = index_cjs_js$6.parse(cleanContent);
3090
3110
  return parsed?.compilerOptions?.strict === true;
3091
3111
  }
3092
3112
  catch {
@@ -3099,6 +3119,19 @@ function checkTsConfigStrict(projectPath) {
3099
3119
  * @param projectPath - Project directory path
3100
3120
  * @param packageJson - Optional pre-loaded package.json
3101
3121
  * @returns Detection result or null if not detected
3122
+ *
3123
+ * @example Detecting TypeScript
3124
+ * ```typescript
3125
+ * import { typescriptDetector } from '@hyperfrontend/project-scope'
3126
+ *
3127
+ * const result = typescriptDetector('./my-project')
3128
+ * if (result) {
3129
+ * console.log(`TypeScript ${result.version}`)
3130
+ * console.log(`Strict mode: ${result.strictMode ?? 'unknown'}`)
3131
+ * // => "TypeScript 5.3.0"
3132
+ * // => "Strict mode: true"
3133
+ * }
3134
+ * ```
3102
3135
  */
3103
3136
  function typescriptDetector(projectPath, packageJson) {
3104
3137
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3125,7 +3158,7 @@ function typescriptDetector(projectPath, packageJson) {
3125
3158
  break;
3126
3159
  }
3127
3160
  }
3128
- const typePackages = keys(deps).filter((d) => d.startsWith('@types/'));
3161
+ const typePackages = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('@types/'));
3129
3162
  if (typePackages.length > 0) {
3130
3163
  confidence += 10;
3131
3164
  sources.push({ type: 'package.json', field: '@types/* packages' });
@@ -3140,7 +3173,7 @@ function typescriptDetector(projectPath, packageJson) {
3140
3173
  version,
3141
3174
  configPath,
3142
3175
  strictMode,
3143
- confidence: min(confidence, 100),
3176
+ confidence: index_cjs_js$8.min(confidence, 100),
3144
3177
  detectedFrom: sources,
3145
3178
  };
3146
3179
  }
@@ -3150,6 +3183,17 @@ function typescriptDetector(projectPath, packageJson) {
3150
3183
  * @param projectPath - Project directory path
3151
3184
  * @param packageJson - Optional pre-loaded package.json
3152
3185
  * @returns Detection result or null if not detected
3186
+ *
3187
+ * @example Detecting Flow type system
3188
+ * ```typescript
3189
+ * import { flowDetector } from '@hyperfrontend/project-scope'
3190
+ *
3191
+ * const result = flowDetector('./my-project')
3192
+ * if (result) {
3193
+ * console.log(`Flow ${result.version} with config: ${result.configPath}`)
3194
+ * // => "Flow 0.232.0 with config: .flowconfig"
3195
+ * }
3196
+ * ```
3153
3197
  */
3154
3198
  function flowDetector(projectPath, packageJson) {
3155
3199
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3184,7 +3228,7 @@ function flowDetector(projectPath, packageJson) {
3184
3228
  name: 'Flow',
3185
3229
  version,
3186
3230
  configPath,
3187
- confidence: min(confidence, 100),
3231
+ confidence: index_cjs_js$8.min(confidence, 100),
3188
3232
  detectedFrom: sources,
3189
3233
  };
3190
3234
  }
@@ -3207,6 +3251,18 @@ function hasJsDocTypes(content) {
3207
3251
  * @param projectPath - Project directory path
3208
3252
  * @param packageJson - Optional pre-loaded package.json
3209
3253
  * @returns Detection result or null if not detected
3254
+ *
3255
+ * @example Detecting JSDoc type annotations
3256
+ * ```typescript
3257
+ * import { jsdocDetector } from '@hyperfrontend/project-scope'
3258
+ *
3259
+ * const result = jsdocDetector('./my-project')
3260
+ * if (result) {
3261
+ * console.log('JSDoc types detected')
3262
+ * console.log('Sources:', result.detectedFrom.map(s => s.path ?? s.field))
3263
+ * // => "Sources: ['jsconfig.json', 'src/utils.js (JSDoc annotations)']"
3264
+ * }
3265
+ * ```
3210
3266
  */
3211
3267
  function jsdocDetector(projectPath, packageJson) {
3212
3268
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3223,7 +3279,7 @@ function jsdocDetector(projectPath, packageJson) {
3223
3279
  if (content) {
3224
3280
  try {
3225
3281
  const cleanContent = content.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, '');
3226
- const parsed = parse(cleanContent);
3282
+ const parsed = index_cjs_js$6.parse(cleanContent);
3227
3283
  if (parsed?.compilerOptions?.checkJs === true || parsed?.compilerOptions?.allowJs === true) {
3228
3284
  confidence += 30;
3229
3285
  sources.push({ type: 'config-file', path: 'tsconfig.json (checkJs/allowJs)' });
@@ -3262,7 +3318,7 @@ function jsdocDetector(projectPath, packageJson) {
3262
3318
  return {
3263
3319
  id: 'jsdoc',
3264
3320
  name: 'JSDoc',
3265
- confidence: min(confidence, 100),
3321
+ confidence: index_cjs_js$8.min(confidence, 100),
3266
3322
  detectedFrom: sources,
3267
3323
  };
3268
3324
  }
@@ -3300,7 +3356,7 @@ function isDetectAllOptions(value) {
3300
3356
  * @param packageJsonOrOptions - Optional pre-loaded package.json or options object
3301
3357
  * @returns All detection results organized by category
3302
3358
  *
3303
- * @example
3359
+ * @example Running all tech detectors
3304
3360
  * ```typescript
3305
3361
  * import { detectAll } from '@hyperfrontend/project-scope'
3306
3362
  *
@@ -3417,7 +3473,7 @@ function buildSummary(frontend, backend, testing) {
3417
3473
  * @param options - Identification options
3418
3474
  * @returns Framework identification result
3419
3475
  *
3420
- * @example
3476
+ * @example Identifying all frameworks in project
3421
3477
  * ```typescript
3422
3478
  * import { identifyFrameworks } from '@hyperfrontend/project-scope'
3423
3479
  *
@@ -3532,6 +3588,14 @@ function identifyFrameworks(projectPath, options) {
3532
3588
  * Clear the framework identification cache.
3533
3589
  *
3534
3590
  * Useful for testing or when the project files have changed.
3591
+ *
3592
+ * @example Clearing the framework cache
3593
+ * ```typescript
3594
+ * import { clearFrameworkIdentificationCache } from '@hyperfrontend/project-scope'
3595
+ *
3596
+ * // Reset cache before re-identifying frameworks
3597
+ * clearFrameworkIdentificationCache()
3598
+ * ```
3535
3599
  */
3536
3600
  function clearFrameworkIdentificationCache() {
3537
3601
  frameworkIdCache.clear();
@@ -3543,6 +3607,15 @@ function clearFrameworkIdentificationCache() {
3543
3607
  * @param frameworkId - Framework identifier to check
3544
3608
  * @param minConfidence - Minimum confidence threshold (default: 50)
3545
3609
  * @returns True if the framework is detected with sufficient confidence
3610
+ *
3611
+ * @example Checking for a specific framework
3612
+ * ```typescript
3613
+ * import { usesFramework } from '@hyperfrontend/project-scope'
3614
+ *
3615
+ * if (usesFramework('/path/to/project', 'react', 70)) {
3616
+ * console.log('Project uses React with high confidence')
3617
+ * }
3618
+ * ```
3546
3619
  */
3547
3620
  function usesFramework(projectPath, frameworkId, minConfidence = 50) {
3548
3621
  const identification = identifyFrameworks(projectPath, { minConfidence });
@@ -3553,4 +3626,3 @@ function usesFramework(projectPath, frameworkId, minConfidence = 50) {
3553
3626
  exports.clearFrameworkIdentificationCache = clearFrameworkIdentificationCache;
3554
3627
  exports.identifyFrameworks = identifyFrameworks;
3555
3628
  exports.usesFramework = usesFramework;
3556
- //# sourceMappingURL=index.cjs.js.map