@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
package/tech/index.cjs.js CHANGED
@@ -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
  }
@@ -1196,6 +678,19 @@ const backendDetectors = [
1196
678
  * @param projectPath - Project directory path
1197
679
  * @param packageJson - Optional pre-loaded package.json
1198
680
  * @returns Array of detected frameworks, sorted by confidence
681
+ * @example Detecting multiple backend frameworks
682
+ * ```typescript
683
+ * const pkg = {
684
+ * dependencies: { '@nestjs/core': '^10.0.0', '@nestjs/common': '^10.0.0' },
685
+ * devDependencies: { express: '^4.18.0' },
686
+ * }
687
+ *
688
+ * const results = detectBackendFrameworks('/path/to/project', pkg)
689
+ * // => [
690
+ * // { id: 'nestjs', name: 'NestJS', confidence: 85, ... },
691
+ * // { id: 'express', name: 'Express', confidence: 80, ... },
692
+ * // ]
693
+ * ```
1199
694
  */
1200
695
  function detectBackendFrameworks(projectPath, packageJson) {
1201
696
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -1209,102 +704,194 @@ function detectBackendFrameworks(projectPath, packageJson) {
1209
704
  return results.sort((a, b) => b.confidence - a.confidence);
1210
705
  }
1211
706
 
1212
- /** Config patterns for Webpack */
1213
- const WEBPACK_CONFIG_PATTERNS = [
1214
- 'webpack.config.js',
1215
- 'webpack.config.ts',
1216
- 'webpack.config.cjs',
1217
- 'webpack.config.mjs',
1218
- 'webpack.config.babel.js',
1219
- ];
707
+ /** Config patterns for Babel */
708
+ const BABEL_CONFIG_PATTERNS = ['babel.config.js', 'babel.config.cjs', 'babel.config.mjs', 'babel.config.json', '.babelrc', '.babelrc.json', '.babelrc.js'];
1220
709
  /**
1221
- * Detect Webpack in project.
710
+ * Detect Babel in project.
1222
711
  *
1223
712
  * @param projectPath - Project directory path
1224
713
  * @param packageJson - Optional pre-loaded package.json
1225
714
  * @returns Detection result or null if not detected
715
+ *
716
+ * @example Detecting Babel compiler
717
+ * ```typescript
718
+ * const result = babelDetector('/path/to/project', {
719
+ * name: 'my-app',
720
+ * devDependencies: { '@babel/core': '^7.23.0', '@babel/preset-env': '^7.23.0' }
721
+ * })
722
+ * // => {
723
+ * // id: 'babel',
724
+ * // name: 'Babel',
725
+ * // version: '7.23.0',
726
+ * // confidence: 60,
727
+ * // detectedFrom: [
728
+ * // { type: 'package.json', field: 'dependencies.@babel/core' },
729
+ * // { type: 'package.json', field: 'dependencies (@babel packages)' }
730
+ * // ]
731
+ * // }
732
+ * ```
1226
733
  */
1227
- function webpackDetector(projectPath, packageJson) {
734
+ function babelDetector(projectPath, packageJson) {
1228
735
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1229
736
  const sources = [];
1230
737
  let confidence = 0;
1231
738
  let version;
1232
739
  const deps = collectAllDependencies(pkg);
1233
- if (deps['webpack']) {
740
+ if (deps['@babel/core']) {
1234
741
  confidence += 50;
1235
- version = parseVersionString(deps['webpack']);
1236
- sources.push({ type: 'package.json', field: 'dependencies.webpack' });
742
+ version = parseVersionString(deps['@babel/core']);
743
+ sources.push({ type: 'package.json', field: 'dependencies.@babel/core' });
1237
744
  }
1238
- const configPath = locateConfigFile(projectPath, WEBPACK_CONFIG_PATTERNS);
745
+ const configPath = locateConfigFile(projectPath, BABEL_CONFIG_PATTERNS);
1239
746
  if (configPath) {
1240
747
  confidence += 40;
1241
748
  sources.push({ type: 'config-file', path: configPath });
1242
749
  }
1243
- if (deps['webpack-cli']) {
750
+ if (pkg && 'babel' in pkg) {
751
+ confidence += 30;
752
+ sources.push({ type: 'package.json', field: 'babel' });
753
+ }
754
+ const babelPackages = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('@babel/'));
755
+ if (babelPackages.length > 1) {
1244
756
  confidence += 10;
1245
- sources.push({ type: 'package.json', field: 'dependencies.webpack-cli' });
757
+ sources.push({ type: 'package.json', field: 'dependencies (@babel packages)' });
1246
758
  }
1247
- const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'webpack');
759
+ if (confidence === 0) {
760
+ return null;
761
+ }
762
+ return {
763
+ id: 'babel',
764
+ name: 'Babel',
765
+ version,
766
+ configPath,
767
+ confidence: index_cjs_js$8.min(confidence, 100),
768
+ detectedFrom: sources,
769
+ };
770
+ }
771
+
772
+ /**
773
+ * Detect esbuild in project.
774
+ *
775
+ * @param projectPath - Project directory path
776
+ * @param packageJson - Optional pre-loaded package.json
777
+ * @returns Detection result or null if not detected
778
+ *
779
+ * @example Detecting esbuild bundler
780
+ * ```typescript
781
+ * const result = esbuildDetector('/path/to/project', {
782
+ * name: 'my-lib',
783
+ * devDependencies: { 'esbuild': '^0.19.0' },
784
+ * scripts: { 'build': 'esbuild src/index.ts --bundle --outfile=dist/index.js' }
785
+ * })
786
+ * // => {
787
+ * // id: 'esbuild',
788
+ * // name: 'esbuild',
789
+ * // version: '0.19.0',
790
+ * // confidence: 80,
791
+ * // detectedFrom: [
792
+ * // { type: 'package.json', field: 'dependencies.esbuild' },
793
+ * // { type: 'package.json', field: 'scripts.build' }
794
+ * // ]
795
+ * // }
796
+ * ```
797
+ */
798
+ function esbuildDetector(projectPath, packageJson) {
799
+ const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
800
+ const sources = [];
801
+ let confidence = 0;
802
+ let version;
803
+ const deps = collectAllDependencies(pkg);
804
+ if (deps['esbuild']) {
805
+ confidence += 70;
806
+ version = parseVersionString(deps['esbuild']);
807
+ sources.push({ type: 'package.json', field: 'dependencies.esbuild' });
808
+ }
809
+ const esbuildPlugins = index_cjs_js$2.keys(deps).filter((d) => d.includes('esbuild-plugin') || d.includes('esbuild-'));
810
+ if (esbuildPlugins.length > 0) {
811
+ confidence += 15;
812
+ sources.push({ type: 'package.json', field: 'dependencies (esbuild plugins)' });
813
+ }
814
+ const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'esbuild');
1248
815
  for (const name of scriptMatches) {
1249
- confidence = min(confidence + 5, 100);
816
+ confidence = index_cjs_js$8.min(confidence + 10, 100);
1250
817
  sources.push({ type: 'package.json', field: `scripts.${name}` });
1251
818
  }
1252
819
  if (confidence === 0) {
1253
820
  return null;
1254
821
  }
1255
822
  return {
1256
- id: 'webpack',
1257
- name: 'Webpack',
823
+ id: 'esbuild',
824
+ name: 'esbuild',
1258
825
  version,
1259
- configPath,
1260
- confidence: min(confidence, 100),
826
+ confidence: index_cjs_js$8.min(confidence, 100),
1261
827
  detectedFrom: sources,
1262
828
  };
1263
829
  }
1264
830
 
1265
- /** Config patterns for Vite */
1266
- const VITE_CONFIG_PATTERNS = ['vite.config.js', 'vite.config.ts', 'vite.config.mjs', 'vite.config.cjs'];
831
+ /** Config patterns for Parcel */
832
+ const PARCEL_CONFIG_PATTERNS = ['.parcelrc'];
1267
833
  /**
1268
- * Detect Vite in project.
834
+ * Detect Parcel in project.
1269
835
  *
1270
836
  * @param projectPath - Project directory path
1271
837
  * @param packageJson - Optional pre-loaded package.json
1272
838
  * @returns Detection result or null if not detected
839
+ *
840
+ * @example Detecting Parcel bundler
841
+ * ```typescript
842
+ * const result = parcelDetector('/path/to/project', {
843
+ * name: 'my-app',
844
+ * devDependencies: { 'parcel': '^2.10.0' },
845
+ * scripts: { 'dev': 'parcel src/index.html', 'build': 'parcel build src/index.html' }
846
+ * })
847
+ * // => {
848
+ * // id: 'parcel',
849
+ * // name: 'Parcel',
850
+ * // version: '2.10.0',
851
+ * // confidence: 80,
852
+ * // detectedFrom: [
853
+ * // { type: 'package.json', field: 'dependencies.parcel' },
854
+ * // { type: 'package.json', field: 'scripts.dev' },
855
+ * // { type: 'package.json', field: 'scripts.build' }
856
+ * // ]
857
+ * // }
858
+ * ```
1273
859
  */
1274
- function viteDetector(projectPath, packageJson) {
860
+ function parcelDetector(projectPath, packageJson) {
1275
861
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1276
862
  const sources = [];
1277
863
  let confidence = 0;
1278
864
  let version;
1279
865
  const deps = collectAllDependencies(pkg);
1280
- if (deps['vite']) {
866
+ if (deps['parcel']) {
1281
867
  confidence += 60;
1282
- version = parseVersionString(deps['vite']);
1283
- sources.push({ type: 'package.json', field: 'dependencies.vite' });
868
+ version = parseVersionString(deps['parcel']);
869
+ sources.push({ type: 'package.json', field: 'dependencies.parcel' });
1284
870
  }
1285
- const configPath = locateConfigFile(projectPath, VITE_CONFIG_PATTERNS);
871
+ if (deps['parcel-bundler']) {
872
+ confidence += 60;
873
+ version = parseVersionString(deps['parcel-bundler']);
874
+ sources.push({ type: 'package.json', field: 'dependencies.parcel-bundler' });
875
+ }
876
+ const configPath = locateConfigFile(projectPath, PARCEL_CONFIG_PATTERNS);
1286
877
  if (configPath) {
1287
- confidence += 35;
878
+ confidence += 30;
1288
879
  sources.push({ type: 'config-file', path: configPath });
1289
880
  }
1290
- if (deps['vitest']) {
1291
- confidence += 10;
1292
- sources.push({ type: 'package.json', field: 'dependencies.vitest' });
1293
- }
1294
- const vitePlugins = keys(deps).filter((d) => d.startsWith('vite-plugin-') || d.startsWith('@vitejs/'));
1295
- if (vitePlugins.length > 0) {
1296
- confidence += 10;
1297
- sources.push({ type: 'package.json', field: 'dependencies (vite plugins)' });
881
+ const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'parcel');
882
+ for (const name of scriptMatches) {
883
+ confidence = index_cjs_js$8.min(confidence + 10, 100);
884
+ sources.push({ type: 'package.json', field: `scripts.${name}` });
1298
885
  }
1299
886
  if (confidence === 0) {
1300
887
  return null;
1301
888
  }
1302
889
  return {
1303
- id: 'vite',
1304
- name: 'Vite',
890
+ id: 'parcel',
891
+ name: 'Parcel',
1305
892
  version,
1306
893
  configPath,
1307
- confidence: min(confidence, 100),
894
+ confidence: index_cjs_js$8.min(confidence, 100),
1308
895
  detectedFrom: sources,
1309
896
  };
1310
897
  }
@@ -1317,6 +904,28 @@ const ROLLUP_CONFIG_PATTERNS = ['rollup.config.js', 'rollup.config.ts', 'rollup.
1317
904
  * @param projectPath - Project directory path
1318
905
  * @param packageJson - Optional pre-loaded package.json
1319
906
  * @returns Detection result or null if not detected
907
+ *
908
+ * @example Detecting Rollup bundler
909
+ * ```typescript
910
+ * const result = rollupDetector('/path/to/project', {
911
+ * name: 'my-lib',
912
+ * devDependencies: {
913
+ * 'rollup': '^4.0.0',
914
+ * '@rollup/plugin-node-resolve': '^15.0.0',
915
+ * '@rollup/plugin-commonjs': '^25.0.0'
916
+ * }
917
+ * })
918
+ * // => {
919
+ * // id: 'rollup',
920
+ * // name: 'Rollup',
921
+ * // version: '4.0.0',
922
+ * // confidence: 65,
923
+ * // detectedFrom: [
924
+ * // { type: 'package.json', field: 'dependencies.rollup' },
925
+ * // { type: 'package.json', field: 'dependencies (rollup plugins)' }
926
+ * // ]
927
+ * // }
928
+ * ```
1320
929
  */
1321
930
  function rollupDetector(projectPath, packageJson) {
1322
931
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -1334,14 +943,14 @@ function rollupDetector(projectPath, packageJson) {
1334
943
  confidence += 40;
1335
944
  sources.push({ type: 'config-file', path: configPath });
1336
945
  }
1337
- const rollupPlugins = keys(deps).filter((d) => d.startsWith('@rollup/') || d.startsWith('rollup-plugin-'));
946
+ const rollupPlugins = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('@rollup/') || d.startsWith('rollup-plugin-'));
1338
947
  if (rollupPlugins.length > 0) {
1339
948
  confidence += 10;
1340
949
  sources.push({ type: 'package.json', field: 'dependencies (rollup plugins)' });
1341
950
  }
1342
951
  const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'rollup');
1343
952
  for (const name of scriptMatches) {
1344
- confidence = min(confidence + 5, 100);
953
+ confidence = index_cjs_js$8.min(confidence + 5, 100);
1345
954
  sources.push({ type: 'package.json', field: `scripts.${name}` });
1346
955
  }
1347
956
  if (confidence === 0) {
@@ -1352,189 +961,215 @@ function rollupDetector(projectPath, packageJson) {
1352
961
  name: 'Rollup',
1353
962
  version,
1354
963
  configPath,
1355
- confidence: min(confidence, 100),
964
+ confidence: index_cjs_js$8.min(confidence, 100),
1356
965
  detectedFrom: sources,
1357
966
  };
1358
967
  }
1359
968
 
969
+ /** Config patterns for SWC */
970
+ const SWC_CONFIG_PATTERNS = ['.swcrc', 'swc.config.js'];
1360
971
  /**
1361
- * Detect esbuild in project.
972
+ * Detect SWC in project.
1362
973
  *
1363
974
  * @param projectPath - Project directory path
1364
975
  * @param packageJson - Optional pre-loaded package.json
1365
976
  * @returns Detection result or null if not detected
1366
- */
1367
- function esbuildDetector(projectPath, packageJson) {
1368
- const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1369
- const sources = [];
1370
- let confidence = 0;
1371
- let version;
1372
- const deps = collectAllDependencies(pkg);
1373
- if (deps['esbuild']) {
1374
- confidence += 70;
1375
- version = parseVersionString(deps['esbuild']);
1376
- sources.push({ type: 'package.json', field: 'dependencies.esbuild' });
1377
- }
1378
- const esbuildPlugins = keys(deps).filter((d) => d.includes('esbuild-plugin') || d.includes('esbuild-'));
1379
- if (esbuildPlugins.length > 0) {
1380
- confidence += 15;
1381
- sources.push({ type: 'package.json', field: 'dependencies (esbuild plugins)' });
1382
- }
1383
- const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'esbuild');
1384
- for (const name of scriptMatches) {
1385
- confidence = min(confidence + 10, 100);
1386
- sources.push({ type: 'package.json', field: `scripts.${name}` });
1387
- }
1388
- if (confidence === 0) {
1389
- return null;
1390
- }
1391
- return {
1392
- id: 'esbuild',
1393
- name: 'esbuild',
1394
- version,
1395
- confidence: min(confidence, 100),
1396
- detectedFrom: sources,
1397
- };
1398
- }
1399
-
1400
- /** Config patterns for Babel */
1401
- const BABEL_CONFIG_PATTERNS = ['babel.config.js', 'babel.config.cjs', 'babel.config.mjs', 'babel.config.json', '.babelrc', '.babelrc.json', '.babelrc.js'];
1402
- /**
1403
- * Detect Babel in project.
1404
977
  *
1405
- * @param projectPath - Project directory path
1406
- * @param packageJson - Optional pre-loaded package.json
1407
- * @returns Detection result or null if not detected
978
+ * @example Detecting SWC compiler
979
+ * ```typescript
980
+ * const result = swcDetector('/path/to/project', {
981
+ * name: 'my-app',
982
+ * devDependencies: { '@swc/core': '^1.3.0', '@swc/cli': '^0.1.0' }
983
+ * })
984
+ * // => {
985
+ * // id: 'swc',
986
+ * // name: 'SWC',
987
+ * // version: '1.3.0',
988
+ * // confidence: 70,
989
+ * // detectedFrom: [
990
+ * // { type: 'package.json', field: 'dependencies.@swc/core' },
991
+ * // { type: 'package.json', field: 'dependencies.@swc/cli' }
992
+ * // ]
993
+ * // }
994
+ * ```
1408
995
  */
1409
- function babelDetector(projectPath, packageJson) {
996
+ function swcDetector(projectPath, packageJson) {
1410
997
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1411
998
  const sources = [];
1412
999
  let confidence = 0;
1413
1000
  let version;
1414
1001
  const deps = collectAllDependencies(pkg);
1415
- if (deps['@babel/core']) {
1416
- confidence += 50;
1417
- version = parseVersionString(deps['@babel/core']);
1418
- sources.push({ type: 'package.json', field: 'dependencies.@babel/core' });
1002
+ if (deps['@swc/core']) {
1003
+ confidence += 60;
1004
+ version = parseVersionString(deps['@swc/core']);
1005
+ sources.push({ type: 'package.json', field: 'dependencies.@swc/core' });
1419
1006
  }
1420
- const configPath = locateConfigFile(projectPath, BABEL_CONFIG_PATTERNS);
1007
+ const configPath = locateConfigFile(projectPath, SWC_CONFIG_PATTERNS);
1421
1008
  if (configPath) {
1422
- confidence += 40;
1009
+ confidence += 35;
1423
1010
  sources.push({ type: 'config-file', path: configPath });
1424
1011
  }
1425
- if (pkg && 'babel' in pkg) {
1426
- confidence += 30;
1427
- sources.push({ type: 'package.json', field: 'babel' });
1428
- }
1429
- const babelPackages = keys(deps).filter((d) => d.startsWith('@babel/'));
1430
- if (babelPackages.length > 1) {
1012
+ if (deps['@swc/cli']) {
1431
1013
  confidence += 10;
1432
- sources.push({ type: 'package.json', field: 'dependencies (@babel packages)' });
1014
+ sources.push({ type: 'package.json', field: 'dependencies.@swc/cli' });
1015
+ }
1016
+ const swcPlugins = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('@swc/') || d.includes('swc-plugin'));
1017
+ if (swcPlugins.length > 1) {
1018
+ confidence += 5;
1019
+ sources.push({ type: 'package.json', field: 'dependencies (@swc packages)' });
1433
1020
  }
1434
1021
  if (confidence === 0) {
1435
1022
  return null;
1436
1023
  }
1437
1024
  return {
1438
- id: 'babel',
1439
- name: 'Babel',
1025
+ id: 'swc',
1026
+ name: 'SWC',
1440
1027
  version,
1441
1028
  configPath,
1442
- confidence: min(confidence, 100),
1029
+ confidence: index_cjs_js$8.min(confidence, 100),
1443
1030
  detectedFrom: sources,
1444
1031
  };
1445
1032
  }
1446
1033
 
1447
- /** Config patterns for SWC */
1448
- const SWC_CONFIG_PATTERNS = ['.swcrc', 'swc.config.js'];
1034
+ /** Config patterns for Vite */
1035
+ const VITE_CONFIG_PATTERNS = ['vite.config.js', 'vite.config.ts', 'vite.config.mjs', 'vite.config.cjs'];
1449
1036
  /**
1450
- * Detect SWC in project.
1037
+ * Detect Vite in project.
1451
1038
  *
1452
1039
  * @param projectPath - Project directory path
1453
1040
  * @param packageJson - Optional pre-loaded package.json
1454
1041
  * @returns Detection result or null if not detected
1042
+ *
1043
+ * @example Detecting Vite build tool
1044
+ * ```typescript
1045
+ * const result = viteDetector('/path/to/project', {
1046
+ * name: 'my-app',
1047
+ * devDependencies: {
1048
+ * 'vite': '^5.0.0',
1049
+ * '@vitejs/plugin-react': '^4.0.0',
1050
+ * 'vitest': '^1.0.0'
1051
+ * }
1052
+ * })
1053
+ * // => {
1054
+ * // id: 'vite',
1055
+ * // name: 'Vite',
1056
+ * // version: '5.0.0',
1057
+ * // confidence: 80,
1058
+ * // detectedFrom: [
1059
+ * // { type: 'package.json', field: 'dependencies.vite' },
1060
+ * // { type: 'package.json', field: 'dependencies.vitest' },
1061
+ * // { type: 'package.json', field: 'dependencies (vite plugins)' }
1062
+ * // ]
1063
+ * // }
1064
+ * ```
1455
1065
  */
1456
- function swcDetector(projectPath, packageJson) {
1066
+ function viteDetector(projectPath, packageJson) {
1457
1067
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1458
1068
  const sources = [];
1459
1069
  let confidence = 0;
1460
1070
  let version;
1461
1071
  const deps = collectAllDependencies(pkg);
1462
- if (deps['@swc/core']) {
1072
+ if (deps['vite']) {
1463
1073
  confidence += 60;
1464
- version = parseVersionString(deps['@swc/core']);
1465
- sources.push({ type: 'package.json', field: 'dependencies.@swc/core' });
1074
+ version = parseVersionString(deps['vite']);
1075
+ sources.push({ type: 'package.json', field: 'dependencies.vite' });
1466
1076
  }
1467
- const configPath = locateConfigFile(projectPath, SWC_CONFIG_PATTERNS);
1077
+ const configPath = locateConfigFile(projectPath, VITE_CONFIG_PATTERNS);
1468
1078
  if (configPath) {
1469
1079
  confidence += 35;
1470
1080
  sources.push({ type: 'config-file', path: configPath });
1471
1081
  }
1472
- if (deps['@swc/cli']) {
1082
+ if (deps['vitest']) {
1473
1083
  confidence += 10;
1474
- sources.push({ type: 'package.json', field: 'dependencies.@swc/cli' });
1084
+ sources.push({ type: 'package.json', field: 'dependencies.vitest' });
1475
1085
  }
1476
- const swcPlugins = keys(deps).filter((d) => d.startsWith('@swc/') || d.includes('swc-plugin'));
1477
- if (swcPlugins.length > 1) {
1478
- confidence += 5;
1479
- sources.push({ type: 'package.json', field: 'dependencies (@swc packages)' });
1086
+ const vitePlugins = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('vite-plugin-') || d.startsWith('@vitejs/'));
1087
+ if (vitePlugins.length > 0) {
1088
+ confidence += 10;
1089
+ sources.push({ type: 'package.json', field: 'dependencies (vite plugins)' });
1480
1090
  }
1481
1091
  if (confidence === 0) {
1482
1092
  return null;
1483
1093
  }
1484
1094
  return {
1485
- id: 'swc',
1486
- name: 'SWC',
1095
+ id: 'vite',
1096
+ name: 'Vite',
1487
1097
  version,
1488
1098
  configPath,
1489
- confidence: min(confidence, 100),
1099
+ confidence: index_cjs_js$8.min(confidence, 100),
1490
1100
  detectedFrom: sources,
1491
1101
  };
1492
1102
  }
1493
1103
 
1494
- /** Config patterns for Parcel */
1495
- const PARCEL_CONFIG_PATTERNS = ['.parcelrc'];
1104
+ /** Config patterns for Webpack */
1105
+ const WEBPACK_CONFIG_PATTERNS = [
1106
+ 'webpack.config.js',
1107
+ 'webpack.config.ts',
1108
+ 'webpack.config.cjs',
1109
+ 'webpack.config.mjs',
1110
+ 'webpack.config.babel.js',
1111
+ ];
1496
1112
  /**
1497
- * Detect Parcel in project.
1113
+ * Detect Webpack in project.
1498
1114
  *
1499
1115
  * @param projectPath - Project directory path
1500
1116
  * @param packageJson - Optional pre-loaded package.json
1501
1117
  * @returns Detection result or null if not detected
1118
+ *
1119
+ * @example Detecting Webpack bundler
1120
+ * ```typescript
1121
+ * const result = webpackDetector('/path/to/project', {
1122
+ * name: 'my-app',
1123
+ * devDependencies: { 'webpack': '^5.89.0', 'webpack-cli': '^5.1.0' },
1124
+ * scripts: { 'build': 'webpack --mode production' }
1125
+ * })
1126
+ * // => {
1127
+ * // id: 'webpack',
1128
+ * // name: 'Webpack',
1129
+ * // version: '5.89.0',
1130
+ * // confidence: 65,
1131
+ * // detectedFrom: [
1132
+ * // { type: 'package.json', field: 'dependencies.webpack' },
1133
+ * // { type: 'package.json', field: 'dependencies.webpack-cli' },
1134
+ * // { type: 'package.json', field: 'scripts.build' }
1135
+ * // ]
1136
+ * // }
1137
+ * ```
1502
1138
  */
1503
- function parcelDetector(projectPath, packageJson) {
1139
+ function webpackDetector(projectPath, packageJson) {
1504
1140
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1505
1141
  const sources = [];
1506
1142
  let confidence = 0;
1507
1143
  let version;
1508
1144
  const deps = collectAllDependencies(pkg);
1509
- if (deps['parcel']) {
1510
- confidence += 60;
1511
- version = parseVersionString(deps['parcel']);
1512
- sources.push({ type: 'package.json', field: 'dependencies.parcel' });
1513
- }
1514
- if (deps['parcel-bundler']) {
1515
- confidence += 60;
1516
- version = parseVersionString(deps['parcel-bundler']);
1517
- sources.push({ type: 'package.json', field: 'dependencies.parcel-bundler' });
1145
+ if (deps['webpack']) {
1146
+ confidence += 50;
1147
+ version = parseVersionString(deps['webpack']);
1148
+ sources.push({ type: 'package.json', field: 'dependencies.webpack' });
1518
1149
  }
1519
- const configPath = locateConfigFile(projectPath, PARCEL_CONFIG_PATTERNS);
1150
+ const configPath = locateConfigFile(projectPath, WEBPACK_CONFIG_PATTERNS);
1520
1151
  if (configPath) {
1521
- confidence += 30;
1152
+ confidence += 40;
1522
1153
  sources.push({ type: 'config-file', path: configPath });
1523
1154
  }
1524
- const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'parcel');
1155
+ if (deps['webpack-cli']) {
1156
+ confidence += 10;
1157
+ sources.push({ type: 'package.json', field: 'dependencies.webpack-cli' });
1158
+ }
1159
+ const scriptMatches = filterScriptsByCommand(pkg?.scripts, 'webpack');
1525
1160
  for (const name of scriptMatches) {
1526
- confidence = min(confidence + 10, 100);
1161
+ confidence = index_cjs_js$8.min(confidence + 5, 100);
1527
1162
  sources.push({ type: 'package.json', field: `scripts.${name}` });
1528
1163
  }
1529
1164
  if (confidence === 0) {
1530
1165
  return null;
1531
1166
  }
1532
1167
  return {
1533
- id: 'parcel',
1534
- name: 'Parcel',
1168
+ id: 'webpack',
1169
+ name: 'Webpack',
1535
1170
  version,
1536
1171
  configPath,
1537
- confidence: min(confidence, 100),
1172
+ confidence: index_cjs_js$8.min(confidence, 100),
1538
1173
  detectedFrom: sources,
1539
1174
  };
1540
1175
  }
@@ -1555,6 +1190,22 @@ const buildToolDetectors = [
1555
1190
  * @param projectPath - Project directory path
1556
1191
  * @param packageJson - Optional pre-loaded package.json
1557
1192
  * @returns Array of detected build tools, sorted by confidence
1193
+ *
1194
+ * @example Detecting multiple build tools
1195
+ * ```typescript
1196
+ * const tools = detectBuildTools('/path/to/project', {
1197
+ * name: 'my-app',
1198
+ * devDependencies: {
1199
+ * 'vite': '^5.0.0',
1200
+ * '@vitejs/plugin-react': '^4.0.0',
1201
+ * '@babel/core': '^7.23.0'
1202
+ * }
1203
+ * })
1204
+ * // => [
1205
+ * // { id: 'vite', name: 'Vite', version: '5.0.0', confidence: 70, ... },
1206
+ * // { id: 'babel', name: 'Babel', version: '7.23.0', confidence: 50, ... }
1207
+ * // ]
1208
+ * ```
1558
1209
  */
1559
1210
  function detectBuildTools(projectPath, packageJson) {
1560
1211
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -1569,81 +1220,187 @@ function detectBuildTools(projectPath, packageJson) {
1569
1220
  }
1570
1221
 
1571
1222
  /**
1572
- * Detect React in project.
1223
+ * Detect Angular in project.
1573
1224
  *
1574
1225
  * @param projectPath - Project directory path
1575
1226
  * @param packageJson - Optional pre-loaded package.json
1576
1227
  * @returns Detection result or null if not detected
1228
+ *
1229
+ * @example Detecting Angular framework
1230
+ * ```typescript
1231
+ * const result = angularDetector('/path/to/angular-app', {
1232
+ * dependencies: { '@angular/core': '^17.0.0', '@angular/cli': '^17.0.0' }
1233
+ * })
1234
+ * // => {
1235
+ * // id: 'angular',
1236
+ * // name: 'Angular',
1237
+ * // category: 'frontend',
1238
+ * // version: '17.0.0',
1239
+ * // confidence: 85,
1240
+ * // detectedFrom: [
1241
+ * // { type: 'package.json', field: 'dependencies.@angular/core' },
1242
+ * // { type: 'package.json', field: 'dependencies.@angular/cli' }
1243
+ * // ]
1244
+ * // }
1245
+ * ```
1577
1246
  */
1578
- function reactDetector(projectPath, packageJson) {
1247
+ function angularDetector(projectPath, packageJson) {
1579
1248
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1580
1249
  const sources = [];
1581
1250
  let confidence = 0;
1582
1251
  let version;
1583
- const metaFrameworks = [];
1584
1252
  const deps = collectAllDependencies(pkg);
1585
- if (deps['react']) {
1586
- confidence += 60;
1587
- version = parseVersionString(deps['react']);
1588
- sources.push({ type: 'package.json', field: 'dependencies.react' });
1253
+ if (deps['@angular/core']) {
1254
+ confidence += 70;
1255
+ version = parseVersionString(deps['@angular/core']);
1256
+ sources.push({ type: 'package.json', field: 'dependencies.@angular/core' });
1589
1257
  }
1590
- if (deps['react-dom']) {
1591
- confidence += 20;
1592
- sources.push({ type: 'package.json', field: 'dependencies.react-dom' });
1258
+ if (deps['@angular/cli']) {
1259
+ confidence += 15;
1260
+ sources.push({ type: 'package.json', field: 'dependencies.@angular/cli' });
1593
1261
  }
1594
- if (deps['react-native']) {
1595
- confidence += 20;
1596
- sources.push({ type: 'package.json', field: 'dependencies.react-native' });
1262
+ if (exists(node_path.join(projectPath, 'angular.json'))) {
1263
+ confidence += 15;
1264
+ sources.push({ type: 'config-file', path: 'angular.json' });
1597
1265
  }
1598
- const hasJsxFiles = exists(node_path.join(projectPath, 'src', 'App.tsx')) ||
1599
- exists(node_path.join(projectPath, 'src', 'App.jsx')) ||
1600
- exists(node_path.join(projectPath, 'src', 'index.tsx')) ||
1601
- exists(node_path.join(projectPath, 'src', 'index.jsx'));
1602
- if (hasJsxFiles) {
1603
- confidence += 10;
1604
- sources.push({ type: 'directory', path: 'src/*.tsx or src/*.jsx' });
1266
+ if (deps['angular'] && !deps['@angular/core']) {
1267
+ return {
1268
+ id: 'angularjs',
1269
+ name: 'AngularJS (Legacy)',
1270
+ category: 'frontend',
1271
+ version: parseVersionString(deps['angular']),
1272
+ confidence: 80,
1273
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.angular' }],
1274
+ };
1605
1275
  }
1606
- if (deps['next']) {
1607
- metaFrameworks.push({
1608
- id: 'nextjs',
1609
- name: 'Next.js',
1610
- category: 'meta-framework',
1611
- version: parseVersionString(deps['next']),
1612
- confidence: 90,
1613
- detectedFrom: [{ type: 'package.json', field: 'dependencies.next' }],
1614
- });
1276
+ if (confidence === 0) {
1277
+ return null;
1278
+ }
1279
+ return {
1280
+ id: 'angular',
1281
+ name: 'Angular',
1282
+ category: 'frontend',
1283
+ version,
1284
+ confidence: index_cjs_js$8.min(confidence, 100),
1285
+ detectedFrom: sources,
1286
+ };
1287
+ }
1288
+
1289
+ /**
1290
+ * Detect Astro in project.
1291
+ *
1292
+ * @param projectPath - Project directory path
1293
+ * @param packageJson - Optional pre-loaded package.json
1294
+ * @returns Detection result or null if not detected
1295
+ *
1296
+ * @example Detecting Astro framework
1297
+ * ```typescript
1298
+ * const result = astroDetector('/path/to/astro-project', {
1299
+ * dependencies: { 'astro': '^4.0.0' }
1300
+ * })
1301
+ * // => {
1302
+ * // id: 'astro',
1303
+ * // name: 'Astro',
1304
+ * // category: 'meta-framework',
1305
+ * // version: '4.0.0',
1306
+ * // confidence: 70,
1307
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.astro' }]
1308
+ * // }
1309
+ * ```
1310
+ */
1311
+ function astroDetector(projectPath, packageJson) {
1312
+ const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1313
+ const sources = [];
1314
+ let confidence = 0;
1315
+ let version;
1316
+ const deps = collectAllDependencies(pkg);
1317
+ if (deps['astro']) {
1318
+ confidence += 70;
1319
+ version = parseVersionString(deps['astro']);
1320
+ sources.push({ type: 'package.json', field: 'dependencies.astro' });
1615
1321
  }
1322
+ if (exists(node_path.join(projectPath, 'astro.config.mjs')) ||
1323
+ exists(node_path.join(projectPath, 'astro.config.ts')) ||
1324
+ exists(node_path.join(projectPath, 'astro.config.js'))) {
1325
+ confidence += 25;
1326
+ sources.push({ type: 'config-file', path: 'astro.config.*' });
1327
+ }
1328
+ if (exists(node_path.join(projectPath, 'src', 'pages'))) {
1329
+ confidence += 5;
1330
+ sources.push({ type: 'directory', path: 'src/pages/' });
1331
+ }
1332
+ if (confidence === 0) {
1333
+ return null;
1334
+ }
1335
+ return {
1336
+ id: 'astro',
1337
+ name: 'Astro',
1338
+ category: 'meta-framework',
1339
+ version,
1340
+ confidence: index_cjs_js$8.min(confidence, 100),
1341
+ detectedFrom: sources,
1342
+ };
1343
+ }
1344
+
1345
+ /**
1346
+ * Detect Gatsby in project.
1347
+ *
1348
+ * @param projectPath - Project directory path
1349
+ * @param packageJson - Optional pre-loaded package.json
1350
+ * @returns Detection result or null if not detected
1351
+ *
1352
+ * @example Detecting Gatsby framework
1353
+ * ```typescript
1354
+ * const result = gatsbyDetector('/path/to/gatsby-blog', {
1355
+ * dependencies: {
1356
+ * 'gatsby': '^5.0.0',
1357
+ * 'gatsby-plugin-image': '^3.0.0',
1358
+ * 'gatsby-source-filesystem': '^5.0.0'
1359
+ * }
1360
+ * })
1361
+ * // => {
1362
+ * // id: 'gatsby',
1363
+ * // name: 'Gatsby',
1364
+ * // category: 'meta-framework',
1365
+ * // version: '5.0.0',
1366
+ * // confidence: 75,
1367
+ * // detectedFrom: [
1368
+ * // { type: 'package.json', field: 'dependencies.gatsby' },
1369
+ * // { type: 'package.json', field: 'dependencies (gatsby plugins)' }
1370
+ * // ]
1371
+ * // }
1372
+ * ```
1373
+ */
1374
+ function gatsbyDetector(projectPath, packageJson) {
1375
+ const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1376
+ const sources = [];
1377
+ let confidence = 0;
1378
+ let version;
1379
+ const deps = collectAllDependencies(pkg);
1616
1380
  if (deps['gatsby']) {
1617
- metaFrameworks.push({
1618
- id: 'gatsby',
1619
- name: 'Gatsby',
1620
- category: 'meta-framework',
1621
- version: parseVersionString(deps['gatsby']),
1622
- confidence: 90,
1623
- detectedFrom: [{ type: 'package.json', field: 'dependencies.gatsby' }],
1624
- });
1381
+ confidence += 70;
1382
+ version = parseVersionString(deps['gatsby']);
1383
+ sources.push({ type: 'package.json', field: 'dependencies.gatsby' });
1625
1384
  }
1626
- if (deps['@remix-run/react'] || deps['remix']) {
1627
- metaFrameworks.push({
1628
- id: 'remix',
1629
- name: 'Remix',
1630
- category: 'meta-framework',
1631
- version: parseVersionString(deps['@remix-run/react'] ?? deps['remix']),
1632
- confidence: 90,
1633
- detectedFrom: [{ type: 'package.json', field: 'dependencies.@remix-run/react' }],
1634
- });
1385
+ if (exists(node_path.join(projectPath, 'gatsby-config.js')) || exists(node_path.join(projectPath, 'gatsby-config.ts'))) {
1386
+ confidence += 25;
1387
+ sources.push({ type: 'config-file', path: 'gatsby-config.*' });
1388
+ }
1389
+ const gatsbyPlugins = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('gatsby-plugin-') || d.startsWith('gatsby-source-'));
1390
+ if (gatsbyPlugins.length > 0) {
1391
+ confidence += 5;
1392
+ sources.push({ type: 'package.json', field: 'dependencies (gatsby plugins)' });
1635
1393
  }
1636
1394
  if (confidence === 0) {
1637
1395
  return null;
1638
1396
  }
1639
1397
  return {
1640
- id: 'react',
1641
- name: 'React',
1642
- category: 'frontend',
1398
+ id: 'gatsby',
1399
+ name: 'Gatsby',
1400
+ category: 'meta-framework',
1643
1401
  version,
1644
- confidence: min(confidence, 100),
1402
+ confidence: index_cjs_js$8.min(confidence, 100),
1645
1403
  detectedFrom: sources,
1646
- metaFrameworks: metaFrameworks.length > 0 ? metaFrameworks : undefined,
1647
1404
  };
1648
1405
  }
1649
1406
 
@@ -1653,6 +1410,21 @@ function reactDetector(projectPath, packageJson) {
1653
1410
  * @param projectPath - Project directory path
1654
1411
  * @param packageJson - Optional pre-loaded package.json
1655
1412
  * @returns Detection result or null if not detected
1413
+ *
1414
+ * @example Detecting Next.js framework
1415
+ * ```typescript
1416
+ * const result = nextjsDetector('/path/to/nextjs-app', {
1417
+ * dependencies: { 'next': '^14.0.0', 'react': '^18.0.0' }
1418
+ * })
1419
+ * // => {
1420
+ * // id: 'nextjs',
1421
+ * // name: 'Next.js',
1422
+ * // category: 'meta-framework',
1423
+ * // version: '14.0.0',
1424
+ * // confidence: 70,
1425
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.next' }]
1426
+ * // }
1427
+ * ```
1656
1428
  */
1657
1429
  function nextjsDetector(projectPath, packageJson) {
1658
1430
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -1686,230 +1458,335 @@ function nextjsDetector(projectPath, packageJson) {
1686
1458
  name: 'Next.js',
1687
1459
  category: 'meta-framework',
1688
1460
  version,
1689
- confidence: min(confidence, 100),
1461
+ confidence: index_cjs_js$8.min(confidence, 100),
1690
1462
  detectedFrom: sources,
1691
1463
  };
1692
1464
  }
1693
1465
 
1694
1466
  /**
1695
- * Detect Remix in project.
1467
+ * Detect Nuxt in project.
1696
1468
  *
1697
1469
  * @param projectPath - Project directory path
1698
1470
  * @param packageJson - Optional pre-loaded package.json
1699
1471
  * @returns Detection result or null if not detected
1472
+ *
1473
+ * @example Detecting Nuxt framework
1474
+ * ```typescript
1475
+ * const result = nuxtDetector('/path/to/nuxt-app', {
1476
+ * dependencies: { 'nuxt': '^3.0.0', 'vue': '^3.0.0' }
1477
+ * })
1478
+ * // => {
1479
+ * // id: 'nuxt',
1480
+ * // name: 'Nuxt',
1481
+ * // category: 'meta-framework',
1482
+ * // version: '3.0.0',
1483
+ * // confidence: 70,
1484
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.nuxt' }]
1485
+ * // }
1486
+ * ```
1700
1487
  */
1701
- function remixDetector(projectPath, packageJson) {
1488
+ function nuxtDetector(projectPath, packageJson) {
1702
1489
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1703
1490
  const sources = [];
1704
1491
  let confidence = 0;
1705
1492
  let version;
1706
1493
  const deps = collectAllDependencies(pkg);
1707
- if (deps['@remix-run/react']) {
1494
+ if (deps['nuxt'] || deps['nuxt3']) {
1708
1495
  confidence += 70;
1709
- version = parseVersionString(deps['@remix-run/react']);
1710
- sources.push({ type: 'package.json', field: 'dependencies.@remix-run/react' });
1496
+ version = parseVersionString(deps['nuxt'] ?? deps['nuxt3']);
1497
+ sources.push({ type: 'package.json', field: 'dependencies.nuxt' });
1711
1498
  }
1712
- if (deps['@remix-run/node'] || deps['@remix-run/cloudflare'] || deps['@remix-run/deno']) {
1713
- confidence += 20;
1714
- sources.push({ type: 'package.json', field: 'dependencies.@remix-run/*' });
1499
+ if (exists(node_path.join(projectPath, 'nuxt.config.js')) || exists(node_path.join(projectPath, 'nuxt.config.ts'))) {
1500
+ confidence += 25;
1501
+ sources.push({ type: 'config-file', path: 'nuxt.config.*' });
1715
1502
  }
1716
- if (exists(node_path.join(projectPath, 'remix.config.js')) || exists(node_path.join(projectPath, 'remix.config.ts'))) {
1717
- confidence += 10;
1718
- sources.push({ type: 'config-file', path: 'remix.config.*' });
1503
+ if (exists(node_path.join(projectPath, 'pages'))) {
1504
+ confidence += 5;
1505
+ sources.push({ type: 'directory', path: 'pages/' });
1719
1506
  }
1720
1507
  if (confidence === 0) {
1721
1508
  return null;
1722
1509
  }
1723
1510
  return {
1724
- id: 'remix',
1725
- name: 'Remix',
1511
+ id: 'nuxt',
1512
+ name: 'Nuxt',
1726
1513
  category: 'meta-framework',
1727
1514
  version,
1728
- confidence: min(confidence, 100),
1515
+ confidence: index_cjs_js$8.min(confidence, 100),
1729
1516
  detectedFrom: sources,
1730
1517
  };
1731
1518
  }
1732
1519
 
1733
1520
  /**
1734
- * Detect Gatsby in project.
1521
+ * Detect Qwik in project.
1735
1522
  *
1736
1523
  * @param projectPath - Project directory path
1737
1524
  * @param packageJson - Optional pre-loaded package.json
1738
1525
  * @returns Detection result or null if not detected
1526
+ *
1527
+ * @example Detecting Qwik framework
1528
+ * ```typescript
1529
+ * const result = qwikDetector('/path/to/qwik-app', {
1530
+ * dependencies: {
1531
+ * '@builder.io/qwik': '^1.0.0',
1532
+ * '@builder.io/qwik-city': '^1.0.0'
1533
+ * }
1534
+ * })
1535
+ * // => {
1536
+ * // id: 'qwik',
1537
+ * // name: 'Qwik',
1538
+ * // category: 'frontend',
1539
+ * // version: '1.0.0',
1540
+ * // confidence: 90,
1541
+ * // detectedFrom: [
1542
+ * // { type: 'package.json', field: 'dependencies.@builder.io/qwik' },
1543
+ * // { type: 'package.json', field: 'dependencies.@builder.io/qwik-city' }
1544
+ * // ]
1545
+ * // }
1546
+ * ```
1739
1547
  */
1740
- function gatsbyDetector(projectPath, packageJson) {
1548
+ function qwikDetector(projectPath, packageJson) {
1741
1549
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1742
1550
  const sources = [];
1743
1551
  let confidence = 0;
1744
1552
  let version;
1745
1553
  const deps = collectAllDependencies(pkg);
1746
- if (deps['gatsby']) {
1554
+ if (deps['@builder.io/qwik']) {
1747
1555
  confidence += 70;
1748
- version = parseVersionString(deps['gatsby']);
1749
- sources.push({ type: 'package.json', field: 'dependencies.gatsby' });
1556
+ version = parseVersionString(deps['@builder.io/qwik']);
1557
+ sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik' });
1750
1558
  }
1751
- if (exists(node_path.join(projectPath, 'gatsby-config.js')) || exists(node_path.join(projectPath, 'gatsby-config.ts'))) {
1752
- confidence += 25;
1753
- sources.push({ type: 'config-file', path: 'gatsby-config.*' });
1559
+ if (deps['@builder.io/qwik-city']) {
1560
+ confidence += 20;
1561
+ sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik-city' });
1754
1562
  }
1755
- const gatsbyPlugins = keys(deps).filter((d) => d.startsWith('gatsby-plugin-') || d.startsWith('gatsby-source-'));
1756
- if (gatsbyPlugins.length > 0) {
1757
- confidence += 5;
1758
- sources.push({ type: 'package.json', field: 'dependencies (gatsby plugins)' });
1563
+ if (exists(node_path.join(projectPath, 'qwik.config.ts')) || exists(node_path.join(projectPath, 'qwik.config.js'))) {
1564
+ confidence += 10;
1565
+ sources.push({ type: 'config-file', path: 'qwik.config.*' });
1759
1566
  }
1760
1567
  if (confidence === 0) {
1761
1568
  return null;
1762
1569
  }
1763
1570
  return {
1764
- id: 'gatsby',
1765
- name: 'Gatsby',
1766
- category: 'meta-framework',
1571
+ id: 'qwik',
1572
+ name: 'Qwik',
1573
+ category: 'frontend',
1767
1574
  version,
1768
- confidence: min(confidence, 100),
1575
+ confidence: index_cjs_js$8.min(confidence, 100),
1769
1576
  detectedFrom: sources,
1770
1577
  };
1771
1578
  }
1772
1579
 
1773
1580
  /**
1774
- * Detect Vue in project.
1581
+ * Detect React in project.
1775
1582
  *
1776
1583
  * @param projectPath - Project directory path
1777
1584
  * @param packageJson - Optional pre-loaded package.json
1778
1585
  * @returns Detection result or null if not detected
1586
+ *
1587
+ * @example Detecting React library
1588
+ * ```typescript
1589
+ * const result = reactDetector('/path/to/react-app', {
1590
+ * dependencies: { 'react': '^18.0.0', 'react-dom': '^18.0.0' }
1591
+ * })
1592
+ * // => {
1593
+ * // id: 'react',
1594
+ * // name: 'React',
1595
+ * // category: 'frontend',
1596
+ * // version: '18.0.0',
1597
+ * // confidence: 80,
1598
+ * // detectedFrom: [
1599
+ * // { type: 'package.json', field: 'dependencies.react' },
1600
+ * // { type: 'package.json', field: 'dependencies.react-dom' }
1601
+ * // ]
1602
+ * // }
1603
+ * ```
1779
1604
  */
1780
- function vueDetector(projectPath, packageJson) {
1605
+ function reactDetector(projectPath, packageJson) {
1781
1606
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1782
1607
  const sources = [];
1783
1608
  let confidence = 0;
1784
1609
  let version;
1785
1610
  const metaFrameworks = [];
1786
1611
  const deps = collectAllDependencies(pkg);
1787
- if (deps['vue']) {
1788
- confidence += 70;
1789
- version = parseVersionString(deps['vue']);
1790
- sources.push({ type: 'package.json', field: 'dependencies.vue' });
1612
+ if (deps['react']) {
1613
+ confidence += 60;
1614
+ version = parseVersionString(deps['react']);
1615
+ sources.push({ type: 'package.json', field: 'dependencies.react' });
1791
1616
  }
1792
- if (deps['@vue/cli-service']) {
1793
- confidence += 15;
1794
- sources.push({ type: 'package.json', field: 'dependencies.@vue/cli-service' });
1617
+ if (deps['react-dom']) {
1618
+ confidence += 20;
1619
+ sources.push({ type: 'package.json', field: 'dependencies.react-dom' });
1795
1620
  }
1796
- const hasVueFiles = exists(node_path.join(projectPath, 'src', 'App.vue')) || exists(node_path.join(projectPath, 'src', 'main.vue'));
1797
- if (hasVueFiles) {
1621
+ if (deps['react-native']) {
1622
+ confidence += 20;
1623
+ sources.push({ type: 'package.json', field: 'dependencies.react-native' });
1624
+ }
1625
+ const hasJsxFiles = exists(node_path.join(projectPath, 'src', 'App.tsx')) ||
1626
+ exists(node_path.join(projectPath, 'src', 'App.jsx')) ||
1627
+ exists(node_path.join(projectPath, 'src', 'index.tsx')) ||
1628
+ exists(node_path.join(projectPath, 'src', 'index.jsx'));
1629
+ if (hasJsxFiles) {
1798
1630
  confidence += 10;
1799
- sources.push({ type: 'directory', path: 'src/*.vue' });
1631
+ sources.push({ type: 'directory', path: 'src/*.tsx or src/*.jsx' });
1800
1632
  }
1801
- if (exists(node_path.join(projectPath, 'vue.config.js'))) {
1802
- confidence += 5;
1803
- sources.push({ type: 'config-file', path: 'vue.config.js' });
1633
+ if (deps['next']) {
1634
+ metaFrameworks.push({
1635
+ id: 'nextjs',
1636
+ name: 'Next.js',
1637
+ category: 'meta-framework',
1638
+ version: parseVersionString(deps['next']),
1639
+ confidence: 90,
1640
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.next' }],
1641
+ });
1804
1642
  }
1805
- if (deps['nuxt'] || deps['nuxt3']) {
1643
+ if (deps['gatsby']) {
1806
1644
  metaFrameworks.push({
1807
- id: 'nuxt',
1808
- name: 'Nuxt',
1645
+ id: 'gatsby',
1646
+ name: 'Gatsby',
1809
1647
  category: 'meta-framework',
1810
- version: parseVersionString(deps['nuxt'] ?? deps['nuxt3']),
1648
+ version: parseVersionString(deps['gatsby']),
1811
1649
  confidence: 90,
1812
- detectedFrom: [{ type: 'package.json', field: 'dependencies.nuxt' }],
1650
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.gatsby' }],
1651
+ });
1652
+ }
1653
+ if (deps['@remix-run/react'] || deps['remix']) {
1654
+ metaFrameworks.push({
1655
+ id: 'remix',
1656
+ name: 'Remix',
1657
+ category: 'meta-framework',
1658
+ version: parseVersionString(deps['@remix-run/react'] ?? deps['remix']),
1659
+ confidence: 90,
1660
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.@remix-run/react' }],
1813
1661
  });
1814
1662
  }
1815
1663
  if (confidence === 0) {
1816
1664
  return null;
1817
1665
  }
1818
1666
  return {
1819
- id: 'vue',
1820
- name: 'Vue',
1667
+ id: 'react',
1668
+ name: 'React',
1821
1669
  category: 'frontend',
1822
1670
  version,
1823
- confidence: min(confidence, 100),
1671
+ confidence: index_cjs_js$8.min(confidence, 100),
1824
1672
  detectedFrom: sources,
1825
1673
  metaFrameworks: metaFrameworks.length > 0 ? metaFrameworks : undefined,
1826
1674
  };
1827
1675
  }
1828
1676
 
1829
1677
  /**
1830
- * Detect Nuxt in project.
1678
+ * Detect Remix in project.
1831
1679
  *
1832
1680
  * @param projectPath - Project directory path
1833
1681
  * @param packageJson - Optional pre-loaded package.json
1834
1682
  * @returns Detection result or null if not detected
1683
+ *
1684
+ * @example Detecting Remix framework
1685
+ * ```typescript
1686
+ * const result = remixDetector('/path/to/remix-app', {
1687
+ * dependencies: {
1688
+ * '@remix-run/react': '^2.0.0',
1689
+ * '@remix-run/node': '^2.0.0'
1690
+ * }
1691
+ * })
1692
+ * // => {
1693
+ * // id: 'remix',
1694
+ * // name: 'Remix',
1695
+ * // category: 'meta-framework',
1696
+ * // version: '2.0.0',
1697
+ * // confidence: 90,
1698
+ * // detectedFrom: [
1699
+ * // { type: 'package.json', field: 'dependencies.@remix-run/react' },
1700
+ * // { type: 'package.json', field: 'dependencies.@remix-run/*' }
1701
+ * // ]
1702
+ * // }
1703
+ * ```
1835
1704
  */
1836
- function nuxtDetector(projectPath, packageJson) {
1705
+ function remixDetector(projectPath, packageJson) {
1837
1706
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1838
1707
  const sources = [];
1839
1708
  let confidence = 0;
1840
1709
  let version;
1841
1710
  const deps = collectAllDependencies(pkg);
1842
- if (deps['nuxt'] || deps['nuxt3']) {
1711
+ if (deps['@remix-run/react']) {
1843
1712
  confidence += 70;
1844
- version = parseVersionString(deps['nuxt'] ?? deps['nuxt3']);
1845
- sources.push({ type: 'package.json', field: 'dependencies.nuxt' });
1713
+ version = parseVersionString(deps['@remix-run/react']);
1714
+ sources.push({ type: 'package.json', field: 'dependencies.@remix-run/react' });
1846
1715
  }
1847
- if (exists(node_path.join(projectPath, 'nuxt.config.js')) || exists(node_path.join(projectPath, 'nuxt.config.ts'))) {
1848
- confidence += 25;
1849
- sources.push({ type: 'config-file', path: 'nuxt.config.*' });
1716
+ if (deps['@remix-run/node'] || deps['@remix-run/cloudflare'] || deps['@remix-run/deno']) {
1717
+ confidence += 20;
1718
+ sources.push({ type: 'package.json', field: 'dependencies.@remix-run/*' });
1850
1719
  }
1851
- if (exists(node_path.join(projectPath, 'pages'))) {
1852
- confidence += 5;
1853
- sources.push({ type: 'directory', path: 'pages/' });
1720
+ if (exists(node_path.join(projectPath, 'remix.config.js')) || exists(node_path.join(projectPath, 'remix.config.ts'))) {
1721
+ confidence += 10;
1722
+ sources.push({ type: 'config-file', path: 'remix.config.*' });
1854
1723
  }
1855
1724
  if (confidence === 0) {
1856
1725
  return null;
1857
1726
  }
1858
1727
  return {
1859
- id: 'nuxt',
1860
- name: 'Nuxt',
1728
+ id: 'remix',
1729
+ name: 'Remix',
1861
1730
  category: 'meta-framework',
1862
1731
  version,
1863
- confidence: min(confidence, 100),
1732
+ confidence: index_cjs_js$8.min(confidence, 100),
1864
1733
  detectedFrom: sources,
1865
1734
  };
1866
1735
  }
1867
1736
 
1868
1737
  /**
1869
- * Detect Angular in project.
1738
+ * Detect Solid in project.
1870
1739
  *
1871
1740
  * @param projectPath - Project directory path
1872
1741
  * @param packageJson - Optional pre-loaded package.json
1873
1742
  * @returns Detection result or null if not detected
1743
+ *
1744
+ * @example Detecting Solid.js framework
1745
+ * ```typescript
1746
+ * const result = solidDetector('/path/to/solid-app', {
1747
+ * dependencies: { 'solid-js': '^1.8.0', 'vite-plugin-solid': '^2.0.0' }
1748
+ * })
1749
+ * // => {
1750
+ * // id: 'solid',
1751
+ * // name: 'Solid',
1752
+ * // category: 'frontend',
1753
+ * // version: '1.8.0',
1754
+ * // confidence: 90,
1755
+ * // detectedFrom: [
1756
+ * // { type: 'package.json', field: 'dependencies.solid-js' },
1757
+ * // { type: 'package.json', field: 'dependencies.vite-plugin-solid' }
1758
+ * // ]
1759
+ * // }
1760
+ * ```
1874
1761
  */
1875
- function angularDetector(projectPath, packageJson) {
1762
+ function solidDetector(projectPath, packageJson) {
1876
1763
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
1877
1764
  const sources = [];
1878
1765
  let confidence = 0;
1879
1766
  let version;
1880
1767
  const deps = collectAllDependencies(pkg);
1881
- if (deps['@angular/core']) {
1768
+ if (deps['solid-js']) {
1882
1769
  confidence += 70;
1883
- version = parseVersionString(deps['@angular/core']);
1884
- sources.push({ type: 'package.json', field: 'dependencies.@angular/core' });
1885
- }
1886
- if (deps['@angular/cli']) {
1887
- confidence += 15;
1888
- sources.push({ type: 'package.json', field: 'dependencies.@angular/cli' });
1770
+ version = parseVersionString(deps['solid-js']);
1771
+ sources.push({ type: 'package.json', field: 'dependencies.solid-js' });
1889
1772
  }
1890
- if (exists(node_path.join(projectPath, 'angular.json'))) {
1891
- confidence += 15;
1892
- sources.push({ type: 'config-file', path: 'angular.json' });
1773
+ if (deps['vite-plugin-solid']) {
1774
+ confidence += 20;
1775
+ sources.push({ type: 'package.json', field: 'dependencies.vite-plugin-solid' });
1893
1776
  }
1894
- if (deps['angular'] && !deps['@angular/core']) {
1895
- return {
1896
- id: 'angularjs',
1897
- name: 'AngularJS (Legacy)',
1898
- category: 'frontend',
1899
- version: parseVersionString(deps['angular']),
1900
- confidence: 80,
1901
- detectedFrom: [{ type: 'package.json', field: 'dependencies.angular' }],
1902
- };
1777
+ if (deps['solid-start'] || deps['@solidjs/start']) {
1778
+ confidence += 10;
1779
+ sources.push({ type: 'package.json', field: 'dependencies.solid-start' });
1903
1780
  }
1904
1781
  if (confidence === 0) {
1905
1782
  return null;
1906
1783
  }
1907
1784
  return {
1908
- id: 'angular',
1909
- name: 'Angular',
1785
+ id: 'solid',
1786
+ name: 'Solid',
1910
1787
  category: 'frontend',
1911
1788
  version,
1912
- confidence: min(confidence, 100),
1789
+ confidence: index_cjs_js$8.min(confidence, 100),
1913
1790
  detectedFrom: sources,
1914
1791
  };
1915
1792
  }
@@ -1920,6 +1797,21 @@ function angularDetector(projectPath, packageJson) {
1920
1797
  * @param projectPath - Project directory path
1921
1798
  * @param packageJson - Optional pre-loaded package.json
1922
1799
  * @returns Detection result or null if not detected
1800
+ *
1801
+ * @example Detecting Svelte framework
1802
+ * ```typescript
1803
+ * const result = svelteDetector('/path/to/svelte-app', {
1804
+ * devDependencies: { 'svelte': '^4.0.0' }
1805
+ * })
1806
+ * // => {
1807
+ * // id: 'svelte',
1808
+ * // name: 'Svelte',
1809
+ * // category: 'frontend',
1810
+ * // version: '4.0.0',
1811
+ * // confidence: 70,
1812
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.svelte' }]
1813
+ * // }
1814
+ * ```
1923
1815
  */
1924
1816
  function svelteDetector(projectPath, packageJson) {
1925
1817
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -1960,7 +1852,7 @@ function svelteDetector(projectPath, packageJson) {
1960
1852
  name: 'Svelte',
1961
1853
  category: 'frontend',
1962
1854
  version,
1963
- confidence: min(confidence, 100),
1855
+ confidence: index_cjs_js$8.min(confidence, 100),
1964
1856
  detectedFrom: sources,
1965
1857
  metaFrameworks: metaFrameworks.length > 0 ? metaFrameworks : undefined,
1966
1858
  };
@@ -1972,6 +1864,21 @@ function svelteDetector(projectPath, packageJson) {
1972
1864
  * @param projectPath - Project directory path
1973
1865
  * @param packageJson - Optional pre-loaded package.json
1974
1866
  * @returns Detection result or null if not detected
1867
+ *
1868
+ * @example Detecting SvelteKit framework
1869
+ * ```typescript
1870
+ * const result = sveltekitDetector('/path/to/sveltekit-app', {
1871
+ * devDependencies: { '@sveltejs/kit': '^2.0.0', 'svelte': '^4.0.0' }
1872
+ * })
1873
+ * // => {
1874
+ * // id: 'sveltekit',
1875
+ * // name: 'SvelteKit',
1876
+ * // category: 'meta-framework',
1877
+ * // version: '2.0.0',
1878
+ * // confidence: 70,
1879
+ * // detectedFrom: [{ type: 'package.json', field: 'dependencies.@sveltejs/kit' }]
1880
+ * // }
1881
+ * ```
1975
1882
  */
1976
1883
  function sveltekitDetector(projectPath, packageJson) {
1977
1884
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2000,127 +1907,82 @@ function sveltekitDetector(projectPath, packageJson) {
2000
1907
  name: 'SvelteKit',
2001
1908
  category: 'meta-framework',
2002
1909
  version,
2003
- confidence: min(confidence, 100),
1910
+ confidence: index_cjs_js$8.min(confidence, 100),
2004
1911
  detectedFrom: sources,
2005
1912
  };
2006
1913
  }
2007
1914
 
2008
1915
  /**
2009
- * Detect Solid in project.
1916
+ * Detect Vue in project.
2010
1917
  *
2011
1918
  * @param projectPath - Project directory path
2012
1919
  * @param packageJson - Optional pre-loaded package.json
2013
1920
  * @returns Detection result or null if not detected
2014
- */
2015
- function solidDetector(projectPath, packageJson) {
2016
- const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2017
- const sources = [];
2018
- let confidence = 0;
2019
- let version;
2020
- const deps = collectAllDependencies(pkg);
2021
- if (deps['solid-js']) {
2022
- confidence += 70;
2023
- version = parseVersionString(deps['solid-js']);
2024
- sources.push({ type: 'package.json', field: 'dependencies.solid-js' });
2025
- }
2026
- if (deps['vite-plugin-solid']) {
2027
- confidence += 20;
2028
- sources.push({ type: 'package.json', field: 'dependencies.vite-plugin-solid' });
2029
- }
2030
- if (deps['solid-start'] || deps['@solidjs/start']) {
2031
- confidence += 10;
2032
- sources.push({ type: 'package.json', field: 'dependencies.solid-start' });
2033
- }
2034
- if (confidence === 0) {
2035
- return null;
2036
- }
2037
- return {
2038
- id: 'solid',
2039
- name: 'Solid',
2040
- category: 'frontend',
2041
- version,
2042
- confidence: min(confidence, 100),
2043
- detectedFrom: sources,
2044
- };
2045
- }
2046
-
2047
- /**
2048
- * Detect Qwik in project.
2049
1921
  *
2050
- * @param projectPath - Project directory path
2051
- * @param packageJson - Optional pre-loaded package.json
2052
- * @returns Detection result or null if not detected
1922
+ * @example Detecting Vue.js framework
1923
+ * ```typescript
1924
+ * const result = vueDetector('/path/to/vue-app', {
1925
+ * dependencies: { 'vue': '^3.0.0', '@vue/cli-service': '^5.0.0' }
1926
+ * })
1927
+ * // => {
1928
+ * // id: 'vue',
1929
+ * // name: 'Vue',
1930
+ * // category: 'frontend',
1931
+ * // version: '3.0.0',
1932
+ * // confidence: 85,
1933
+ * // detectedFrom: [
1934
+ * // { type: 'package.json', field: 'dependencies.vue' },
1935
+ * // { type: 'package.json', field: 'dependencies.@vue/cli-service' }
1936
+ * // ]
1937
+ * // }
1938
+ * ```
2053
1939
  */
2054
- function qwikDetector(projectPath, packageJson) {
1940
+ function vueDetector(projectPath, packageJson) {
2055
1941
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2056
1942
  const sources = [];
2057
1943
  let confidence = 0;
2058
1944
  let version;
1945
+ const metaFrameworks = [];
2059
1946
  const deps = collectAllDependencies(pkg);
2060
- if (deps['@builder.io/qwik']) {
1947
+ if (deps['vue']) {
2061
1948
  confidence += 70;
2062
- version = parseVersionString(deps['@builder.io/qwik']);
2063
- sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik' });
1949
+ version = parseVersionString(deps['vue']);
1950
+ sources.push({ type: 'package.json', field: 'dependencies.vue' });
2064
1951
  }
2065
- if (deps['@builder.io/qwik-city']) {
2066
- confidence += 20;
2067
- sources.push({ type: 'package.json', field: 'dependencies.@builder.io/qwik-city' });
1952
+ if (deps['@vue/cli-service']) {
1953
+ confidence += 15;
1954
+ sources.push({ type: 'package.json', field: 'dependencies.@vue/cli-service' });
2068
1955
  }
2069
- if (exists(node_path.join(projectPath, 'qwik.config.ts')) || exists(node_path.join(projectPath, 'qwik.config.js'))) {
1956
+ const hasVueFiles = exists(node_path.join(projectPath, 'src', 'App.vue')) || exists(node_path.join(projectPath, 'src', 'main.vue'));
1957
+ if (hasVueFiles) {
2070
1958
  confidence += 10;
2071
- sources.push({ type: 'config-file', path: 'qwik.config.*' });
2072
- }
2073
- if (confidence === 0) {
2074
- return null;
2075
- }
2076
- return {
2077
- id: 'qwik',
2078
- name: 'Qwik',
2079
- category: 'frontend',
2080
- version,
2081
- confidence: min(confidence, 100),
2082
- detectedFrom: sources,
2083
- };
2084
- }
2085
-
2086
- /**
2087
- * Detect Astro in project.
2088
- *
2089
- * @param projectPath - Project directory path
2090
- * @param packageJson - Optional pre-loaded package.json
2091
- * @returns Detection result or null if not detected
2092
- */
2093
- function astroDetector(projectPath, packageJson) {
2094
- const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2095
- const sources = [];
2096
- let confidence = 0;
2097
- let version;
2098
- const deps = collectAllDependencies(pkg);
2099
- if (deps['astro']) {
2100
- confidence += 70;
2101
- version = parseVersionString(deps['astro']);
2102
- sources.push({ type: 'package.json', field: 'dependencies.astro' });
2103
- }
2104
- if (exists(node_path.join(projectPath, 'astro.config.mjs')) ||
2105
- exists(node_path.join(projectPath, 'astro.config.ts')) ||
2106
- exists(node_path.join(projectPath, 'astro.config.js'))) {
2107
- confidence += 25;
2108
- sources.push({ type: 'config-file', path: 'astro.config.*' });
1959
+ sources.push({ type: 'directory', path: 'src/*.vue' });
2109
1960
  }
2110
- if (exists(node_path.join(projectPath, 'src', 'pages'))) {
1961
+ if (exists(node_path.join(projectPath, 'vue.config.js'))) {
2111
1962
  confidence += 5;
2112
- sources.push({ type: 'directory', path: 'src/pages/' });
1963
+ sources.push({ type: 'config-file', path: 'vue.config.js' });
1964
+ }
1965
+ if (deps['nuxt'] || deps['nuxt3']) {
1966
+ metaFrameworks.push({
1967
+ id: 'nuxt',
1968
+ name: 'Nuxt',
1969
+ category: 'meta-framework',
1970
+ version: parseVersionString(deps['nuxt'] ?? deps['nuxt3']),
1971
+ confidence: 90,
1972
+ detectedFrom: [{ type: 'package.json', field: 'dependencies.nuxt' }],
1973
+ });
2113
1974
  }
2114
1975
  if (confidence === 0) {
2115
1976
  return null;
2116
1977
  }
2117
1978
  return {
2118
- id: 'astro',
2119
- name: 'Astro',
2120
- category: 'meta-framework',
1979
+ id: 'vue',
1980
+ name: 'Vue',
1981
+ category: 'frontend',
2121
1982
  version,
2122
- confidence: min(confidence, 100),
1983
+ confidence: index_cjs_js$8.min(confidence, 100),
2123
1984
  detectedFrom: sources,
1985
+ metaFrameworks: metaFrameworks.length > 0 ? metaFrameworks : undefined,
2124
1986
  };
2125
1987
  }
2126
1988
 
@@ -2145,6 +2007,17 @@ const frameworkDetectors = [
2145
2007
  * @param projectPath - Project directory path
2146
2008
  * @param packageJson - Optional pre-loaded package.json
2147
2009
  * @returns Array of detected frameworks, sorted by confidence
2010
+ *
2011
+ * @example Detecting multiple frontend frameworks
2012
+ * ```typescript
2013
+ * const frameworks = detectFrontendFrameworks('/path/to/nextjs-app', {
2014
+ * dependencies: { 'react': '^18.0.0', 'next': '^14.0.0' }
2015
+ * })
2016
+ * // => [
2017
+ * // { id: 'nextjs', name: 'Next.js', category: 'meta-framework', confidence: 70, ... },
2018
+ * // { id: 'react', name: 'React', category: 'frontend', confidence: 60, ... }
2019
+ * // ]
2020
+ * ```
2148
2021
  */
2149
2022
  function detectFrontendFrameworks(projectPath, packageJson) {
2150
2023
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2165,6 +2038,14 @@ function detectFrontendFrameworks(projectPath, packageJson) {
2165
2038
  * @param projectPath - Project directory path
2166
2039
  * @param packageJson - Optional pre-loaded package.json
2167
2040
  * @returns Detection result or null if not detected
2041
+ *
2042
+ * @example Detecting AngularJS framework
2043
+ * ```typescript
2044
+ * const result = angularJSDetector('/path/to/project', {
2045
+ * dependencies: { angular: '^1.8.0', 'angular-route': '^1.8.0' },
2046
+ * })
2047
+ * // => { id: 'angularjs', name: 'AngularJS', confidence: 85, version: '1.8.0', ... }
2048
+ * ```
2168
2049
  */
2169
2050
  function angularJSDetector(projectPath, packageJson) {
2170
2051
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2197,7 +2078,7 @@ function angularJSDetector(projectPath, packageJson) {
2197
2078
  name: 'AngularJS',
2198
2079
  category: 'legacy-frontend',
2199
2080
  version,
2200
- confidence: min(confidence, 100),
2081
+ confidence: index_cjs_js$8.min(confidence, 100),
2201
2082
  detectedFrom: sources,
2202
2083
  };
2203
2084
  }
@@ -2208,6 +2089,14 @@ function angularJSDetector(projectPath, packageJson) {
2208
2089
  * @param projectPath - Project directory path
2209
2090
  * @param packageJson - Optional pre-loaded package.json
2210
2091
  * @returns Detection result or null if not detected
2092
+ *
2093
+ * @example Detecting Backbone.js framework
2094
+ * ```typescript
2095
+ * const result = backboneDetector('/path/to/project', {
2096
+ * dependencies: { backbone: '^1.4.0', underscore: '^1.13.0' },
2097
+ * })
2098
+ * // => { id: 'backbone', name: 'Backbone.js', confidence: 85, version: '1.4.0', ... }
2099
+ * ```
2211
2100
  */
2212
2101
  function backboneDetector(projectPath, packageJson) {
2213
2102
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2240,7 +2129,7 @@ function backboneDetector(projectPath, packageJson) {
2240
2129
  name: 'Backbone.js',
2241
2130
  category: 'legacy-frontend',
2242
2131
  version,
2243
- confidence: min(confidence, 100),
2132
+ confidence: index_cjs_js$8.min(confidence, 100),
2244
2133
  detectedFrom: sources,
2245
2134
  };
2246
2135
  }
@@ -2251,6 +2140,15 @@ function backboneDetector(projectPath, packageJson) {
2251
2140
  * @param projectPath - Project directory path
2252
2141
  * @param packageJson - Optional pre-loaded package.json
2253
2142
  * @returns Detection result or null if not detected
2143
+ *
2144
+ * @example Detecting Ember.js framework
2145
+ * ```typescript
2146
+ * const result = emberDetector('/path/to/project', {
2147
+ * dependencies: { 'ember-source': '^4.0.0' },
2148
+ * devDependencies: { 'ember-cli': '^4.0.0' },
2149
+ * })
2150
+ * // => { id: 'ember', name: 'Ember.js', confidence: 90, version: '4.0.0', ... }
2151
+ * ```
2254
2152
  */
2255
2153
  function emberDetector(projectPath, packageJson) {
2256
2154
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2279,7 +2177,7 @@ function emberDetector(projectPath, packageJson) {
2279
2177
  name: 'Ember.js',
2280
2178
  category: 'legacy-frontend',
2281
2179
  version,
2282
- confidence: min(confidence, 100),
2180
+ confidence: index_cjs_js$8.min(confidence, 100),
2283
2181
  detectedFrom: sources,
2284
2182
  };
2285
2183
  }
@@ -2290,6 +2188,14 @@ function emberDetector(projectPath, packageJson) {
2290
2188
  * @param projectPath - Project directory path
2291
2189
  * @param packageJson - Optional pre-loaded package.json
2292
2190
  * @returns Detection result or null if not detected
2191
+ *
2192
+ * @example Detecting jQuery library
2193
+ * ```typescript
2194
+ * const result = jqueryDetector('/path/to/project', {
2195
+ * dependencies: { jquery: '^3.6.0', 'jquery-ui': '^1.13.0' },
2196
+ * })
2197
+ * // => { id: 'jquery', name: 'jQuery', confidence: 90, version: '3.6.0', ... }
2198
+ * ```
2293
2199
  */
2294
2200
  function jqueryDetector(projectPath, packageJson) {
2295
2201
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2314,41 +2220,99 @@ function jqueryDetector(projectPath, packageJson) {
2314
2220
  return null;
2315
2221
  }
2316
2222
  return {
2317
- id: 'jquery',
2318
- name: 'jQuery',
2319
- category: 'legacy-frontend',
2223
+ id: 'jquery',
2224
+ name: 'jQuery',
2225
+ category: 'legacy-frontend',
2226
+ version,
2227
+ confidence: index_cjs_js$8.min(confidence, 100),
2228
+ detectedFrom: sources,
2229
+ };
2230
+ }
2231
+
2232
+ /** All legacy framework detectors */
2233
+ const legacyDetectors = [
2234
+ { id: 'angularjs', name: 'AngularJS', category: 'legacy-frontend', detect: angularJSDetector },
2235
+ { id: 'backbone', name: 'Backbone.js', category: 'legacy-frontend', detect: backboneDetector },
2236
+ { id: 'ember', name: 'Ember.js', category: 'legacy-frontend', detect: emberDetector },
2237
+ { id: 'jquery', name: 'jQuery', category: 'legacy-frontend', detect: jqueryDetector },
2238
+ ];
2239
+ /**
2240
+ * Detect all legacy frameworks in project.
2241
+ *
2242
+ * @param projectPath - Project directory path
2243
+ * @param packageJson - Optional pre-loaded package.json
2244
+ * @returns Array of detected legacy frameworks, sorted by confidence
2245
+ *
2246
+ * @example Detecting legacy frameworks
2247
+ * ```typescript
2248
+ * const results = detectLegacyFrameworks('/path/to/project', {
2249
+ * dependencies: { jquery: '^3.6.0', backbone: '^1.4.0' },
2250
+ * })
2251
+ * // => [{ id: 'jquery', confidence: 80 }, { id: 'backbone', confidence: 70 }]
2252
+ * ```
2253
+ */
2254
+ function detectLegacyFrameworks(projectPath, packageJson) {
2255
+ const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2256
+ const results = [];
2257
+ for (const detector of legacyDetectors) {
2258
+ const detection = detector.detect(projectPath, pkg ?? undefined);
2259
+ if (detection) {
2260
+ results.push(detection);
2261
+ }
2262
+ }
2263
+ return results.sort((a, b) => b.confidence - a.confidence);
2264
+ }
2265
+
2266
+ /**
2267
+ * Detect Biome in project.
2268
+ *
2269
+ * @param projectPath - Project directory path
2270
+ * @param packageJson - Optional pre-loaded package.json
2271
+ * @returns Detection result or null if not detected
2272
+ *
2273
+ * @example Detecting Biome linter
2274
+ * ```typescript
2275
+ * const result = biomeDetector('/path/to/project', {
2276
+ * devDependencies: { '@biomejs/biome': '^1.5.0' },
2277
+ * })
2278
+ * // => { id: 'biome', name: 'Biome', confidence: 70, version: '1.5.0', ... }
2279
+ * ```
2280
+ */
2281
+ function biomeDetector(projectPath, packageJson) {
2282
+ const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2283
+ const sources = [];
2284
+ let confidence = 0;
2285
+ let configPath;
2286
+ let version;
2287
+ const deps = collectAllDependencies(pkg);
2288
+ if (deps['@biomejs/biome']) {
2289
+ confidence += 70;
2290
+ version = parseVersionString(deps['@biomejs/biome']);
2291
+ sources.push({ type: 'package.json', field: 'dependencies.@biomejs/biome' });
2292
+ }
2293
+ if (exists(node_path.join(projectPath, 'biome.json'))) {
2294
+ confidence += 30;
2295
+ configPath = 'biome.json';
2296
+ sources.push({ type: 'config-file', path: 'biome.json' });
2297
+ }
2298
+ if (!configPath && exists(node_path.join(projectPath, 'biome.jsonc'))) {
2299
+ confidence += 30;
2300
+ configPath = 'biome.jsonc';
2301
+ sources.push({ type: 'config-file', path: 'biome.jsonc' });
2302
+ }
2303
+ if (confidence === 0) {
2304
+ return null;
2305
+ }
2306
+ return {
2307
+ id: 'biome',
2308
+ name: 'Biome',
2320
2309
  version,
2321
- confidence: min(confidence, 100),
2310
+ configPath,
2311
+ confidence: index_cjs_js$8.min(confidence, 100),
2322
2312
  detectedFrom: sources,
2323
2313
  };
2324
2314
  }
2325
2315
 
2326
- /** All legacy framework detectors */
2327
- const legacyDetectors = [
2328
- { id: 'angularjs', name: 'AngularJS', category: 'legacy-frontend', detect: angularJSDetector },
2329
- { id: 'backbone', name: 'Backbone.js', category: 'legacy-frontend', detect: backboneDetector },
2330
- { id: 'ember', name: 'Ember.js', category: 'legacy-frontend', detect: emberDetector },
2331
- { id: 'jquery', name: 'jQuery', category: 'legacy-frontend', detect: jqueryDetector },
2332
- ];
2333
- /**
2334
- * Detect all legacy frameworks in project.
2335
- *
2336
- * @param projectPath - Project directory path
2337
- * @param packageJson - Optional pre-loaded package.json
2338
- * @returns Array of detected legacy frameworks, sorted by confidence
2339
- */
2340
- function detectLegacyFrameworks(projectPath, packageJson) {
2341
- const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2342
- const results = [];
2343
- for (const detector of legacyDetectors) {
2344
- const detection = detector.detect(projectPath, pkg ?? undefined);
2345
- if (detection) {
2346
- results.push(detection);
2347
- }
2348
- }
2349
- return results.sort((a, b) => b.confidence - a.confidence);
2350
- }
2351
-
2352
2316
  /** Config patterns for ESLint */
2353
2317
  const ESLINT_CONFIG_PATTERNS = [
2354
2318
  'eslint.config.js',
@@ -2368,6 +2332,15 @@ const ESLINT_CONFIG_PATTERNS = [
2368
2332
  * @param projectPath - Project directory path
2369
2333
  * @param packageJson - Optional pre-loaded package.json
2370
2334
  * @returns Detection result or null if not detected
2335
+ *
2336
+ * @example Detecting ESLint linter
2337
+ * ```typescript
2338
+ * const result = eslintDetector('/path/to/project', {
2339
+ * devDependencies: { eslint: '^8.50.0', '@typescript-eslint/parser': '^6.0.0' },
2340
+ * scripts: { lint: 'eslint src/' },
2341
+ * })
2342
+ * // => { id: 'eslint', name: 'ESLint', confidence: 65, version: '8.50.0', ... }
2343
+ * ```
2371
2344
  */
2372
2345
  function eslintDetector(projectPath, packageJson) {
2373
2346
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2389,7 +2362,7 @@ function eslintDetector(projectPath, packageJson) {
2389
2362
  confidence += 30;
2390
2363
  sources.push({ type: 'package.json', field: 'eslintConfig' });
2391
2364
  }
2392
- const eslintPlugins = keys(deps).filter((d) => d.startsWith('eslint-plugin-') || d.startsWith('@typescript-eslint/') || d.startsWith('eslint-config-'));
2365
+ const eslintPlugins = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('eslint-plugin-') || d.startsWith('@typescript-eslint/') || d.startsWith('eslint-config-'));
2393
2366
  if (eslintPlugins.length > 0) {
2394
2367
  confidence += 10;
2395
2368
  sources.push({ type: 'package.json', field: 'dependencies (eslint plugins)' });
@@ -2407,7 +2380,7 @@ function eslintDetector(projectPath, packageJson) {
2407
2380
  name: 'ESLint',
2408
2381
  version,
2409
2382
  configPath,
2410
- confidence: min(confidence, 100),
2383
+ confidence: index_cjs_js$8.min(confidence, 100),
2411
2384
  detectedFrom: sources,
2412
2385
  };
2413
2386
  }
@@ -2431,6 +2404,15 @@ const PRETTIER_CONFIG_PATTERNS = [
2431
2404
  * @param projectPath - Project directory path
2432
2405
  * @param packageJson - Optional pre-loaded package.json
2433
2406
  * @returns Detection result or null if not detected
2407
+ *
2408
+ * @example Detecting Prettier formatter
2409
+ * ```typescript
2410
+ * const result = prettierDetector('/path/to/project', {
2411
+ * devDependencies: { prettier: '^3.0.0' },
2412
+ * scripts: { format: 'prettier --write .' },
2413
+ * })
2414
+ * // => { id: 'prettier', name: 'Prettier', confidence: 55, version: '3.0.0', ... }
2415
+ * ```
2434
2416
  */
2435
2417
  function prettierDetector(projectPath, packageJson) {
2436
2418
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2456,7 +2438,7 @@ function prettierDetector(projectPath, packageJson) {
2456
2438
  confidence += 10;
2457
2439
  sources.push({ type: 'config-file', path: '.prettierignore' });
2458
2440
  }
2459
- const prettierPlugins = keys(deps).filter((d) => d.startsWith('prettier-plugin-'));
2441
+ const prettierPlugins = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('prettier-plugin-'));
2460
2442
  if (prettierPlugins.length > 0) {
2461
2443
  confidence += 5;
2462
2444
  sources.push({ type: 'package.json', field: 'dependencies (prettier plugins)' });
@@ -2474,7 +2456,7 @@ function prettierDetector(projectPath, packageJson) {
2474
2456
  name: 'Prettier',
2475
2457
  version,
2476
2458
  configPath,
2477
- confidence: min(confidence, 100),
2459
+ confidence: index_cjs_js$8.min(confidence, 100),
2478
2460
  detectedFrom: sources,
2479
2461
  };
2480
2462
  }
@@ -2493,6 +2475,14 @@ const STYLELINT_CONFIG_PATTERNS = [
2493
2475
  * @param projectPath - Project directory path
2494
2476
  * @param packageJson - Optional pre-loaded package.json
2495
2477
  * @returns Detection result or null if not detected
2478
+ *
2479
+ * @example Detecting Stylelint linter
2480
+ * ```typescript
2481
+ * const result = stylelintDetector('/path/to/project', {
2482
+ * devDependencies: { stylelint: '^15.0.0', 'stylelint-config-standard': '^30.0.0' },
2483
+ * })
2484
+ * // => { id: 'stylelint', name: 'Stylelint', confidence: 65, version: '15.0.0', ... }
2485
+ * ```
2496
2486
  */
2497
2487
  function stylelintDetector(projectPath, packageJson) {
2498
2488
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2514,7 +2504,7 @@ function stylelintDetector(projectPath, packageJson) {
2514
2504
  break;
2515
2505
  }
2516
2506
  }
2517
- const stylelintPlugins = keys(deps).filter((d) => d.startsWith('stylelint-'));
2507
+ const stylelintPlugins = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('stylelint-'));
2518
2508
  if (stylelintPlugins.length > 0) {
2519
2509
  confidence += 5;
2520
2510
  sources.push({ type: 'package.json', field: 'dependencies (stylelint plugins)' });
@@ -2527,49 +2517,7 @@ function stylelintDetector(projectPath, packageJson) {
2527
2517
  name: 'Stylelint',
2528
2518
  version,
2529
2519
  configPath,
2530
- confidence: min(confidence, 100),
2531
- detectedFrom: sources,
2532
- };
2533
- }
2534
-
2535
- /**
2536
- * Detect Biome in project.
2537
- *
2538
- * @param projectPath - Project directory path
2539
- * @param packageJson - Optional pre-loaded package.json
2540
- * @returns Detection result or null if not detected
2541
- */
2542
- function biomeDetector(projectPath, packageJson) {
2543
- const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2544
- const sources = [];
2545
- let confidence = 0;
2546
- let configPath;
2547
- let version;
2548
- const deps = collectAllDependencies(pkg);
2549
- if (deps['@biomejs/biome']) {
2550
- confidence += 70;
2551
- version = parseVersionString(deps['@biomejs/biome']);
2552
- sources.push({ type: 'package.json', field: 'dependencies.@biomejs/biome' });
2553
- }
2554
- if (exists(node_path.join(projectPath, 'biome.json'))) {
2555
- confidence += 30;
2556
- configPath = 'biome.json';
2557
- sources.push({ type: 'config-file', path: 'biome.json' });
2558
- }
2559
- if (!configPath && exists(node_path.join(projectPath, 'biome.jsonc'))) {
2560
- confidence += 30;
2561
- configPath = 'biome.jsonc';
2562
- sources.push({ type: 'config-file', path: 'biome.jsonc' });
2563
- }
2564
- if (confidence === 0) {
2565
- return null;
2566
- }
2567
- return {
2568
- id: 'biome',
2569
- name: 'Biome',
2570
- version,
2571
- configPath,
2572
- confidence: min(confidence, 100),
2520
+ confidence: index_cjs_js$8.min(confidence, 100),
2573
2521
  detectedFrom: sources,
2574
2522
  };
2575
2523
  }
@@ -2587,6 +2535,14 @@ const lintingDetectors = [
2587
2535
  * @param projectPath - Project directory path
2588
2536
  * @param packageJson - Optional pre-loaded package.json
2589
2537
  * @returns Array of detected linting tools, sorted by confidence
2538
+ *
2539
+ * @example Detecting multiple linting tools
2540
+ * ```typescript
2541
+ * const results = detectLintingTools('/path/to/project', {
2542
+ * devDependencies: { eslint: '^8.0.0', prettier: '^3.0.0' },
2543
+ * })
2544
+ * // => [{ id: 'eslint', confidence: 50 }, { id: 'prettier', confidence: 50 }]
2545
+ * ```
2590
2546
  */
2591
2547
  function detectLintingTools(projectPath, packageJson) {
2592
2548
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -2601,140 +2557,179 @@ function detectLintingTools(projectPath, packageJson) {
2601
2557
  }
2602
2558
 
2603
2559
  /**
2604
- * Detect NX in project.
2560
+ * Detect Lerna in project.
2605
2561
  *
2606
2562
  * @param workspacePath - Workspace directory path
2607
2563
  * @param packageJson - Optional pre-loaded package.json
2608
2564
  * @returns Detection result or null if not detected
2565
+ *
2566
+ * @example Detecting Lerna monorepo
2567
+ * ```typescript
2568
+ * // Project with lerna.json config file
2569
+ * const result = lernaDetector('/path/to/lerna-project')
2570
+ * // => {
2571
+ * // id: 'lerna',
2572
+ * // name: 'Lerna',
2573
+ * // confidence: 80,
2574
+ * // configPath: 'lerna.json',
2575
+ * // detectedFrom: [{ type: 'config-file', path: 'lerna.json' }]
2576
+ * // }
2577
+ * ```
2609
2578
  */
2610
- function nxDetector(workspacePath, packageJson) {
2579
+ function lernaDetector(workspacePath, packageJson) {
2611
2580
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
2612
2581
  const sources = [];
2613
2582
  let confidence = 0;
2614
2583
  let version;
2615
- let workspaceLayout;
2616
- const nxJsonPath = node_path.join(workspacePath, 'nx.json');
2617
- if (exists(nxJsonPath)) {
2618
- confidence += 70;
2619
- sources.push({ type: 'config-file', path: 'nx.json' });
2584
+ let configPath;
2585
+ const lernaJsonPath = node_path.join(workspacePath, 'lerna.json');
2586
+ if (exists(lernaJsonPath)) {
2587
+ confidence += 80;
2588
+ configPath = 'lerna.json';
2589
+ sources.push({ type: 'config-file', path: 'lerna.json' });
2620
2590
  }
2621
2591
  const deps = collectAllDependencies(pkg);
2622
- if (deps['nx']) {
2623
- confidence += 20;
2624
- version = parseVersionString(deps['nx']);
2625
- sources.push({ type: 'package.json', field: 'dependencies.nx' });
2626
- }
2627
- const hasApps = exists(node_path.join(workspacePath, 'apps'));
2628
- const hasLibs = exists(node_path.join(workspacePath, 'libs'));
2629
- if (hasApps || hasLibs) {
2630
- confidence += 10;
2631
- sources.push({ type: 'directory', path: 'apps/ or libs/' });
2632
- workspaceLayout = {
2633
- appsDir: hasApps ? 'apps' : '',
2634
- libsDir: hasLibs ? 'libs' : '',
2635
- };
2592
+ if (deps['lerna']) {
2593
+ confidence += 15;
2594
+ version = parseVersionString(deps['lerna']);
2595
+ sources.push({ type: 'package.json', field: 'dependencies.lerna' });
2636
2596
  }
2637
- const nxPackages = keys(deps).filter((d) => d.startsWith('@nx/') || d.startsWith('@nrwl/'));
2638
- if (nxPackages.length > 0) {
2639
- confidence += 10;
2640
- sources.push({ type: 'package.json', field: '@nx/* packages' });
2597
+ if (exists(node_path.join(workspacePath, 'packages'))) {
2598
+ confidence += 5;
2599
+ sources.push({ type: 'directory', path: 'packages/' });
2641
2600
  }
2642
2601
  if (confidence === 0) {
2643
2602
  return null;
2644
2603
  }
2645
2604
  return {
2646
- id: 'nx',
2647
- name: 'NX',
2605
+ id: 'lerna',
2606
+ name: 'Lerna',
2648
2607
  version,
2649
- configPath: exists(nxJsonPath) ? 'nx.json' : undefined,
2650
- confidence: min(confidence, 100),
2608
+ configPath,
2609
+ confidence: index_cjs_js$8.min(confidence, 100),
2651
2610
  detectedFrom: sources,
2652
- workspaceLayout,
2653
2611
  };
2654
2612
  }
2655
2613
 
2656
2614
  /**
2657
- * Detect Turborepo in project.
2615
+ * Detect npm workspaces in project.
2658
2616
  *
2659
2617
  * @param workspacePath - Workspace directory path
2660
2618
  * @param packageJson - Optional pre-loaded package.json
2661
2619
  * @returns Detection result or null if not detected
2620
+ *
2621
+ * @example Detecting npm workspaces
2622
+ * ```typescript
2623
+ * // Project with workspaces in package.json and package-lock.json
2624
+ * const result = npmWorkspacesDetector('/path/to/npm-project')
2625
+ * // => {
2626
+ * // id: 'npm-workspaces',
2627
+ * // name: 'npm Workspaces',
2628
+ * // confidence: 90,
2629
+ * // configPath: 'package.json',
2630
+ * // detectedFrom: [
2631
+ * // { type: 'package.json', field: 'workspaces' },
2632
+ * // { type: 'lockfile', path: 'package-lock.json' }
2633
+ * // ]
2634
+ * // }
2635
+ * ```
2662
2636
  */
2663
- function turborepoDetector(workspacePath, packageJson) {
2637
+ function npmWorkspacesDetector(workspacePath, packageJson) {
2664
2638
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
2665
2639
  const sources = [];
2666
2640
  let confidence = 0;
2667
- let version;
2668
- let configPath;
2669
- const turboJsonPath = node_path.join(workspacePath, 'turbo.json');
2670
- if (exists(turboJsonPath)) {
2641
+ if (pkg?.workspaces) {
2671
2642
  confidence += 80;
2672
- configPath = 'turbo.json';
2673
- sources.push({ type: 'config-file', path: 'turbo.json' });
2643
+ sources.push({ type: 'package.json', field: 'workspaces' });
2674
2644
  }
2675
- const deps = collectAllDependencies(pkg);
2676
- if (deps['turbo']) {
2677
- confidence += 15;
2678
- version = parseVersionString(deps['turbo']);
2679
- sources.push({ type: 'package.json', field: 'dependencies.turbo' });
2645
+ if (exists(node_path.join(workspacePath, 'package-lock.json'))) {
2646
+ confidence += 10;
2647
+ sources.push({ type: 'lockfile', path: 'package-lock.json' });
2680
2648
  }
2681
- const scripts = pkg?.scripts ?? {};
2682
- if (values(scripts).some((s) => s?.includes('turbo'))) {
2683
- confidence += 5;
2684
- sources.push({ type: 'package.json', field: 'scripts (turbo commands)' });
2649
+ if (exists(node_path.join(workspacePath, 'yarn.lock'))) {
2650
+ return null;
2685
2651
  }
2686
2652
  if (confidence === 0) {
2687
2653
  return null;
2688
2654
  }
2689
2655
  return {
2690
- id: 'turborepo',
2691
- name: 'Turborepo',
2692
- version,
2693
- configPath,
2694
- confidence: min(confidence, 100),
2656
+ id: 'npm-workspaces',
2657
+ name: 'npm Workspaces',
2658
+ configPath: 'package.json',
2659
+ confidence: index_cjs_js$8.min(confidence, 100),
2695
2660
  detectedFrom: sources,
2696
2661
  };
2697
2662
  }
2698
2663
 
2699
2664
  /**
2700
- * Detect Lerna in project.
2665
+ * Detect NX in project.
2701
2666
  *
2702
2667
  * @param workspacePath - Workspace directory path
2703
2668
  * @param packageJson - Optional pre-loaded package.json
2704
2669
  * @returns Detection result or null if not detected
2670
+ *
2671
+ * @example Detecting NX workspace
2672
+ * ```typescript
2673
+ * // Project with nx.json and apps/libs directories
2674
+ * const result = nxDetector('/path/to/nx-workspace')
2675
+ * // => {
2676
+ * // id: 'nx',
2677
+ * // name: 'NX',
2678
+ * // confidence: 100,
2679
+ * // configPath: 'nx.json',
2680
+ * // version: '17.0.0',
2681
+ * // workspaceLayout: { appsDir: 'apps', libsDir: 'libs' },
2682
+ * // detectedFrom: [
2683
+ * // { type: 'config-file', path: 'nx.json' },
2684
+ * // { type: 'package.json', field: 'dependencies.nx' },
2685
+ * // { type: 'directory', path: 'apps/ or libs/' }
2686
+ * // ]
2687
+ * // }
2688
+ * ```
2705
2689
  */
2706
- function lernaDetector(workspacePath, packageJson) {
2690
+ function nxDetector(workspacePath, packageJson) {
2707
2691
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
2708
2692
  const sources = [];
2709
2693
  let confidence = 0;
2710
2694
  let version;
2711
- let configPath;
2712
- const lernaJsonPath = node_path.join(workspacePath, 'lerna.json');
2713
- if (exists(lernaJsonPath)) {
2714
- confidence += 80;
2715
- configPath = 'lerna.json';
2716
- sources.push({ type: 'config-file', path: 'lerna.json' });
2695
+ let workspaceLayout;
2696
+ const nxJsonPath = node_path.join(workspacePath, 'nx.json');
2697
+ if (exists(nxJsonPath)) {
2698
+ confidence += 70;
2699
+ sources.push({ type: 'config-file', path: 'nx.json' });
2717
2700
  }
2718
2701
  const deps = collectAllDependencies(pkg);
2719
- if (deps['lerna']) {
2720
- confidence += 15;
2721
- version = parseVersionString(deps['lerna']);
2722
- sources.push({ type: 'package.json', field: 'dependencies.lerna' });
2702
+ if (deps['nx']) {
2703
+ confidence += 20;
2704
+ version = parseVersionString(deps['nx']);
2705
+ sources.push({ type: 'package.json', field: 'dependencies.nx' });
2723
2706
  }
2724
- if (exists(node_path.join(workspacePath, 'packages'))) {
2725
- confidence += 5;
2726
- sources.push({ type: 'directory', path: 'packages/' });
2707
+ const hasApps = exists(node_path.join(workspacePath, 'apps'));
2708
+ const hasLibs = exists(node_path.join(workspacePath, 'libs'));
2709
+ if (hasApps || hasLibs) {
2710
+ confidence += 10;
2711
+ sources.push({ type: 'directory', path: 'apps/ or libs/' });
2712
+ workspaceLayout = {
2713
+ appsDir: hasApps ? 'apps' : '',
2714
+ libsDir: hasLibs ? 'libs' : '',
2715
+ };
2716
+ }
2717
+ const nxPackages = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('@nx/') || d.startsWith('@nrwl/'));
2718
+ if (nxPackages.length > 0) {
2719
+ confidence += 10;
2720
+ sources.push({ type: 'package.json', field: '@nx/* packages' });
2727
2721
  }
2728
2722
  if (confidence === 0) {
2729
2723
  return null;
2730
2724
  }
2731
2725
  return {
2732
- id: 'lerna',
2733
- name: 'Lerna',
2726
+ id: 'nx',
2727
+ name: 'NX',
2734
2728
  version,
2735
- configPath,
2736
- confidence: min(confidence, 100),
2729
+ configPath: exists(nxJsonPath) ? 'nx.json' : undefined,
2730
+ confidence: index_cjs_js$8.min(confidence, 100),
2737
2731
  detectedFrom: sources,
2732
+ workspaceLayout,
2738
2733
  };
2739
2734
  }
2740
2735
 
@@ -2744,6 +2739,19 @@ function lernaDetector(workspacePath, packageJson) {
2744
2739
  * @param workspacePath - Workspace directory path
2745
2740
  * @param packageJson - Optional pre-loaded package.json
2746
2741
  * @returns Detection result or null if not detected
2742
+ *
2743
+ * @example Detecting Rush monorepo
2744
+ * ```typescript
2745
+ * // Project with rush.json config file
2746
+ * const result = rushDetector('/path/to/rush-project')
2747
+ * // => {
2748
+ * // id: 'rush',
2749
+ * // name: 'Rush',
2750
+ * // confidence: 90,
2751
+ * // configPath: 'rush.json',
2752
+ * // detectedFrom: [{ type: 'config-file', path: 'rush.json' }]
2753
+ * // }
2754
+ * ```
2747
2755
  */
2748
2756
  function rushDetector(workspacePath, packageJson) {
2749
2757
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
@@ -2775,73 +2783,67 @@ function rushDetector(workspacePath, packageJson) {
2775
2783
  name: 'Rush',
2776
2784
  version,
2777
2785
  configPath,
2778
- confidence: min(confidence, 100),
2779
- detectedFrom: sources,
2780
- };
2781
- }
2782
-
2783
- /**
2784
- * Detect pnpm workspaces in project.
2785
- *
2786
- * @param workspacePath - Workspace directory path
2787
- * @returns Detection result or null if not detected
2788
- */
2789
- function pnpmWorkspacesDetector(workspacePath) {
2790
- const sources = [];
2791
- let confidence = 0;
2792
- let configPath;
2793
- const pnpmWorkspacePath = node_path.join(workspacePath, 'pnpm-workspace.yaml');
2794
- if (exists(pnpmWorkspacePath)) {
2795
- confidence += 90;
2796
- configPath = 'pnpm-workspace.yaml';
2797
- sources.push({ type: 'config-file', path: 'pnpm-workspace.yaml' });
2798
- }
2799
- if (exists(node_path.join(workspacePath, 'pnpm-lock.yaml'))) {
2800
- confidence += 10;
2801
- sources.push({ type: 'lockfile', path: 'pnpm-lock.yaml' });
2802
- }
2803
- if (confidence === 0) {
2804
- return null;
2805
- }
2806
- return {
2807
- id: 'pnpm-workspaces',
2808
- name: 'pnpm Workspaces',
2809
- configPath,
2810
- confidence: min(confidence, 100),
2786
+ confidence: index_cjs_js$8.min(confidence, 100),
2811
2787
  detectedFrom: sources,
2812
2788
  };
2813
2789
  }
2814
2790
 
2815
2791
  /**
2816
- * Detect npm workspaces in project.
2792
+ * Detect Turborepo in project.
2817
2793
  *
2818
2794
  * @param workspacePath - Workspace directory path
2819
2795
  * @param packageJson - Optional pre-loaded package.json
2820
2796
  * @returns Detection result or null if not detected
2797
+ *
2798
+ * @example Detecting Turborepo monorepo
2799
+ * ```typescript
2800
+ * // Project with turbo.json and turbo dependency
2801
+ * const result = turborepoDetector('/path/to/turbo-project')
2802
+ * // => {
2803
+ * // id: 'turborepo',
2804
+ * // name: 'Turborepo',
2805
+ * // confidence: 95,
2806
+ * // configPath: 'turbo.json',
2807
+ * // version: '2.0.0',
2808
+ * // detectedFrom: [
2809
+ * // { type: 'config-file', path: 'turbo.json' },
2810
+ * // { type: 'package.json', field: 'dependencies.turbo' }
2811
+ * // ]
2812
+ * // }
2813
+ * ```
2821
2814
  */
2822
- function npmWorkspacesDetector(workspacePath, packageJson) {
2815
+ function turborepoDetector(workspacePath, packageJson) {
2823
2816
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
2824
2817
  const sources = [];
2825
2818
  let confidence = 0;
2826
- if (pkg?.workspaces) {
2819
+ let version;
2820
+ let configPath;
2821
+ const turboJsonPath = node_path.join(workspacePath, 'turbo.json');
2822
+ if (exists(turboJsonPath)) {
2827
2823
  confidence += 80;
2828
- sources.push({ type: 'package.json', field: 'workspaces' });
2824
+ configPath = 'turbo.json';
2825
+ sources.push({ type: 'config-file', path: 'turbo.json' });
2829
2826
  }
2830
- if (exists(node_path.join(workspacePath, 'package-lock.json'))) {
2831
- confidence += 10;
2832
- sources.push({ type: 'lockfile', path: 'package-lock.json' });
2827
+ const deps = collectAllDependencies(pkg);
2828
+ if (deps['turbo']) {
2829
+ confidence += 15;
2830
+ version = parseVersionString(deps['turbo']);
2831
+ sources.push({ type: 'package.json', field: 'dependencies.turbo' });
2833
2832
  }
2834
- if (exists(node_path.join(workspacePath, 'yarn.lock'))) {
2835
- return null;
2833
+ const scripts = pkg?.scripts ?? {};
2834
+ if (index_cjs_js$2.values(scripts).some((s) => s?.includes('turbo'))) {
2835
+ confidence += 5;
2836
+ sources.push({ type: 'package.json', field: 'scripts (turbo commands)' });
2836
2837
  }
2837
2838
  if (confidence === 0) {
2838
2839
  return null;
2839
2840
  }
2840
2841
  return {
2841
- id: 'npm-workspaces',
2842
- name: 'npm Workspaces',
2843
- configPath: 'package.json',
2844
- confidence: min(confidence, 100),
2842
+ id: 'turborepo',
2843
+ name: 'Turborepo',
2844
+ version,
2845
+ configPath,
2846
+ confidence: index_cjs_js$8.min(confidence, 100),
2845
2847
  detectedFrom: sources,
2846
2848
  };
2847
2849
  }
@@ -2852,6 +2854,23 @@ function npmWorkspacesDetector(workspacePath, packageJson) {
2852
2854
  * @param workspacePath - Workspace directory path
2853
2855
  * @param packageJson - Optional pre-loaded package.json
2854
2856
  * @returns Detection result or null if not detected
2857
+ *
2858
+ * @example Detecting yarn workspaces
2859
+ * ```typescript
2860
+ * // Project with workspaces in package.json and yarn.lock
2861
+ * const result = yarnWorkspacesDetector('/path/to/yarn-project')
2862
+ * // => {
2863
+ * // id: 'yarn-workspaces',
2864
+ * // name: 'Yarn Workspaces',
2865
+ * // confidence: 100,
2866
+ * // configPath: 'package.json',
2867
+ * // detectedFrom: [
2868
+ * // { type: 'package.json', field: 'workspaces' },
2869
+ * // { type: 'lockfile', path: 'yarn.lock' },
2870
+ * // { type: 'config-file', path: '.yarnrc.yml' }
2871
+ * // ]
2872
+ * // }
2873
+ * ```
2855
2874
  */
2856
2875
  function yarnWorkspacesDetector(workspacePath, packageJson) {
2857
2876
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
@@ -2876,7 +2895,7 @@ function yarnWorkspacesDetector(workspacePath, packageJson) {
2876
2895
  id: 'yarn-workspaces',
2877
2896
  name: 'Yarn Workspaces',
2878
2897
  configPath: 'package.json',
2879
- confidence: min(confidence, 100),
2898
+ confidence: index_cjs_js$8.min(confidence, 100),
2880
2899
  detectedFrom: sources,
2881
2900
  };
2882
2901
  }
@@ -2897,6 +2916,15 @@ const monorepoDetectors = [
2897
2916
  * @param workspacePath - Workspace directory path
2898
2917
  * @param packageJson - Optional pre-loaded package.json
2899
2918
  * @returns Array of detected monorepo tools, sorted by confidence
2919
+ *
2920
+ * @example Detecting monorepo tools
2921
+ * ```typescript
2922
+ * const detections = detectMonorepoTools('/path/to/project')
2923
+ * // => [
2924
+ * // { id: 'nx', name: 'NX', confidence: 90, configPath: 'nx.json', detectedFrom: [...] },
2925
+ * // { id: 'npm-workspaces', name: 'npm Workspaces', confidence: 80, ... }
2926
+ * // ]
2927
+ * ```
2900
2928
  */
2901
2929
  function detectMonorepoTools(workspacePath, packageJson) {
2902
2930
  const pkg = packageJson ?? readPackageJsonIfExists(workspacePath);
@@ -2910,111 +2938,129 @@ function detectMonorepoTools(workspacePath, packageJson) {
2910
2938
  return results.sort((a, b) => b.confidence - a.confidence);
2911
2939
  }
2912
2940
 
2913
- /** Config patterns for Jest */
2914
- const JEST_CONFIG_PATTERNS = ['jest.config.js', 'jest.config.ts', 'jest.config.mjs', 'jest.config.cjs', 'jest.config.json'];
2941
+ /** Config patterns for Cypress */
2942
+ const CYPRESS_CONFIG_PATTERNS = ['cypress.config.js', 'cypress.config.ts', 'cypress.config.mjs', 'cypress.json'];
2915
2943
  /**
2916
- * Detect Jest in project.
2944
+ * Detect Cypress in project.
2917
2945
  *
2918
2946
  * @param projectPath - Project directory path
2919
2947
  * @param packageJson - Optional pre-loaded package.json
2920
2948
  * @returns Detection result or null if not detected
2949
+ *
2950
+ * @example Detecting Cypress testing framework
2951
+ * ```typescript
2952
+ * import { cypressDetector } from '@hyperfrontend/project-scope'
2953
+ *
2954
+ * const result = cypressDetector('./my-project')
2955
+ * if (result) {
2956
+ * console.log(`Cypress ${result.version} detected (${result.confidence}% confidence)`)
2957
+ * // => "Cypress 13.6.0 detected (95% confidence)"
2958
+ * }
2959
+ * ```
2921
2960
  */
2922
- function jestDetector(projectPath, packageJson) {
2961
+ function cypressDetector(projectPath, packageJson) {
2923
2962
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2924
2963
  const sources = [];
2925
2964
  let confidence = 0;
2926
2965
  let version;
2927
2966
  const deps = collectAllDependencies(pkg);
2928
- if (deps['jest']) {
2967
+ if (deps['cypress']) {
2929
2968
  confidence += 60;
2930
- version = parseVersionString(deps['jest']);
2931
- sources.push({ type: 'package.json', field: 'dependencies.jest' });
2969
+ version = parseVersionString(deps['cypress']);
2970
+ sources.push({ type: 'package.json', field: 'dependencies.cypress' });
2932
2971
  }
2933
- const configPath = locateConfigFile(projectPath, JEST_CONFIG_PATTERNS);
2972
+ const configPath = locateConfigFile(projectPath, CYPRESS_CONFIG_PATTERNS);
2934
2973
  if (configPath) {
2935
2974
  confidence += 30;
2936
2975
  sources.push({ type: 'config-file', path: configPath });
2937
2976
  }
2938
- if (pkg && 'jest' in pkg) {
2939
- confidence += 20;
2940
- sources.push({ type: 'package.json', field: 'jest' });
2941
- }
2942
- const testScript = pkg?.scripts?.['test'] ?? '';
2943
- if (testScript.includes('jest')) {
2977
+ if (exists(node_path.join(projectPath, 'cypress'))) {
2944
2978
  confidence += 10;
2945
- sources.push({ type: 'package.json', field: 'scripts.test' });
2946
- }
2947
- if (deps['@types/jest']) {
2948
- confidence += 5;
2949
- sources.push({ type: 'package.json', field: 'dependencies.@types/jest' });
2979
+ sources.push({ type: 'directory', path: 'cypress/' });
2950
2980
  }
2951
- if (deps['ts-jest']) {
2981
+ const e2eScript = pkg?.scripts?.['e2e'] ?? pkg?.scripts?.['test:e2e'] ?? '';
2982
+ if (e2eScript.includes('cypress')) {
2952
2983
  confidence += 5;
2953
- sources.push({ type: 'package.json', field: 'dependencies.ts-jest' });
2984
+ sources.push({ type: 'package.json', field: 'scripts.e2e or scripts.test:e2e' });
2954
2985
  }
2955
2986
  if (confidence === 0) {
2956
2987
  return null;
2957
2988
  }
2958
2989
  return {
2959
- id: 'jest',
2960
- name: 'Jest',
2961
- type: 'unit',
2990
+ id: 'cypress',
2991
+ name: 'Cypress',
2992
+ type: 'e2e',
2962
2993
  version,
2963
2994
  configPath,
2964
- confidence: min(confidence, 100),
2995
+ confidence: index_cjs_js$8.min(confidence, 100),
2965
2996
  detectedFrom: sources,
2966
2997
  };
2967
2998
  }
2968
2999
 
2969
- /** Config patterns for Vitest */
2970
- const VITEST_CONFIG_PATTERNS = ['vitest.config.js', 'vitest.config.ts', 'vitest.config.mjs'];
3000
+ /** Config patterns for Jest */
3001
+ const JEST_CONFIG_PATTERNS = ['jest.config.js', 'jest.config.ts', 'jest.config.mjs', 'jest.config.cjs', 'jest.config.json'];
2971
3002
  /**
2972
- * Detect Vitest in project.
3003
+ * Detect Jest in project.
2973
3004
  *
2974
3005
  * @param projectPath - Project directory path
2975
3006
  * @param packageJson - Optional pre-loaded package.json
2976
3007
  * @returns Detection result or null if not detected
3008
+ *
3009
+ * @example Detecting Jest testing framework
3010
+ * ```typescript
3011
+ * import { jestDetector } from '@hyperfrontend/project-scope'
3012
+ *
3013
+ * const result = jestDetector('./my-project')
3014
+ * if (result) {
3015
+ * console.log(`Jest ${result.version} detected`)
3016
+ * console.log('Sources:', result.detectedFrom.map(s => s.type))
3017
+ * // => "Sources: ['package.json', 'config-file']"
3018
+ * }
3019
+ * ```
2977
3020
  */
2978
- function vitestDetector(projectPath, packageJson) {
3021
+ function jestDetector(projectPath, packageJson) {
2979
3022
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
2980
3023
  const sources = [];
2981
3024
  let confidence = 0;
2982
3025
  let version;
2983
3026
  const deps = collectAllDependencies(pkg);
2984
- if (deps['vitest']) {
2985
- confidence += 70;
2986
- version = parseVersionString(deps['vitest']);
2987
- sources.push({ type: 'package.json', field: 'dependencies.vitest' });
3027
+ if (deps['jest']) {
3028
+ confidence += 60;
3029
+ version = parseVersionString(deps['jest']);
3030
+ sources.push({ type: 'package.json', field: 'dependencies.jest' });
2988
3031
  }
2989
- const configPath = locateConfigFile(projectPath, VITEST_CONFIG_PATTERNS);
3032
+ const configPath = locateConfigFile(projectPath, JEST_CONFIG_PATTERNS);
2990
3033
  if (configPath) {
2991
- confidence += 25;
3034
+ confidence += 30;
2992
3035
  sources.push({ type: 'config-file', path: configPath });
2993
3036
  }
2994
- if (!configPath) {
2995
- const viteConfig = exists(node_path.join(projectPath, 'vite.config.ts')) ||
2996
- exists(node_path.join(projectPath, 'vite.config.js')) ||
2997
- exists(node_path.join(projectPath, 'vite.config.mjs'));
2998
- if (viteConfig && deps['vitest']) {
2999
- confidence += 5;
3000
- sources.push({ type: 'config-file', path: 'vite.config.*' });
3001
- }
3037
+ if (pkg && 'jest' in pkg) {
3038
+ confidence += 20;
3039
+ sources.push({ type: 'package.json', field: 'jest' });
3002
3040
  }
3003
3041
  const testScript = pkg?.scripts?.['test'] ?? '';
3004
- if (testScript.includes('vitest')) {
3042
+ if (testScript.includes('jest')) {
3005
3043
  confidence += 10;
3006
3044
  sources.push({ type: 'package.json', field: 'scripts.test' });
3007
3045
  }
3046
+ if (deps['@types/jest']) {
3047
+ confidence += 5;
3048
+ sources.push({ type: 'package.json', field: 'dependencies.@types/jest' });
3049
+ }
3050
+ if (deps['ts-jest']) {
3051
+ confidence += 5;
3052
+ sources.push({ type: 'package.json', field: 'dependencies.ts-jest' });
3053
+ }
3008
3054
  if (confidence === 0) {
3009
3055
  return null;
3010
3056
  }
3011
3057
  return {
3012
- id: 'vitest',
3013
- name: 'Vitest',
3058
+ id: 'jest',
3059
+ name: 'Jest',
3014
3060
  type: 'unit',
3015
3061
  version,
3016
3062
  configPath,
3017
- confidence: min(confidence, 100),
3063
+ confidence: index_cjs_js$8.min(confidence, 100),
3018
3064
  detectedFrom: sources,
3019
3065
  };
3020
3066
  }
@@ -3027,6 +3073,17 @@ const MOCHA_CONFIG_PATTERNS = ['.mocharc.js', '.mocharc.json', '.mocharc.yaml',
3027
3073
  * @param projectPath - Project directory path
3028
3074
  * @param packageJson - Optional pre-loaded package.json
3029
3075
  * @returns Detection result or null if not detected
3076
+ *
3077
+ * @example Detecting Mocha testing framework
3078
+ * ```typescript
3079
+ * import { mochaDetector } from '@hyperfrontend/project-scope'
3080
+ *
3081
+ * const result = mochaDetector('./my-project')
3082
+ * if (result) {
3083
+ * console.log(`Mocha ${result.version} detected (${result.confidence}%)`)
3084
+ * // => "Mocha 10.2.0 detected (95%)"
3085
+ * }
3086
+ * ```
3030
3087
  */
3031
3088
  function mochaDetector(projectPath, packageJson) {
3032
3089
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3066,42 +3123,58 @@ function mochaDetector(projectPath, packageJson) {
3066
3123
  type: 'unit',
3067
3124
  version,
3068
3125
  configPath,
3069
- confidence: min(confidence, 100),
3126
+ confidence: index_cjs_js$8.min(confidence, 100),
3070
3127
  detectedFrom: sources,
3071
3128
  };
3072
3129
  }
3073
3130
 
3074
- /** Config patterns for Cypress */
3075
- const CYPRESS_CONFIG_PATTERNS = ['cypress.config.js', 'cypress.config.ts', 'cypress.config.mjs', 'cypress.json'];
3131
+ /** Config patterns for Playwright */
3132
+ const PLAYWRIGHT_CONFIG_PATTERNS = ['playwright.config.js', 'playwright.config.ts', 'playwright.config.mjs'];
3076
3133
  /**
3077
- * Detect Cypress in project.
3134
+ * Detect Playwright in project.
3078
3135
  *
3079
3136
  * @param projectPath - Project directory path
3080
3137
  * @param packageJson - Optional pre-loaded package.json
3081
3138
  * @returns Detection result or null if not detected
3139
+ *
3140
+ * @example Detecting Playwright testing framework
3141
+ * ```typescript
3142
+ * import { playwrightDetector } from '@hyperfrontend/project-scope'
3143
+ *
3144
+ * const result = playwrightDetector('./my-project')
3145
+ * if (result) {
3146
+ * console.log(`Playwright ${result.version} (${result.type} tests)`)
3147
+ * // => "Playwright 1.42.0 (e2e tests)"
3148
+ * }
3149
+ * ```
3082
3150
  */
3083
- function cypressDetector(projectPath, packageJson) {
3151
+ function playwrightDetector(projectPath, packageJson) {
3084
3152
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
3085
3153
  const sources = [];
3086
3154
  let confidence = 0;
3087
3155
  let version;
3088
3156
  const deps = collectAllDependencies(pkg);
3089
- if (deps['cypress']) {
3090
- confidence += 60;
3091
- version = parseVersionString(deps['cypress']);
3092
- sources.push({ type: 'package.json', field: 'dependencies.cypress' });
3157
+ if (deps['@playwright/test']) {
3158
+ confidence += 70;
3159
+ version = parseVersionString(deps['@playwright/test']);
3160
+ sources.push({ type: 'package.json', field: 'dependencies.@playwright/test' });
3093
3161
  }
3094
- const configPath = locateConfigFile(projectPath, CYPRESS_CONFIG_PATTERNS);
3162
+ if (deps['playwright']) {
3163
+ confidence += 50;
3164
+ version = version ?? parseVersionString(deps['playwright']);
3165
+ sources.push({ type: 'package.json', field: 'dependencies.playwright' });
3166
+ }
3167
+ const configPath = locateConfigFile(projectPath, PLAYWRIGHT_CONFIG_PATTERNS);
3095
3168
  if (configPath) {
3096
- confidence += 30;
3169
+ confidence += 25;
3097
3170
  sources.push({ type: 'config-file', path: configPath });
3098
3171
  }
3099
- if (exists(node_path.join(projectPath, 'cypress'))) {
3100
- confidence += 10;
3101
- sources.push({ type: 'directory', path: 'cypress/' });
3172
+ if (exists(node_path.join(projectPath, 'e2e')) || exists(node_path.join(projectPath, 'tests'))) {
3173
+ confidence += 5;
3174
+ sources.push({ type: 'directory', path: 'e2e/ or tests/' });
3102
3175
  }
3103
3176
  const e2eScript = pkg?.scripts?.['e2e'] ?? pkg?.scripts?.['test:e2e'] ?? '';
3104
- if (e2eScript.includes('cypress')) {
3177
+ if (e2eScript.includes('playwright')) {
3105
3178
  confidence += 5;
3106
3179
  sources.push({ type: 'package.json', field: 'scripts.e2e or scripts.test:e2e' });
3107
3180
  }
@@ -3109,65 +3182,77 @@ function cypressDetector(projectPath, packageJson) {
3109
3182
  return null;
3110
3183
  }
3111
3184
  return {
3112
- id: 'cypress',
3113
- name: 'Cypress',
3185
+ id: 'playwright',
3186
+ name: 'Playwright',
3114
3187
  type: 'e2e',
3115
3188
  version,
3116
3189
  configPath,
3117
- confidence: min(confidence, 100),
3190
+ confidence: index_cjs_js$8.min(confidence, 100),
3118
3191
  detectedFrom: sources,
3119
3192
  };
3120
3193
  }
3121
3194
 
3122
- /** Config patterns for Playwright */
3123
- const PLAYWRIGHT_CONFIG_PATTERNS = ['playwright.config.js', 'playwright.config.ts', 'playwright.config.mjs'];
3195
+ /** Config patterns for Vitest */
3196
+ const VITEST_CONFIG_PATTERNS = ['vitest.config.js', 'vitest.config.ts', 'vitest.config.mjs'];
3124
3197
  /**
3125
- * Detect Playwright in project.
3198
+ * Detect Vitest in project.
3126
3199
  *
3127
3200
  * @param projectPath - Project directory path
3128
3201
  * @param packageJson - Optional pre-loaded package.json
3129
3202
  * @returns Detection result or null if not detected
3203
+ *
3204
+ * @example Detecting Vitest testing framework
3205
+ * ```typescript
3206
+ * import { vitestDetector } from '@hyperfrontend/project-scope'
3207
+ *
3208
+ * const result = vitestDetector('./my-project')
3209
+ * if (result) {
3210
+ * console.log(`Vitest ${result.version} detected`)
3211
+ * console.log('Config:', result.configPath)
3212
+ * // => "Config: vitest.config.ts"
3213
+ * }
3214
+ * ```
3130
3215
  */
3131
- function playwrightDetector(projectPath, packageJson) {
3216
+ function vitestDetector(projectPath, packageJson) {
3132
3217
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
3133
3218
  const sources = [];
3134
3219
  let confidence = 0;
3135
3220
  let version;
3136
3221
  const deps = collectAllDependencies(pkg);
3137
- if (deps['@playwright/test']) {
3222
+ if (deps['vitest']) {
3138
3223
  confidence += 70;
3139
- version = parseVersionString(deps['@playwright/test']);
3140
- sources.push({ type: 'package.json', field: 'dependencies.@playwright/test' });
3141
- }
3142
- if (deps['playwright']) {
3143
- confidence += 50;
3144
- version = version ?? parseVersionString(deps['playwright']);
3145
- sources.push({ type: 'package.json', field: 'dependencies.playwright' });
3224
+ version = parseVersionString(deps['vitest']);
3225
+ sources.push({ type: 'package.json', field: 'dependencies.vitest' });
3146
3226
  }
3147
- const configPath = locateConfigFile(projectPath, PLAYWRIGHT_CONFIG_PATTERNS);
3227
+ const configPath = locateConfigFile(projectPath, VITEST_CONFIG_PATTERNS);
3148
3228
  if (configPath) {
3149
3229
  confidence += 25;
3150
3230
  sources.push({ type: 'config-file', path: configPath });
3151
3231
  }
3152
- if (exists(node_path.join(projectPath, 'e2e')) || exists(node_path.join(projectPath, 'tests'))) {
3153
- confidence += 5;
3154
- sources.push({ type: 'directory', path: 'e2e/ or tests/' });
3232
+ if (!configPath) {
3233
+ const viteConfig = exists(node_path.join(projectPath, 'vite.config.ts')) ||
3234
+ exists(node_path.join(projectPath, 'vite.config.js')) ||
3235
+ exists(node_path.join(projectPath, 'vite.config.mjs'));
3236
+ if (viteConfig && deps['vitest']) {
3237
+ confidence += 5;
3238
+ sources.push({ type: 'config-file', path: 'vite.config.*' });
3239
+ }
3155
3240
  }
3156
- const e2eScript = pkg?.scripts?.['e2e'] ?? pkg?.scripts?.['test:e2e'] ?? '';
3157
- if (e2eScript.includes('playwright')) {
3158
- confidence += 5;
3159
- sources.push({ type: 'package.json', field: 'scripts.e2e or scripts.test:e2e' });
3241
+ const testScript = pkg?.scripts?.['test'] ?? '';
3242
+ if (testScript.includes('vitest')) {
3243
+ confidence += 10;
3244
+ sources.push({ type: 'package.json', field: 'scripts.test' });
3160
3245
  }
3161
3246
  if (confidence === 0) {
3162
3247
  return null;
3163
3248
  }
3164
3249
  return {
3165
- id: 'playwright',
3166
- name: 'Playwright',
3167
- type: 'e2e',
3250
+ id: 'vitest',
3251
+ name: 'Vitest',
3252
+ type: 'unit',
3168
3253
  version,
3169
3254
  configPath,
3170
- confidence: min(confidence, 100),
3255
+ confidence: index_cjs_js$8.min(confidence, 100),
3171
3256
  detectedFrom: sources,
3172
3257
  };
3173
3258
  }
@@ -3186,6 +3271,21 @@ const testingDetectors = [
3186
3271
  * @param projectPath - Project directory path
3187
3272
  * @param packageJson - Optional pre-loaded package.json
3188
3273
  * @returns Array of detected testing frameworks, sorted by confidence
3274
+ *
3275
+ * @example Detecting multiple testing frameworks
3276
+ * ```typescript
3277
+ * import { detectTestingFrameworks } from '@hyperfrontend/project-scope'
3278
+ *
3279
+ * const frameworks = detectTestingFrameworks('./my-project')
3280
+ * // => [
3281
+ * // { id: 'jest', name: 'Jest', type: 'unit', confidence: 95, ... },
3282
+ * // { id: 'cypress', name: 'Cypress', type: 'e2e', confidence: 85, ... }
3283
+ * // ]
3284
+ *
3285
+ * // Results are sorted by confidence (highest first)
3286
+ * const primary = frameworks[0]?.name ?? 'None'
3287
+ * console.log(`Primary testing framework: ${primary}`)
3288
+ * ```
3189
3289
  */
3190
3290
  function detectTestingFrameworks(projectPath, packageJson) {
3191
3291
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3212,7 +3312,7 @@ function checkTsConfigStrict(projectPath) {
3212
3312
  return undefined;
3213
3313
  try {
3214
3314
  const cleanContent = content.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, '');
3215
- const parsed = parse(cleanContent);
3315
+ const parsed = index_cjs_js$6.parse(cleanContent);
3216
3316
  return parsed?.compilerOptions?.strict === true;
3217
3317
  }
3218
3318
  catch {
@@ -3225,6 +3325,19 @@ function checkTsConfigStrict(projectPath) {
3225
3325
  * @param projectPath - Project directory path
3226
3326
  * @param packageJson - Optional pre-loaded package.json
3227
3327
  * @returns Detection result or null if not detected
3328
+ *
3329
+ * @example Detecting TypeScript
3330
+ * ```typescript
3331
+ * import { typescriptDetector } from '@hyperfrontend/project-scope'
3332
+ *
3333
+ * const result = typescriptDetector('./my-project')
3334
+ * if (result) {
3335
+ * console.log(`TypeScript ${result.version}`)
3336
+ * console.log(`Strict mode: ${result.strictMode ?? 'unknown'}`)
3337
+ * // => "TypeScript 5.3.0"
3338
+ * // => "Strict mode: true"
3339
+ * }
3340
+ * ```
3228
3341
  */
3229
3342
  function typescriptDetector(projectPath, packageJson) {
3230
3343
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3251,7 +3364,7 @@ function typescriptDetector(projectPath, packageJson) {
3251
3364
  break;
3252
3365
  }
3253
3366
  }
3254
- const typePackages = keys(deps).filter((d) => d.startsWith('@types/'));
3367
+ const typePackages = index_cjs_js$2.keys(deps).filter((d) => d.startsWith('@types/'));
3255
3368
  if (typePackages.length > 0) {
3256
3369
  confidence += 10;
3257
3370
  sources.push({ type: 'package.json', field: '@types/* packages' });
@@ -3266,7 +3379,7 @@ function typescriptDetector(projectPath, packageJson) {
3266
3379
  version,
3267
3380
  configPath,
3268
3381
  strictMode,
3269
- confidence: min(confidence, 100),
3382
+ confidence: index_cjs_js$8.min(confidence, 100),
3270
3383
  detectedFrom: sources,
3271
3384
  };
3272
3385
  }
@@ -3276,6 +3389,17 @@ function typescriptDetector(projectPath, packageJson) {
3276
3389
  * @param projectPath - Project directory path
3277
3390
  * @param packageJson - Optional pre-loaded package.json
3278
3391
  * @returns Detection result or null if not detected
3392
+ *
3393
+ * @example Detecting Flow type system
3394
+ * ```typescript
3395
+ * import { flowDetector } from '@hyperfrontend/project-scope'
3396
+ *
3397
+ * const result = flowDetector('./my-project')
3398
+ * if (result) {
3399
+ * console.log(`Flow ${result.version} with config: ${result.configPath}`)
3400
+ * // => "Flow 0.232.0 with config: .flowconfig"
3401
+ * }
3402
+ * ```
3279
3403
  */
3280
3404
  function flowDetector(projectPath, packageJson) {
3281
3405
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3310,7 +3434,7 @@ function flowDetector(projectPath, packageJson) {
3310
3434
  name: 'Flow',
3311
3435
  version,
3312
3436
  configPath,
3313
- confidence: min(confidence, 100),
3437
+ confidence: index_cjs_js$8.min(confidence, 100),
3314
3438
  detectedFrom: sources,
3315
3439
  };
3316
3440
  }
@@ -3333,6 +3457,18 @@ function hasJsDocTypes(content) {
3333
3457
  * @param projectPath - Project directory path
3334
3458
  * @param packageJson - Optional pre-loaded package.json
3335
3459
  * @returns Detection result or null if not detected
3460
+ *
3461
+ * @example Detecting JSDoc type annotations
3462
+ * ```typescript
3463
+ * import { jsdocDetector } from '@hyperfrontend/project-scope'
3464
+ *
3465
+ * const result = jsdocDetector('./my-project')
3466
+ * if (result) {
3467
+ * console.log('JSDoc types detected')
3468
+ * console.log('Sources:', result.detectedFrom.map(s => s.path ?? s.field))
3469
+ * // => "Sources: ['jsconfig.json', 'src/utils.js (JSDoc annotations)']"
3470
+ * }
3471
+ * ```
3336
3472
  */
3337
3473
  function jsdocDetector(projectPath, packageJson) {
3338
3474
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3349,7 +3485,7 @@ function jsdocDetector(projectPath, packageJson) {
3349
3485
  if (content) {
3350
3486
  try {
3351
3487
  const cleanContent = content.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, '');
3352
- const parsed = parse(cleanContent);
3488
+ const parsed = index_cjs_js$6.parse(cleanContent);
3353
3489
  if (parsed?.compilerOptions?.checkJs === true || parsed?.compilerOptions?.allowJs === true) {
3354
3490
  confidence += 30;
3355
3491
  sources.push({ type: 'config-file', path: 'tsconfig.json (checkJs/allowJs)' });
@@ -3388,7 +3524,7 @@ function jsdocDetector(projectPath, packageJson) {
3388
3524
  return {
3389
3525
  id: 'jsdoc',
3390
3526
  name: 'JSDoc',
3391
- confidence: min(confidence, 100),
3527
+ confidence: index_cjs_js$8.min(confidence, 100),
3392
3528
  detectedFrom: sources,
3393
3529
  };
3394
3530
  }
@@ -3404,6 +3540,20 @@ const typeSystemDetectors = [
3404
3540
  * @param projectPath - Project directory path
3405
3541
  * @param packageJson - Optional pre-loaded package.json
3406
3542
  * @returns Array of detected type systems, sorted by confidence
3543
+ *
3544
+ * @example Detecting all type systems
3545
+ * ```typescript
3546
+ * import { detectTypeSystems } from '@hyperfrontend/project-scope'
3547
+ *
3548
+ * const typeSystems = detectTypeSystems('./my-project')
3549
+ * // => [
3550
+ * // { id: 'typescript', name: 'TypeScript', version: '5.3.0', strictMode: true, confidence: 95, ... },
3551
+ * // { id: 'jsdoc', name: 'JSDoc', confidence: 40, ... }
3552
+ * // ]
3553
+ *
3554
+ * const primary = typeSystems[0]?.name ?? 'None'
3555
+ * console.log(`Primary type system: ${primary}`)
3556
+ * ```
3407
3557
  */
3408
3558
  function detectTypeSystems(projectPath, packageJson) {
3409
3559
  const pkg = packageJson ?? readPackageJsonIfExists(projectPath);
@@ -3457,7 +3607,7 @@ function isDetectAllOptions(value) {
3457
3607
  * @param packageJsonOrOptions - Optional pre-loaded package.json or options object
3458
3608
  * @returns All detection results organized by category
3459
3609
  *
3460
- * @example
3610
+ * @example Running all tech detectors
3461
3611
  * ```typescript
3462
3612
  * import { detectAll } from '@hyperfrontend/project-scope'
3463
3613
  *
@@ -3534,6 +3684,18 @@ function detectAll(projectPath, packageJsonOrOptions) {
3534
3684
  * Clear the tech detection cache.
3535
3685
  *
3536
3686
  * Useful for testing or when the project files have changed.
3687
+ *
3688
+ * @example Clearing the tech detection cache
3689
+ * ```typescript
3690
+ * import { detectAll, clearTechDetectionCache } from '@hyperfrontend/project-scope'
3691
+ *
3692
+ * // Initial detection (cached)
3693
+ * const first = detectAll('./my-project')
3694
+ *
3695
+ * // After modifying package.json, clear cache to re-detect
3696
+ * clearTechDetectionCache()
3697
+ * const fresh = detectAll('./my-project')
3698
+ * ```
3537
3699
  */
3538
3700
  function clearTechDetectionCache() {
3539
3701
  detectAllCache.clear();
@@ -3619,4 +3781,3 @@ exports.vitestDetector = vitestDetector;
3619
3781
  exports.vueDetector = vueDetector;
3620
3782
  exports.webpackDetector = webpackDetector;
3621
3783
  exports.yarnWorkspacesDetector = yarnWorkspacesDetector;
3622
- //# sourceMappingURL=index.cjs.js.map