@hyperfrontend/project-scope 0.2.1 → 0.2.2

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